• 沒有找到結果。

Generics 12/28/2015 Hsuan-Tien Lin (

N/A
N/A
Protected

Academic year: 2022

Share "Generics 12/28/2015 Hsuan-Tien Lin ("

Copied!
22
0
0

加載中.... (立即查看全文)

全文

(1)

Generics

12/28/2015

Hsuan-Tien Lin (林軒田) htlin@csie.ntu.edu.tw

Department of Computer Science

& Information Engineering

National Taiwan University

( 國立台灣大學資訊工程系)

(2)

How can we write a class for an In-

teger set of arbitrary size?

(3)

How can we write a class for a

String set of arbitrary size?

(4)

How can we write classes for Inte-

ger/String/Double/Professor sets of

arbitrary size?

(5)

How can we write one class for ar-

bitrary sets of arbitrary size?

(6)

Motivation of Generics (1/3)

1 c l a s s S t r i n g A r r a y {

2 p r i v a t e S t r i n g [ ] myarr ;

3 p u b l i c S t r i n g A r r a y (i n t l e n ) { myarr = new S t r i n g [ l e n ] ; }

4 p u b l i c S t r i n g g e t (i n t n ) { r e t u r n myarr [ n ] ; }

5 p u b l i c v o i d s e t (i n t n , S t r i n g s ) { myarr [ n ] = s ; }

6 p u b l i c v o i d s h o w A l l ( ) {

7 f o r(i n t i = 0 ; i <myarr . l e n g t h ; i ++)

8 System . o u t . p r i n t l n ( myarr [ i ] ) ;

9 }

10 }

11 c l a s s P r o f e s s o r A r r a y {

12 p r i v a t e P r o f e s s o r [ ] myarr ;

13 p u b l i c P r o f e s s o r A r r a y (i n t l e n ) { myarr = new P r o f e s s o r [ l e n ] ; }

14 p u b l i c P r o f e s s o r g e t (i n t n ) { r e t u r n myarr [ n ] ; }

15 p u b l i c v o i d s e t (i n t n , P r o f e s s o r p ) { myarr [ n ] = p ; }

16 p u b l i c v o i d s h o w A l l ( ) {

17 f o r(i n t i = 0 ; i <myarr . l e n g t h ; i ++)

18 System . o u t . p r i n t l n ( myarr [ i ] ) ;

19 }

20 }

Can we avoid writing the same boring things again and again?

(7)

Motivation of Generics (2/3)

1 c l a s s O b j e c t A r r a y {

2 p r i v a t e O b j e c t [ ] myarr ;

3 p u b l i c O b j e c t A r r a y (i n t l e n ) { myarr = new O b j e c t [ l e n ] ; }

4 p r o t e c t e d O b j e c t g e t (i n t n ) { r e t u r n myarr [ n ] ; }

5 p r o t e c t e d v o i d s e t (i n t n , O b j e c t o ) { myarr [ n ] = o ; }

6 p u b l i c v o i d s h o w A l l ( ) {

7 f o r(i n t i = 0 ; i <myarr . l e n g t h ; i ++)

8 System . o u t . p r i n t l n ( myarr [ i ] ) ;

9 }

10 }

11

12 c l a s s S t r i n g A r r a y extends O b j e c t A r r a y {

13 p u b l i c S t r i n g A r r a y (i n t l e n ) { super( l e n ) ; }

14 p u b l i c S t r i n g g e t (i n t n ) { r e t u r n ( S t r i n g )super. g e t ( n ) ; }

15 p u b l i c v o i d s e t (i n t n , S t r i n g s ) { super. s e t ( n , s ) ; }

16 }

Yes, by inheritance and polynormphism—everything is an Object

(8)

Motivation of Generics (3/3)

1 c l a s s ANYArray {

2 p r i v a t e ANY [ ] myarr ;

3 p u b l i c ANYArray (i n t l e n ) { myarr = new ANY [ l e n ] ; }

4 p r o t e c t e d ANY g e t (i n t n ) { r e t u r n myarr [ n ] ; }

5 p r o t e c t e d v o i d s e t (i n t n , ANY o ) { myarr [ n ] = o ; }

6 p u b l i c v o i d s h o w A l l ( ) {

7 f o r(i n t i = 0 ; i <myarr . l e n g t h ; i ++)

8 System . o u t . p r i n t l n ( myarr [ i ] ) ;

9 }

10 }

Yes, by identifying the common parts, and then replacing

sed ’s/ANY/String/’ ANYArray.java >

StringArray.java

(9)

C++ Solution (roughly)

1 t e m p l a t e <c l a s s ANY>

2 c l a s s A r r a y {

3 p r i v a t e ANY [ ] myarr ;

4 p u b l i c A r r a y (i n t l e n ) { myarr = new ANY [ l e n ] ; }

5 p r o t e c t e d ANY g e t (i n t n ) { r e t u r n myarr [ n ] ; }

6 p r o t e c t e d v o i d s e t (i n t n , ANY o ) { myarr [ n ] = o ; }

7 p u b l i c v o i d s h o w A l l ( ) {

8 f o r(i n t i = 0 ; i <myarr . l e n g t h ; i ++)

9 System . o u t . p r i n t l n ( myarr [ i ] ) ;

10 }

11 }

12

13 {

14 Array < S t r i n g > s a r r ( 5 ) ;

15 s a r r . s e t ( 3 , " l a l a l a " ) ;

16 }

basically, the step sed ’s/ANY/String/’ ANYArray.cpp >

StringArray.cppdone by compiler

code automatically

duplicates during complication as you use

Array<String>, Array<Integer>, Array<Double>, ...

(10)

Java Solution (roughly)

1 c l a s s Array <ANY> {

2 p r i v a t e ANY [ ] myarr ;

3 p u b l i c A r r a y (i n t l e n ) { myarr = (ANY [ ] ) (new O b j e c t [ l e n ] ) ; }

4 p r o t e c t e d ANY g e t (i n t n ) { r e t u r n myarr [ n ] ; }

5 p r o t e c t e d v o i d s e t (i n t n , ANY o ) { myarr [ n ] = o ; }

6 p u b l i c v o i d s h o w A l l ( ) {

7 f o r(i n t i = 0 ; i <myarr . l e n g t h ; i ++)

8 System . o u t . p r i n t l n ( myarr [ i ] ) ;

9 }

10 }

11

12 {

13 Array < S t r i n g > s a r r ( 5 ) ;

14 s a r r . s e t ( 3 , " l a l a l a " ) ;

15 }

the ANY → Object step is automatically done by compiler: a true

one-class solution

(11)

How does duplicating solution com-

pare with one-class solution?

(12)

How can we write one class for ar-

bitrary sets of arbitrary size while

keeping type information?

(13)

Should StringSet extend Object-

Set?

(14)

Java Solution: Generics (since 1.4)

no manual duplicating (as opposed to old languages): save coding efforts

no automatic duplicating (as opposed to C++): save code size and re-compiling efforts

check type information very strictly by compiler (as opposed to single-object polymorphism): ensure type safety in JVM

Note: type information

erased after

compilation

(15)

Type Erasure: Mystery 1

1 c l a s s Set <T> {

2 Set ( ) {

3 T [ ] a r r = new T [ 1 0 ] ;

4 a r r [ 0 ] = new T ( ) ;

5 }

6 }

cannot new with an “undetermined type” T (no T in runtime)

(16)

Type Erasure: Mystery 2

1 c l a s s Set <T> {

2 }

3 p u b l i c c l a s s Fun {

4 p u b l i c s t a t i c v o i d main ( S t r i n g [ ] argv ) {

5 Set < S t r i n g > [ ] a r r = new Set < S t r i n g > [ 2 0 ] ;

6 a r r [ 0 ] . addElement (new I n t e g e r ( 3 ) ) ;

7 }

8 }

cannot create generic array (after type erasure, no type guarantee)

(17)

Use of Generics: Java Collection Framework

interfaces: Collection (Set, List) and Map

abstract classes: AbstractCollection (AbstractSet, AbstractList) and AbstractMap

concrete classes: HashSet, ArrayList, HashMap

(18)

This is Where It Starts...

array “direct inheritance” introduces type unsafety

1 F r u i t [ ] f r A r r = new F r u i t [ 3 ] ;

2 Food [ ] f o A r r = f r A r r ; / / Compiler : Yes !

3 f o A r r [ 0 ] = new Meat ( ) ;/ / Compiler : Yes !

4 F r u i t f r = f r A r r [ 0 ] ; / / Compiler : Yes !

generic:

not using direct inheritance

1 A r r a y L i s t < F r u i t > f r A r r = new A r r a y L i s t < F r u i t > ( 3 ) ;

2 A r r a y L i s t <Food> f o A r r = f r A r r ; / / Compiler : No !

3 f o A r r . add ( 0 , new Meat ( ) ) ; / / Compiler : Yes !

4 F r u i t f r = f r A r r . g e t ( 0 ) ; / / Compiler : Yes !

(19)

What If We Want to “Convert From” An Existing List?

1 MyList < F r u i t > f r A r r = new MyList < F r u i t > ( ) ;

2 MyList <Food> f o A r r = new MyList <Food > ( f r A r r ) ; / / c o n v e r t

3

4 c l a s s MyList <T> {

5 p u b l i c MyList <T > ( ) { }

6 p u b l i c <S> MyList <T> ( MyList <S> i n p u t ) { / ∗ code ∗ / }

7 }

shouldn’t work because we can convert Fruit (S) List to Meat (T) List arbitrarily

enforce type compatibility: S extends T

1 p u b l i c <S extends T> MyList <T> ( MyList <S> i n p u t ) { }

2 / / or , i f S i s n o t needed

3 p u b l i c MyList <T> ( MyList <? extends T> i n p u t ) { }

now this converting is like “upper cast”

(20)

What If We Want to “Convert To” A New List?

1 MyList < F r u i t > f r A r r = new MyList < F r u i t > ( ) ;

2 MyList <Food> f o A r r = new MyList <Food > ( ) ;

3 f r A r r . dumpInto ( f o A r r ) ;

4

5 c l a s s MyList <T> {

6 p u b l i c MyList <T > ( ) { }

7 p u b l i c <S> dumpInto ( MyList <S> o u t p u t ) { / ∗ code ∗ / }

8 }

shouldn’t work because we can dump Fruit (S) List to Meat (T) List arbitrarily

enforce type compatibility: S super T

1 p u b l i c <S super T> dumpInto ( MyList <S> o u t p u t ) { }

2 / / or , i f S i s n o t needed

3 p u b l i c dumpInto ( MyList <? super T> o u t p u t ) { }

again, “upper cast”, but in another direction

(21)

More about Type Erasure

one main reason: JVM doesn’t need changing between 1.4 and 1.5

replace types by upper bounds

cast automatically inserted with safe check

allow using “legacy code”

unsafely

List

List<Object>

List<?>

List<Fruit>

Calling legacy code from generic code is inherently dangerous;

once you mix generic code with non-generic legacy code, all the safety guarantees that the generic type system usually provides are void.

cons: lose run-time ability of generic types (new T())

(22)

More on Polymorphism

ad-hoc polymorphism: one method name, many different uses (via signature): print(int) and print(Object)

subtype polynorphism (often seen in OOP): one entry point (parent method), many different future uses (via overriding the method): String.valueOf(Object) which calls

Object.toString()

parametric polymorphism (generics, often seen in Functional Programming): one class (type-erased), many different uses:

printList(List<T> lst)

參考文獻

相關文件

[r]

[r]

Lee [2006] uses a difficulty level based on a weighted sum of the techniques required to solve a puzzle, showing from a sample of 10,000 Sudoku puzzles that there is a

Applied Mathematics Beijing Donghong Li H China University of Geosciences Information Technology Beijing Zhaodou Chen H China University of Geosciences Information Technology

Machine Learning for Modern Artificial Intelligence.. Hsuan-Tien

The relationship between these extra type parameters, and the types to which they are associated, is established by parameteriz- ing the interfaces (Java generics, C#, and Eiffel)

n Logical channel number and media information (RTP payload type). n Far endpoint responds with Open Logical

„ Indicate the type and format of information included in the message body. „ Content-Length: the length of the message