技术开发 频道

JAVA泛型浅析


IT168技术文档】 
    反射: 
    由于泛型的引入,导致原来的反射机制增加了很多新的接口,如:下图所示,图中黄色部分是新增加的接口(仅仅给出一部分),用于支持泛型,绿色部分是已有的部分;



    Java编译器在编译的时候,同时生成针对擦除类型和泛化类型的两套字节码,而在运行时,JVM只使用擦除类型的字节码,泛化类型的字节码仅仅被用于反射! 
    看一个简单的例子:
List<Integer> ints = new ArrayList<Integer>(); Class<?> cls = ints.getClass(); out.println(cls.getName()); TypeVariable<?>[]tv = cls.getTypeParameters(); for(TypeVariable<?> it : tv){ out.println(it.getName()); }
        输出: 
        java.util.ArrayList 
       
    这里首先是输出实例ints的类型名字,然后输出ints的类型参数的名字,按照大多数人的设想,这个类型参数的名字应该是java.lang.Integer,然而输出的是“E”。原因就是上面的那句话,运行时使用的时擦除字节码,Integer都变成了Object,反射字节码就用于反射操作,原代码中的变量E,将被编译到反射字节码中,所以… 
    由于引入了泛型,原来的Class在泛型中都变成了Class<T>,其中T是可以具体化的类型;因为class永远代表一个具体化的类型,所以不允许使用非具体化类型来参数化Class!如:
Class<Integer> c1 = Integer.class; // OK Class<? Extends Number> c2= Integer.class
//OK Integer.class的类型是Class<Integer>而Class<Integer>刚好是Class<? Extends Number>的子类 Class<?> c3 = List<Integer>.class //错误,违背上面的原则 Class<?> c4 = Integer.class; //OK
    如果一个表达式Exp其返回的结果类型是T,那么Exp.class的类型就是Class<? Extends |T|>,其中|T|是T的擦除类型!
List<Integer> ints = new ArrayList<Integer>(); Class<? extends List> k = ints.getClass(); assert k == ArrayList.class;
    总结: 
    本文主要列举了在使用Java泛型时应该注意的问题。Java泛型是Java5的一个重要特性,它和自动装箱、变长参数等新特性一起,提升了Java代码的健壮性和易用性,但SUN本身过分强调向前的兼容性,也引入了不少问题和麻烦。
0
相关文章