Java反射通过class获取父类泛型类型
在Java的反射技术中,通过Method和Field对象很容易就可以取出泛型类型的具体类型。但是普通类的泛型参数在编译期会被擦除,比如定义了一个List<String>对象,在运行期我们可以拿到的信息就只剩下List,并不知道List中的元素类型是什么。这也说明了,为什么fun(List<String> list)和 fun(List<Integer>)会被编译器认为是相同的函数。
但是,对于获取父类的泛型类型,还是会有办法的。在Class类中,有这样一个方法:
/**
* Returns the {@code Type} representing the direct superclass of
* the entity (class, interface, primitive type or void) represented by
* this {@code Class}.
*
* <p>If the superclass is a parameterized type, the {@code Type}
* object returned must accurately reflect the actual type
* parameters used in the source code. The parameterized type
* representing the superclass is created if it had not been
* created before. See the declaration of {@link
* java.lang.reflect.ParameterizedType ParameterizedType} for the
* semantics of the creation process for parameterized types. If
* this {@code Class} represents either the {@code Object}
* class, an interface, a primitive type, or void, then null is
* returned. If this object represents an array class then the
* {@code Class} object representing the {@code Object} class is
* returned.
*
* @throws java.lang.reflect.GenericSignatureFormatError if the generic
* class signature does not conform to the format specified in
* <cite>The Java™ Virtual Machine Specification</cite>
* @throws TypeNotPresentException if the generic superclass
* refers to a non-existent type declaration
* @throws java.lang.reflect.MalformedParameterizedTypeException if the
* generic superclass refers to a parameterized type that cannot be
* instantiated for any reason
* @return the superclass of the class represented by this object
* @since 1.5
*/
public Type getGenericSuperclass() {
if (getGenericSignature() != null) {
// Historical irregularity:
// Generic signature marks interfaces with superclass = Object
// but this API returns null for interfaces
if (isInterface())
return null;
return getGenericInfo().getSuperclass();
} else
return getSuperclass();
}
此方法返回的是具有泛型信息的父类,如果没有则返回Object对象。具体什么样的类都返回什么样的结果,来看测试代码
public void printGenericType(){
Class clazz1 = new ArrayList<Integer>().getClass();
Class clazz2 = new String[0].getClass();
Class clazz3 = String.class;
Class clazz4 = Object.class;
Class clazz5 = new IntList().getClass();
System.out.println(clazz1.getGenericSuperclass());
System.out.println(clazz2.getGenericSuperclass());
System.out.println(clazz3.getGenericSuperclass());
System.out.println(clazz4.getGenericSuperclass());
System.out.println(clazz5.getGenericSuperclass());
}
结果:
java.util.AbstractList<E>
class java.lang.Object
class java.lang.Object
null
java.util.ArrayList<java.lang.Integer>
上面的测试代码中分别打印出了ArrayList,数组,普通类,Object类和自定义的一个类通过getGenericSuperclass()方法获取到的结果。普通类以及数组的父类都是Object,所以打印出的结果是Object。Object没有父类,打印出的是null。普通的ArrayList打印出的结果是java.util.AbstractList<E>,第五个class打印出了带有泛型信息的java.util.ArrayList<java.lang.Integer>。IntList的定义是这样的
public class IntList extends ArrayList<Integer> {
}
ArrayList的定义是这样的
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
两处的不同在于继承父类的时候有没有知道父类泛型的具体类型,如果指定了,则可以通过上面的方法得到这个具体的类型。否则不能得到,这两者一定还存在 其他的区别联系,下面打印出获得的具体类型是什么
public void getGenericType(){
Class clazz1 = new ArrayList<Integer>().getClass();
Type type = clazz1.getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) type;
System.out.println(parameterizedType);
System.out.println(parameterizedType.getActualTypeArguments()[0].getClass());
Class clazz2 = new IntList().getClass();
Type type2 = clazz2.getGenericSuperclass();
ParameterizedType parameterizedType2 = (ParameterizedType) type2;
System.out.println(parameterizedType2);
System.out.println(parameterizedType2.getActualTypeArguments()[0].getClass());
}
结果
java.util.AbstractList<E>
class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
java.util.ArrayList<java.lang.Integer>
class java.lang.Class
原来如此,如果在继承父类的时候没有指定父类的泛型类型,则这时候获取到的类型是TypeVariableImpl;而指定了父类的泛型类型则这时候就能获取到对应的Class