It’s basically the way that generics are implemented in Java via compiler trickery. The compiled generic code actually just uses java.lang.Object
wherever you talk about T
(or some other type parameter) – and there’s some metadata to tell the compiler that it really is a generic type.
When you compile some code against a generic type or method, the compiler works out what you really mean (i.e. what the type argument for T
is) and verifies at compile time that you’re doing the right thing, but the emitted code again just talks in terms of java.lang.Object
– the compiler generates extra casts where necessary. At execution time, a List<String>
and a List<Date>
are exactly the same; the extra type information has been erased by the compiler.
Compare this with, say, C#, where the information is retained at execution time, allowing code to contain expressions such as typeof(T)
which is the equivalent to T.class
– except that the latter is invalid. (There are further differences between .NET generics and Java generics, mind you.) Type erasure is the source of many of the “odd” warning/error messages when dealing with Java generics.
Other resources:
- Oracle documentation
- Wikipedia
- Gilad Bracha’s Java generics guide (PDF – highly recommended; link may need to change periodically)
- Angelika Langer’s Java Generics FAQ