Helping ordinary people create extraordinary websites!
HOME TUTORIALS SCRIPTS WEB HOSTING BLOG FORUM
Get Our Newsletter
Your Email:

Java Theory and Practice: Generics Gotchas

By Brian Goetz
2005-03-23


Implications of erasure

Because generics are implemented almost entirely in the Java compiler, and not in the runtime, nearly all type information about generic types has been "erased" by the time the bytecode is generated. In other words, the compiler generates pretty much the same code you would have written by hand without generics, casts and all, after checking the type-safety of your program. Unlike in C++, List<Integer> and List<String> are the same class (although they are different types, both subtypes of List<?> -- a distinction that is more important in JDK 5.0 than in previous versions of the language).

One of the implications of erasure is that a class cannot implement both Comparable<String> and Comparable<Number>, because both of these are in fact the same interface, specifying the same compareTo() method. It might seem sensible to want to declare a DecimalString class that is comparable to both Strings and Numbers, but to the Java compiler, you would be trying to declare the same method twice:

public class DecimalString implements Comparable<Number>, Comparable<String> { ... } // nope

Another consequence of erasure is that using casts or instanceof with generic type parameters doesn't make any sense. The following code will not improve the type safety of your code at all:

public <T> T naiveCast(T t, Object o) { return (T) o; }

The compiler will simply emit an unchecked conversion warning, because it doesn't know if the cast is safe or not. The naiveCast() method will not in fact do any casting at all -- T will simply be replaced with its erasure (Object), and the object passed in will be cast to Object -- not what was intended.

Erasure is also responsible for the construction issues described above -- that you cannot create an object of generic type because the compiler doesn't know what constructor to call. If your generic class needs to be constructing objects whose type is specified by generic type parameters, its constructors should take a class literal (Foo.class) and store it so that instances can be created with reflection.

Tutorial Pages:
» Identify and avoid some of the pitfalls in learning to use generics
» Generics are not covariant
» Construction delays
» Generifying existing classes
» Implications of erasure
» Summary
» Resources


First published by IBM developerWorks


 | Bookmark
Related Tutorials:
» All about JAXP, Part 1
» Make Database Queries Without the Database
» Load List Values for Improved Efficiency
» 2 Ways To Implement Session Tracking
» A Simple Way to Read an XML File in Java
» Develop Aspect-Oriented Java Applications with Eclipse and AJDT