« Home « Kết quả tìm kiếm

Language Features of Java Generics


Tóm tắt Xem thử

- Generics adds substantial expressive power to the Java programming language.
- Editor's Note: This is the second of two installments presenting an overview of Java Generics, a new language feature that will be supported in the upcoming release of Java 2 Platform, Standard Edition 1.5.
- installment—"Language Features of Java Generics,".
- Static and nonstatic methods as well as constructors can be parameterized in pretty much the same way as we described parameterizing types previously (see "Language Features of Java Generics,".
- Everything said about type variables of parameterized types applies to type variables of parameterized methods in the exact same way..
- See Listing 1 for an example of a parameterized static method: max()..
- The type parameters are inferred from the invocation context.
- In our example, the compiler would invoke max<Byte>.
- The type inference algorithm is.
- So far we have been instantiating parameterized types using a concrete type that replaces the type parameter in the instantiation.
- In addition, so-called wildcards can be used to instantiate a parameterized type.
- A wildcard instantiation looks like this:.
- ref = new LinkedList<Integer>();.
- wildcard, for instance, is the family of subtypes of type Number.
- is the family of supertypes of type Integer.
- is the set of all types.
- Correspondingly, the wildcard instantiation of a.
- refers to the set of instantiations of List for types that are subtypes of Number..
- Reference variables of a wildcard instantiation type can refer to an object of a compatible type, however..
- Compatible in this sense are concrete instantiations from the family of instantiations denoted by the wildcard instantiation.
- Similarly, we cannot create objects of a wildcard instantiation type, but a variable of the wildcard instantiation type can refer to an object of a compatible.
- Access to an object through a reference variable of a wildcard instantiation type is restricted.
- Through a wildcard instantiation with "extends".
- we must not invoke methods that take arguments of the type that the wildcard stands for:.
- new LinkedList<Integer>();.
- The add() method of type List takes an argument of the element type, which is the type parameter of the parameterized List type.
- Through a wildcard instantiation such as List<? extends Number>.
- methods where the return type is the type that the wildcard stands for are prohibited.
- In practice, wildcard instantiations will show up most frequently as argument or return types in method declarations, and only rarely in the declaration of variables.
- The most useful wildcard is the "extends".
- Examples for the use of this wildcard can be found in the J2SE 1.5 platform libraries.
- One example is the method Boolean addAll(Collection<? extends ElementType>.
- It allows the addition of elements to a List of element type.
- Though there are many more details not covered here, we want to forge ahead by exploring some of the underlying principles of JG, in particular the translation of paramterized types and methods into Java byte code..
- While this sounds pretty technical and mainly like a compiler builder's concern, an understanding of these principles aids understanding of many of the less obvious effects related to JG..
- How is JG implemented? What does the Java compiler do with our Java source code that contains definitions and usages of parameterized types and methods?.
- Here we intend to take a look under the hood of the compilation process to understand the effects and side effects of JG..
- A compiler that must translate a parameterized type or method (in any language) has in principle two choices:.
- Code specialization – The compiler generates a new representation for every instantiation of a parameterized type or method.
- For instance, the compiler would generate code for a list of integers and additional, different code for a list of strings..
- Code sharing – The compiler generates code for only one representation of a parameterized type or method and maps all the concrete instantiations of the generic type or method to the one unique representation, performing type checks and type conversions where needed..
- Code specialization is the approach that C++ takes for its templates.
- A list of integers and a list of strings would be represented in the executable code as two implementations of two different types..
- This bloat is particularly wasteful in cases where the elements in a collection are references (or pointers) because all references (or pointers) are of the same size and internally have the same representation.
- There is no need for generation of mostly identical code for a list of references to integers and a list of references to strings.
- Both lists could be represented internally by a list of references to any type of object.
- The compiler just has to add a couple of casts whenever these references are passed in and out of the generic type or method.
- Values of primitive type are of different size and require that different code is generated for a list of int and a list of double, for instance.
- No primitive types – Primitive types are prohibited as type arguments of parameterized types or methods, that is, the compiler rejects instantiations such as a List..
- Boxing – Primitive type values are boxed automatically so that, internally, references to the boxed primitive value were used.
- (Boxing is the process of wrapping a primitive value into its corresponding reference type, and unboxing is the reverse [see Resources.
- Naturally, boxing has a negative effect on performance because of the extra box and unbox operations..
- Type Erasure.
- Let's turn to the details of the code sharing implementation of JG.
- The key question is: how exactly does the Java compiler map different instantiations of a parameterized type or method onto a single representation of the type or method?.
- The translation technique used by the Java compiler can be imagined as a translation from generic Java source code back into regular Java code.
- The translation technique is called type erasure.
- the compiler removes all occurrences of the type variables and replaces them by their leftmost bound or type Object, if no bound had been specified.
- For instance, the instantiations LinkedList<Integer>.
- and a LinkedList<String>.
- In addition to removal of all type variables and replacing them by their leftmost bound, the compiler inserts a couple of casts in certain places and adds so-called bridge methods where needed..
- Type erasure meets this requirement: after type erasure there is no difference anymore between a parameterized and a regular type or method..
- For explanatory reasons we described the type erasure as a translation not from generic Java code into regular nongeneric Java code.
- the translation is from generic Java code directly to Java byte code..
- Nevertheless, we will subsequently refer to the type erasure process as a translation from generic Java to nongeneric Java..
- Listing 3 illustrates the translation by type erasure and shows the type erasure of our previous example of generic types (see Listing 2).
- occurrences of the type variable A are replaced by type Object.
- In the main() method, where a linked list of strings is used, the compiler added a cast from Object to String.
- See Listing 4 for a type erasure of our parameterized max() method from Listing 1..
- We see the inserted cast from Object to Byte in the main() method, where the generic method is invoked for a collection of Bytes, and we see an example of a bridge method in class Byte..
- The compiler inserts bridge methods in subclasses to ensure overriding works correctly.
- In the example, class Byte implements interface Comparable<Byte>.
- The compiler translates the compareTo() method of the generic interface Comparable<A>.
- After this translation, method Byte.compareTo(Byte) is no overriding version of method Comparable<Byte>.compareTo(Object) any longer because the two methods have different signatures as a side effect of translation by erasure.
- To enable overriding, the compiler adds a bridge method to the subclass.
- The bridge method has the same signature as the superclass's method that must be overridden and delegates to the other methods in the derived class that was the result of translation by erasure..
- The greatest difficulties in using and understanding JG stem perhaps from the type erasure translation process by which the compiler elides all occurrences of the type parameters, which leads to quite a number of surprising effects.
- For example, arrays of parameterized types are prohibited in Java, that is, Comparable<String>.
- It boils down to the fact that arrays are best avoided and replaced by collections as soon as the element type is a parameterized type.
- Despite the rough edges here and there, the addition of JG adds substantial expressive power to the Java programming language.
- She was involved in compiler construction in the '90s and has been watching closely the development of C.
- Her teaching is backed by over 12 years of work as a developer in the software industry and over 8 years of training and consulting

Xem thử không khả dụng, vui lòng xem tại trang nguồn
hoặc xem Tóm tắt