Generic types added in JDK 5.0 provided enhancement to type safety in Java. For example in using Collections, generic types allow restricting the type the collection would contain as opposed to pre-JDK5 wherein collection classes accept anything that extends from java.lang.Object (which means almost everything!). And this improvement of allowing types to be specified for collections reduces, if not eliminate, the need for casts and also reduces unexpected ClassCastException at runtime.
Generics also became a key element in Generic DAOs (Data Access Objects) used for ORM driven applications such as those using Hibernate or Toplink.
As beautiful as it may seem, Generics also has its sharp corners which will surely give you several head scratching or even cursing if you are not aware of these Generics traps. The following are some important things to remember when using Generics.
Generics are not covariant.
Most developers might be tempted to think that collections are somehow the better incarnation of arrays and applying the concept of inheritance, some idioms with arrays may sometimes be applied to parameterized collections which turns out not to work the way you think it is.
For example, we all know that arrays are objects. And supposed you have an array of Integer, and since Integer extends Number this is perfectly legal:
Number[] numbers = new Integer[3];
and since all objects in Java extends from java.lang.Object this is also perfectly legal:
Object[] numbers = new Integer[3];
This idiom however if applied to parameterized collections won’t work. The following would not compile.
List numbers = new ArrayList();
Why? Because if the compiler would allow this idiom, it would break the promise of type-safety implicit in the definition of the ArrayList declaration, it is an ArrayList of Integer. That is why Generics cannot be covariant.
Problem with Erasure
The implementation of Generics in Java often described as a crappy implementation is somehow tricky. This implementation is known as type erasure, type-safety is enforced by the compiler at compile time but erases these type information before creating the bytecodes. Because of erasure List and List are considered the same class (at runtime the type parameters are already erased and both just exists as raw Lists).
Since compiler removes all type information before the byte codes are generated, suppose you have a class class MyClass { }, these codes will not compile:
public void someMethod(Object item) {
if (item instanceof E) { . . .} //Fails. Cannot determine type of E
E e = new E(); //no way to determine a constructor
E[] eArray = new E[3]; //fails
}
Constructing Wildcard References
Java allow us to use wildcards in collections when we don’t know what the collection will hold at runtime by doing for example: Set<?> setOfUnknown as opposed to raw types. Supposed you want to create a copy of a collection inside a method, and that collection happens to be using a wildcard, So you might think this is ok:
public List<?> copyList(List<?> list) {
return new ArrayList<?>(list);
}
This is illegal! However, this is fine:
public List<?> copyList(List<?> list) {
return new ArrayList
One thought on “Generics: Beauty and Madness”
You may want to have a look at Google Guava for some nifty uses of Java Generics.
One thought on “Generics: Beauty and Madness”
You may want to have a look at Google Guava for some nifty uses of Java Generics.