我们都知道,Java的泛型在运行期会被擦除,但是真的是这样的吗?看下面的例子:
package com.zzj.generic;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
/**
* 泛型擦除
*
* @author lenovo
*
*/
public class GenericErasureTest {
private List<String> list = new ArrayList<String>();
public static void main(String[] args) throws Exception {
getGenericInfo();
}
/**
* 获取声明的泛型类型
*
* @throws NoSuchFieldException
*/
private static void getGenericInfo() throws NoSuchFieldException {
Field declaredField = GenericErasureTest.class.getDeclaredField("list");
Type genericFieldType = declaredField.getGenericType();
if (genericFieldType instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) genericFieldType;
Type[] fieldArgTypes = pType.getActualTypeArguments();
for (Type fieldArgType : fieldArgTypes) {
if (fieldArgType instanceof Class) {
Class<?> fieldArgClass = (Class<?>) fieldArgType;
System.out.println("fieldArgClass = "
+ fieldArgClass.getName());
}
}
}
}
}
测试:fieldArgClass = java.lang.String
结果是在运行期得到了泛型的类型!我们知道,变量的声明是在编译期确定的,变量的实例化是在运行期确定的。由于字段list的类型在编译期已经确定,编译器并没有把泛型类型信息擦除,而是擦除了实例化时候的泛型类型信息。
反编译后的字段定义如下:
private List<String> list = new ArrayList();
确如上面的推断,所以Java泛型的擦除是半擦除的。
我们不但可以在运行期获取字段的泛型信息,也可以获取方法的参数泛型信息和方法返回值的泛型信息,使用方法同上。