(转载)JVM如何理解Java泛型类
转载:http://www.iteye.com/topic/549509
?
?
??????? 这样看似乎没有问题的代码连编译器都通过不了:
?????? 【Error】 ?? Name clash: The method equals(T) of type Pair<T> has the same erasure as equals(Object) of type Object but does not override it。
??????? 编译器说你的方法与Object中的方法冲突了。这是为什么?
?
??????? 开始我也不太明白这个问题,觉得好像编译器帮助我们使得equals(T)这样的方法覆盖上了Object中的equals(Object)。经过大家的讨论,我觉得应该这么解释这个问题?
?
??????? 首先、我们都知道子类方法要覆盖,必须与父类方法具有相同的方法签名(方法名+参数列表)。而且必须保证子类的访问权限>=父类的访问权限。这是大家都知道的事实。
??????? 然后、在上面的代码中,当编译器看到Pair<T>中的equals(T)方法时,第一反应当然是equals(T)没有覆盖住父类Object中的equals(Object)了。
??????? 接着、编译器将泛型代码中的T用Object替代(擦除)。突然发现擦除以后equals(T)变成了equals(Object),糟糕了,这个方法与Object类中的equals一样了。基于开始确定没有覆盖这样一个想法,编译器彻底的疯了(精神分裂)。然后得出两个结论:①坚持原来的思想:没有覆盖。但现在一样造成了方法冲突了。 ? ②写这程序的程序员疯了(哈哈)。
?
??????? 再说了,拿Pair<T>对象和T对象比较equals,就像牛头对比马嘴,哈哈,逻辑上也不通呀。
?
(3) 没有泛型数组一说
?
????? Pair<String>[] stringPairs=new Pair<String>[10];
????? Pair<Integer>[] intPairs=new Pair<Integer>[10];
????? 这种写法编译器会指定一个Cannot create a generic array of Pair<String>的错误
?
????? 我们说过泛型擦除之后,Pair<String>[]会变成Pair[],进而又可以转换为Object[];
????? 假设泛型数组存在,那么
??????????? Object[0]=stringPairs[0]; Ok
??????????? Object[1]=intPairs[0]; Ok
?????? 这就麻烦了,理论上将Object[]可以存储所有Pair对象,但这些Pair对象是泛型对象,他们的类型变量都不一样,那么调用每一个Object[]数组元素的对象方法可能都会得到不同的记过,也许是个字符串,也许是整形,这对于JVM可是无法预料的。
?
????? 记住: 数组必须牢记它的元素类型,也就是所有的元素对象都必须一个样,泛型类型恰恰做不到这一点。即使Pair<String>,Pair<Integer>... 都是Pair类型的,但他们还是不一样。
?
总结:泛型代码与JVM
??? ① 虚拟机中没有泛型,只有普通类和方法。
??? ② 在编译阶段,所有泛型类的类型参数都会被Object或者它们的限定边界来替换。(类型擦除)
??? ③ 在继承泛型类型的时候,桥方法的合成是为了避免类型变量擦除所带来的多态灾难。