详解java 中泛型中的类型擦除和桥方法
在Java中,泛型的引入是为了在编译时提供强类型检查和支持泛型编程。为了实现泛型,Java编译器应用类型擦除实现:
1、 用类型参数(typeparameters)的限定(如果没有就用Object)替换泛型类型中的所有类型参数。
2、 需要保持类型安全的时候插入类型转换(隐含插入)
3、 在extened泛型类型中生成桥方法来保证多态性
类型擦除确保不会为已参数化了的类型(paramterizedtypes)产生新类,这样泛型能保证没有运行时的负载。
泛型类型擦除
在类型擦除过程中,java编译器擦除所有类型参数,用它的限定或者Object(没限定时)替换。
考虑下面的泛型类:
publicclassNode{ privateTdata; privateNode next; publicNode(Tdata,Node next)} this.data=data; this.next=next; } publicTgetData(){returndata;} //... }
因为类型参数T是非限定的,Java编译器使用Object替换它:
publicclassNode{ privateObjectdata; privateNodenext; publicNode(Objectdata,Nodenext){ this.data=data; this.next=next; } publicObjectgetData(){returndata;} //... }
下面的例子,泛型Node类使用了限定类型参数:
publicclassNode>{ privateTdata; privateNode next; publicNode(Tdata,Node next){ this.data=data; this.next=next; } publicTgetData(){returndata;} //...
编译器会使用第一个限定类,Comparable替换限定参数类型T:
publicclassNode{ privateComparabledata; privateNodenext; publicNode(Comparabledata,Nodenext){ this.data=data; this.next=next; } publicComparablegetData(){returndata;} //... }
同样,泛型方法也可以擦除。规则类似,不细说。
类型擦除的影响和桥方法
有时候类型擦除会引起无法预知的情况。比如:
给定以下两个类:
publicclassNode{ publicTdata; publicNode(Tdata){this.data=data;} publicvoidsetData(Tdata){ System.out.println("Node.setData"); this.data=data; } } publicclassMyNodeextendsNode { publicMyNode(Integerdata){super(data);} publicvoidsetData(Integerdata){ System.out.println("MyNode.setData"); super.setData(data); } }
考虑以下代码:
MyNodemn=newMyNode(5); Noden=mn;//原生类型–编译器会给出未检查警告 n.setData("Hello"); Integerx=mn.data;//会引发抛出ClassCastException
类型擦除后,代码变成:
MyNodemn=newMyNode(5); Noden=(MyNode)mn;//原生类型–编译器会给出未检查警告 n.setData("Hello"); Integerx=(String)mn.data;//会引发抛出ClassCastException
publicclassNode{ publicObjectdata; publicNode(Objectdata){this.data=data;} publicvoidsetData(Objectdata){ System.out.println("Node.setData"); this.data=data; } } publicclassMyNodeextendsNode{ publicMyNode(Integerdata){super(data);} publicvoidsetData(Integerdata){ System.out.println("MyNode.setData"); super.setData(data); } }
类型擦除后,方法的签名已经不匹配。Node方法变成setData(Object),MyNode方法变成setData(Integer)。MyNodesetData方法已经不是覆盖NodesetData方法。
为了解决这个问题,维持泛型类型的多态性,java编译器会生成一个桥方法:
classMyNodeextendsNode{ //编译器生成的桥方法 // publicvoidsetData(Objectdata){ setData((Integer)data); } publicvoidsetData(Integerdata){ System.out.println("MyNode.setData"); super.setData(data); } //...
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!