Why I have to define a subclass to get the Type
of superclass' generic param? Is the limit necessary?
I read the code of Fastjson of Alibaba and tried to figure out why use TypeReference
must create an anonymous subclass. Then I found that an object cannot get its own generic param Type
even its own Type
.
public class TypeReference {
static ConcurrentMap<Type, Type> classTypeCache
= new ConcurrentHashMap<Type, Type>(16, 0.75f, 1);
protected final Type type;
protected TypeReference() {
Type superClass = getClass().getGenericSuperclass();
Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
Type cachedType = classTypeCache.get(type);
if (cachedType == null) {
classTypeCache.putIfAbsent(type, type);
cachedType = classTypeCache.get(type);
}
this.type = cachedType;
}
// ...
}
Sorry for my poor English. Thanks for your answers.
Because of Type Erasure.
Consider the following example
List<String> stringList = new ArrayList<>();
List<Number> numberList = new ArrayList<>();
System.out.println(stringList.getClass() == numberList.getClass());
This will print true
. Regardless of the generic type, both instances of ArrayList
have the same class and a single Class
object. So how could this single Class
object return the right Type
for both objects?
We can even get a step further,
List<String> stringList = Collections.emptyList();
List<Number> numberList = Collections.emptyList();
System.out.println(stringList == (Object)numberList);
Objects do not know their generic type. If a collection is immutable and always empty, it can be used to represent arbitrary empty lists. The same applies to stateless functions
Function<String, String> stringFunction = Function.identity();
Function<Number, Number> numberFunction = Function.identity();
System.out.println(stringFunction == (Object)numberFunction);
Prints true
(on most systems; this is not a guaranteed behavior).
Generic types are only retained in some specific cases, like the signatures of field and method declarations and generic super types.
That’s why you need to create a subclass to exploit the fact that it will store the declared generic supertype. While it sometimes would be useful to construct a Type
instance in a simpler way and a suitable factory method can be regarded a missing feature, getting the actual generic type of an arbitrary object (or its Class
) is not possible in general.