Generic erasure
As we all know, Java's generics are only valid at compile time, and the generic type will be erased at runtime, that is, List< ;String> and List
Why choose this implementation mechanism? Can't you just erase it? It was 10 years after the birth of Java that I wanted to implement a concept similar to C templates, namely generics. Java's class library is a very valuable asset in the Java ecosystem. It must ensure backward compatibility (that is, existing code and class files are still legal) and migration compatibility (generalized code and non-generalized code can call each other). Based on the above Due to these two backgrounds and considerations, Java designers adopted a compromise implementation method of "type erasure".
At the same time, there is such a "hole" mechanism that prevents us from obtaining the specific types of generic parameters at will during runtime.
TypeToken
Use
Students who have used Gson know that they need to define a TypeToken type during deserialization. Like this
private Type type = new TypeToken<List<Map<String, Foo>>>(){}.getType(); //调用fromJson方法时把type传过去,如果type的类型和json保持一致,则可以反序列化出来 gson.fromJson(json, type);
Three questions
1. Why use TypeToken to define the deserialized type? As mentioned above, if you directly pass the types of List
2.Why are there curly brackets {}? This brace is the essence. As we all know, in Java syntax, in this context, {} is used to define an anonymous class. This anonymous class inherits the TypeToken class, which is a subclass of TypeToken.
3. Why should we obtain the generic type through subclasses? This is the key to TypeToken being able to obtain the generic type. This is a clever method. The idea is like this, since the generics in List
The generics of the parent class that my subclass needs to inherit have been determined. Sure enough, the JVM saves this part of the information, and it is saved in the Class information of the subclass.
So how do we obtain this information? Fortunately, Java provides an API:
Type mySuperClass = foo.getClass().getGenericSuperclass(); Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0]; System.out.println(type);
In summary, for classes with generics, a ParameterizedType object is returned, for Object, interfaces and primitive types, null is returned, and for array classes, Object is returned. .class. ParameterizedType is a Java type that represents a type with generic parameters. After the introduction of generics in JDK1.5, all Classes in Java implement the Type interface. ParameterizedType inherits the Type interface. All Class classes containing generics will Implement this interface.
Debug it yourself and you will know what it returns.
Principle
The core method is the two sentences just mentioned, and the rest is very simple. Let’s look at the getType method of TypeToken
public final Type getType() { //直接返回type return type; }
Look at the initialization of type
//注意这里用了protected关键字,限制了只有子类才能访问 protected TypeToken() { this.type = getSuperclassTypeParameter(getClass()); this.rawType = (Class<? super T>) $Gson$Types.getRawType(type); this.hashCode = type.hashCode(); } //getSuperclassTypeParameter方法 //这几句就是上面的说到 static Type getSuperclassTypeParameter(Class<?> subclass) { Type superclass = subclass.getGenericSuperclass(); if (superclass instanceof Class) { throw new RuntimeException("Missing type parameter."); } ParameterizedType parameterized = (ParameterizedType) superclass; //这里注意一下,返回的是Gson自定义的,在$Gson$Types里面定义的TypeImpl等,这个类都是继承Type的。 return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]); }
The above is the detailed content of How to use TypeToken in Java. For more information, please follow other related articles on the PHP Chinese website!