在 Java 反射中,对于一般的类,我们可以通过对象.getClass
来获得类对象
,然后通过类对象.getFields()
可以获得类下的字段对象数组
,以及字段对象.getType()
来获得字段的具体类型,如下面源码中carClass.getFields()[0].getType():int
;
但如果是泛型类(参见源码中的Foo<T>
类),因为其具体类型是外部传入的,引起 Java反射是无法获取到传入泛型的具体类型的,如字段对象.getType
输出 Object(参见源码中输出fooClass.getFields()[0].getType():class java.lang.Object
)
Gson的TypeToken解决了 Java 泛型反射问题,通过定义一个匿名内部类new TypeToken<Foo<Integer>>(){}
,然后可以获取具体的泛型类型。
源码如下:
package test.onjava;
import com.google.gson.reflect.TypeToken;
class TestGeneric {
class Car {
public int wheel;
protected int color; // carClass.getFields().length 不包含这个
}
class Foo<T> {
public T value;
public String key;
}
void testGeneric(){
// 一般类
System.out.println("-----------------------Normal class--------");
Car car = new Car();
Class carClass = car.getClass();
System.out.println(" car.getClass():" + carClass);
System.out.println(" carClass.getFields().length:" + carClass.getFields().length);
System.out.println(" carClass.getFields()[0].getType():" + carClass.getFields()[0].getType());
// 泛型类
System.out.println("-----------------------Generic class--------");
Foo foo = new Foo<Integer>();
Class fooClass = foo.getClass();
System.out.println(" foo.getClass():" + fooClass);
System.out.println(" fooClass.getFields().length:" + fooClass.getFields().length);
System.out.println(" fooClass.getFields()[0].getType():" + fooClass.getFields()[0].getType());
// Gson
System.out.println("----------------------Gson TypeToken---------");
TypeToken typeToken= new TypeToken<Foo<Integer>>(){};
System.out.println(" typeToken.getRawType:" + typeToken.getRawType());
System.out.println(" typeToken.getType:" + typeToken.getType());
}
}
输出
-----------------------Normal class--------
car.getClass():class test.onjava.TestGeneric$Car
carClass.getFields().length:1
carClass.getFields()[0].getType():int
-----------------------Generic class--------
foo.getClass():class test.onjava.TestGeneric$Foo
fooClass.getFields().length:2
fooClass.getFields()[0].getType():class java.lang.Object
----------------------Gson TypeToken---------
typeToken.getRawType:class test.onjava.TestGeneric$Foo
typeToken.getType:test.onjava.TestGeneric$Foo<java.lang.Integer>