Possible Duplicate:
Why are not all type information erased in Java at runtime?
Java's generics are implemented via type erasure, so I thought it was no possible to get any information about the parameterized type at runtime. However, I found the following class in the Jackson library.
(I've simplified the class slightly for the sake of this example)
public abstract class TypeReference<T> {
final Type _type;
protected TypeReference() {
Type superClass = getClass().getGenericSuperclass();
_type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
public Type getType() { return _type; }
}
The class provides access to it's parameterized type as the following test demonstrates:
void testTypeReference() {
// notice that we're instantiating an anonymous subclass of TypeReference
TypeReference<CurrencyDto> tr = new TypeReference<CurrencyDto>() {};
assert tr.getType() == CurrencyDto.class
}
This class illustrates that actual type parameters can be retrieved at runtime (using reflection), how is this consistent with the notion that Java Generics are implemented via type erasure?
Concrete type argument information is stored in class files when it's known at compile time. For example, if you have a class with a method that returns List<String>
(not List<T>
!) that information will be available at runtime. Similarly, if you have a class:
public class Foo extends Bar<String> {
}
the type argument String
is hardcoded in to Foo
at compile time. The TypeReference
class (and all similar constructs, such as TypeLiteral
in Guice and TypeToken
in Gson) utilizes this fact by requiring you to make an anonymous subclass of it in your code. When you do this, an actual class file will be generated with that information present, just as with the Foo
example above.
For more information, see Neal Gafter's blog post here.
Type erasure more refers to the fact that you can't get information on the actual type arguments to an instance of a generic type at runtime (note that Foo
, a subclass of Bar<String>
, has no type variables and is not generic). For example, if you create an instance of the generic type ArrayList<E>
:
List<String> foo = new ArrayList<String>();
no type information is stored in that object. So when you pass it to some other method:
public <T> T foo(List<T> list)
there's no way to find out what T
is.
It is really quite simple: you can not get generic information from value INSTANCES, but you can get it from TYPES (classes), with some restrictions. Specifically, there are 3 places where generic type information is available (see http://www.cowtowncoder.com/blog/archives/2008/12/entry_126.html for details); on super-class/interface declaration (parameterization of super type), on field declarations, and and on method (argument, return type) declarations.
In case of TypeReference what happens is that you create an anonymous type with specified super type; and this information will then be available since that anonymous type (class) is passed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With