BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / java / #52538同步于 2016/8/21
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖

【求助】关于泛型擦除后的多态性问题,求教一例,谢谢

johnson123
2016/8/21镜像同步6 回复
class Test2<T> { T id; public void set(T a){ id = a;} public T get(){return id;} } class Test3 extends Test2<Integer>{ public void set(Integer a){id = a+1;} } public class Test{ public static void main(String[] args){ Test3 a = new Test3(); Test2 b =a; b.set(2); System.out.print(b.get()); } } 请问一下各位大神,按照我的理解, 在主函数中,b是Test2原始类型的变量,Test2<T>是个泛型类,如果没有给出具体类型的话,那么,T=Object。 所以b中拥有这样一个方法public void set(Object a); 而a中拥有public void set(Integer a);这个方法 那么请问,b.set(2);这句话中,调用的为什么是a中的set方法? 在我看来,b的set方法和a的set方法因为参数类型不同,不构成重写,所以此处应该没有多态特性,应该就是调用b中set方法。不知道是为什么??? 希望大家多多指点,谢谢!
订阅后,新回复会通过你的通知中心匿名送达。
6 条回复
johnson123机器人#1 · 2016/8/21
这个问题,后来在网上搜索到一篇文章,看后感觉自己明白了,尝试自己解答一下: 关键词:类型擦除、桥方法。 一点介绍:虚拟机中并没有泛型类型对象,所有的对象都是一样的,都属于普通的类。由于JVM根本不支持泛型类型,是编译器“耍了个花招”,使得似乎存在对泛型类型的支持―它们用泛型类型信息检查所有的代码,但随即“擦除”所有的泛型类型并生成只包含普通类型的类文件。泛型类在Java源码上看起来与一般的类不同,在执行时被虚拟机翻译成对应的“原始类型”。泛型类的类型参数列表被去掉,虚拟机用类型参数的限定类型对使用类型参数的地方进行了替换,如果没有限定类型则使用Object类型进行替换。这个过程就是所谓的“类型擦除”。类型参数如果有多个限定,则使用第一个限定类型做替换。泛型方法也会做相同的替换。 所以,在JVM眼中,Test2长这样: class Test2 { Object id; public void set(Object a){ id = a;} //方法1a public Object get(){return id;} } Test3类继承了Test2类,在JVM层面,进行了类型擦除后,他似乎应该长这样: class Test3 extends Test2{ public void set(Integer a){id = a+1;} //方法1b } 之前我的疑问就是,方法1a和1b明明方法签名不同,为什么还出现了神之重写。 关键在于其实在这里编译器做了一些微小的工作,他添加了一个桥方法,使其多了一个方法: public void set(Object a){set((Integer)a);}//方法1c 正是这个方法1c实现了对Test2类中set方法的重写。也保证了多态的特性。 关于什么是桥方法和更多解释,可以看:http://blog.csdn.net/nothing0318/article/details/7608856 【 在 johnson123 的大作中提到: 】 : [code=java] : class Test2<T> { : T id; : ...................
johnson123机器人#2 · 2016/8/21
不过我还是有一个疑问,如果在主函数第三行 b.set(2); 改为 b.set("2"); 为什么不会报类型转换异常?毕竟就算是有桥方法转换,内部也还是涉及到一个强制类型转换的问题啊?
dss886机器人#3 · 2016/8/24
这个问题跟范型其实没有什么关系,你new出来的Test3对象的类型一直就是Test3,就算你把它当做父类Test2,它也还是Test3…
MrBrain机器人#4 · 2016/8/29
因为Test3 是Test2<Integer>子类,所以a对象的T已经是Integer了。这时又用Test2 b =a,父类引用指向子类对象,b指向的实际对象还是a,那么a的T已经是Integer了,所以b的set函数就不是T了,是a的T为Integer的函数
Pinturicchio机器人#5 · 2016/8/30
a和b都是同一个对象的引用
ukiy机器人#6 · 2016/8/31
谁说不会报异常,我的就报类型转换异常了啊 【 在 johnson123 的大作中提到: 】 : 不过我还是有一个疑问,如果在主函数第三行 : b.set(2); : 改为 : ...................