I understand that in Java contrary to, for example, C# generics are compile-time feature and is removed via type erasure. So, how does Gson's TypeToken
really work? How does it get the generic type of an object?
问题:
回答1:
From §4.6 of the JLS (emphasis mine):
Type erasure is a mapping from types (possibly including parameterized types and type variables) to types (that are never parameterized types or type variables). We write |T| for the erasure of type T. The erasure mapping is defined as follows:
The erasure of a parameterized type (§4.5) G is |G|.
The erasure of a nested type T.C is |T|.C.
The erasure of an array type T[] is |T|[].
The erasure of a type variable (§4.4) is the erasure of its leftmost bound.
The erasure of every other type is the type itself.
Therefore, if you declare a class with an anonymous subclass of itself, it keeps it's parameterized type; it's not erased. Therefore, consider the following code:
import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
import java.util.HashMap;
public class Erasure<T>
{
public static void main(String...strings) {
Class<?> foo = new Erasure<HashMap<Integer, String>>() {}.getClass();
ParameterizedType t = (ParameterizedType) foo.getGenericSuperclass();
System.out.println(t.getOwnerType());
System.out.println(t.getRawType());
System.out.println(Arrays.toString(t.getActualTypeArguments()));
}
}
This outputs:
null
class Erasure
[java.util.HashMap<java.lang.Integer, java.lang.String>]
Notice that you would get a ClassCastException
if you did not declare the class anonymously, because of erasure; the superclass would not be a parameterized type, it would be an Object
.
回答2:
Java's type erasure applies to individual objects, not classes or fields or methods. TypeToken uses an anonymous class to ensure it keeps generic type information, instead of just creating an object.