Jump to content

Generics in Java

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Ed Poor (talk | contribs) at 20:15, 15 November 2006 (subheads were getting nested too deeply). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)

Generics were added to the Java programming language in 2004 as part of J2SE 5.0. Unlike C++ templates, generic Java code generates only one compiled version of a generic class. Generic Java classes can only use object types as type parameters — primitive types are not allowed. Thus a List<Integer> is legal, while a List<int> is not.

In Java, generics are checked at compile time for type correctness. The generic type information is then removed via a process called type erasure, generic type information is retained only for superclass. For example, List<Integer> will be converted into a non-generic (raw) List, which can contain arbitrary objects. However, due to the compile-time check, the resulting code is guaranteed to be type correct, as long the code generated no unchecked compiler warnings.

One side-effect of this process is that the generic type information is typically not known at runtime. Thus, at runtime, a List<Integer> and a List<String> refer to the same class, List. One way to mitigate this side effect is through the use of Java's Collections.checkedSet() method, which will decorate the declared Collection and check for improper use (i.e. insertion of an inappropriate type) of a typed Collection at runtime. This can be useful in situations when legacy code is interoperating with code that makes use of generics.

Like C++ and C#, Java allows nested generic types. Thus List<Map<Integer, String>> is a valid type.

Wildcards

Generic type parameters in Java are not limited to specific classes. Java allows the use of wildcards to specify bounds on what type of parameters a given generic object may have. For example, List<?> indicates a list which has an unknown object type. Methods which take such a list as an argument could take any type of list. Reading from the list will return objects of type Object, and writing non-null elements to the list is not allowed, since the parameter type is not known.

To specify the upper bound of a generic element, the extends keyword is used, which indicates that the generic type is a subclass (either extends the class, or implements the interface) of the bounding class. So List<? extends Number> means that the given list contains objects which extend the Number class; for example, the list could be List<Float> or List<Number>. Thus, reading an element from the list will return a Number, while writing non-null elements is once again not allowed, since it is not known what type of element the list holds.

To specify the lower bound of a generic element, the super keyword is used, which indicates that the generic type is a superclass of the bounding class. So List<? super Number> could be List<Number> or List<Object>. Reading from the list returns objects of type Object, while any element of type Number can be added to the list, since it is guaranteed to be a valid type to store in the list.

Limitations

A limitation of the Java implementation of generics makes it impossible to create an array of a generic type, since there is no way to determine what the component type of the array should be. Thus if a method had a type parameter T, the programmer cannot create a new array of that type, such as via new T[size];. (It is possible to work around this limitation using Java's reflection mechanisms: if an instance of class T is available, one can obtain from that object the Class object corresponding to T and use java.lang.reflect.Array.newInstance to create the array.) Another limitation of the Java implementation of generics is that it is impossible to create an array of a generic class with a type parameter type other than <?>. This is due to the way arrays are handled in the language, and is necessary to assure that all code that doesn't cause compile warnings without using explicit casts is guaranteed to be type safe.