Java中的类反射与泛型信息

Java中的泛型设计

Java中的 泛型类型(geneic type),它只在程序源码中存在,在编译后的字节码中就已经替换为对应的 原始类型(raw type)。既然类文件的泛型信息都已经被擦除,那JVM中就不可能存在泛型这种类型。如JVM中并不存在ArrayLis<Integer>这种类型,不管是ArrayLis<Integer>或ArrayList<String>在JVM中都是同一种类型,即原始类型ArrayList。可通过以下测试
	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		ArrayList<String> list_str = new ArrayList<String>();
		ArrayList<Integer> list_int = new ArrayList<Integer>();
		
		if(list.getClass() == ArrayList.class
				&& list_str.getClass() == ArrayList.class
				&& list_int.getClass() == ArrayList.class) { //true
			
			System.out.println("它们都属于 ArrayList 类型");
		}
	}

类反射与Type接口

虽然JVM中并不存在泛型类型,但还是通过类反射获得部分泛型信息(为此JDK1.5之后class文件中增加了一些泛型信息描述)。为了支持泛型类型的声明,Java提供了一个接口 java.lang.reflect.Type,它的子类如下:
(1)Class类         描述原始类型(即普通类型)
(2)ParameterizedType接口         描述参数化类型,如List<String>、Map<String,Integer>等
(3)TypeVariable接口         描述类型变量类型
(4)WildcardType接口         描述通配符类型
(5)GeneicArrayType接口         描述泛型数组类型

在类反射中我们可以通过Type接口及其子类获得部分泛型信息,如以下所示
public class Data<T> {
	String str;
	List<String> list;
	T item;

	public static void main(String[] args) {
		Data<Double> data = new Data<Double>();

		Class<?> clazz = data.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			Type type = field.getGenericType();

			if (type instanceof Class) {
				//属性str属于原始类型
			}
			if (type instanceof ParameterizedType) { // 属性list
				ParameterizedType pt = (ParameterizedType) type;
				//返回参数类型对应的原始类型,这是为 java.util.List
				Type rawType = pt.getRawType();
				//返回泛型参数数组,这里为 [java.lang.String]
				Type[] typeArgs = pt.getActualTypeArguments();
			}
			if (type instanceof TypeVariable) { // 属性item
				TypeVariable<?> tv = (TypeVariable<?>) type;
				//返回该变量类型的名字,这里为T
				String name = tv.getName();
			}
		}
	}
}

获取Class对象中的泛型信息

上面我已经提过泛型类型在生成class文件的时候就已经被擦除,而Class对象作为class文件在JVM中的表现形式,究竟能获得什么样的泛型信息呢?比如在上面的例子中我通过Data<Double> data = new Data<Double>()实例化了Data<T>类,那通过对象data来获取它实例化时的泛型参数(即Double)吗?毫无疑问要通过类反射获得,即通过该对象对应的Class对象获得。
当时我就是顺着这个思路搞了很久才发现走不通。很明显,Class对象是和该Class对应的任意实例无关的,它存的是定义它的class文件中的信息。于是结论便是不可能通过类反射获取到data对象的实例化参数。

不过,我们还是可以看看Class类的API文档总返回Type类型的接口有哪些:
(1)Type[]  getGenericInterfaces()  返回该类继承的接口对应的类型
(2)Type  getGenericSuperclass()  返回该类的父类对应的类型 
通过以上两个接口我们可以知道通过Class可以获取该父类或接口的泛型类型,如以下代码所示:
public class Data<T> {
	String str;
	List<String> list;
	T item;

	public static void main(String[] args) {
		//定义了一个匿名内部类并实例化
		Data<Double> data = new Data<Double>(){
		};
		Class<?> clazz = data.getClass();
		Type type = clazz.getGenericSuperclass();
		if(type instanceof ParameterizedType){
			ParameterizedType pt = (ParameterizedType)type;
			 //返回参数类型对应的原始类型,这是为 xx.xx.Data
            Type rawType = pt.getRawType();  
            //返回泛型参数数组,这里为 [java.lang.Double]  
            Type[] typeArgs = pt.getActualTypeArguments();  
		}
	}
}
尽管通过以上方式我们能获取到对象data的泛型参数Double,但却不得不定义一个明确泛型参数的子类,归根到底还是在于Class对象代表的是class文件,和它实例的对象无关。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值