深入理解java范型

1、要理解java编译和解释执行的过程。在各过程中,范型的存在性、存在方式、被处理方式。
2、编译器编译源代码时,会检查范型,防止类型出错。
例如:List<String> usernames = new ArrayList<Integer>();将不能通过编译。
它将源代码编译为字节码,这时候的字节码,与没有使用范型编译过来的字节码比较,多出了一些范型信息。
但是这些范型信息的有无,对于JVM是一样的(如果不考虑反射)。
List<String> usernames = new ArrayList<String>();
Object o = usernames;
List<Integer> ints = (List<Integer>)o;//warning
usernames.add("avril lavigne");
ints.add(100);
以上代码,ints和usernames指向同一个列表,但是却可以添加字符串和整型对象。
这段代码应该会加深你对范型的理解。
3、 对“拭去法”的理解,并不只是简单的将范型信息擦除。
public class Hello<T> {
T t;
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
Type[] types = Hello.class.getTypeParameters();
System.out.println(types[0]);
Hello<String> h = new Hello<>();
h.t = "";
h.getClass().getDeclaredField("t").set(h, 1);;
System.out.println(h.t);
}
}
这段代码通过编译,并输出
T
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at generic.Hello.main(Hello.java:13)
也就是说,字节码被载入jvm后,字段的类型仍然保持为T。这也验证了范型是参数化类型的说法。
如果再加两行代码
Hello<Integer> h2 = new Hello<>();
h2.t = (Integer)(Object)h.t;
也将通过编译,然而运行却报异常。
说明在实例化对象的时候,动态的将字段的类型进行了设定,<String>和<Integer>的信息对运行时产生了影响!!!
同一个类型实例化的对象,相同的属性类型却不能匹配!!!
有范型和没范型,编译得到的字节码有本质的不同。jvm载入后,类中含有参数化类型。
这个类型化参数,是在运行时动态绑定的!
范型没有被拭去?是的。"拭去法"并不能简单的理解。
更准确的理解应该是,编译时,对于类定义,范型作为类型的参数化信息,并不决定类型。
拭去,指的是在类定义时,范型不决定被定义类的类型,而不是指范型信息被擦除!范型信息仍然是该类的一部分!!!



猜你喜欢

转载自blog.csdn.net/zhoujiaping123/article/details/51660926