我对桥接方法创建有一些疑问。我们可以应用桥接技术进行协变覆盖。现在考虑一下官方帮助中的例子:
public class Node<T>{
private T data;
public Node(T data){ this.data=data;}
public void setData(T data){
System.out.println("Node.setData");
this.data=data;
}
}
public class MyNode extends Node<Integer>{
public MyNode(Integer data){ super(data); }
public void setData(Integer data){
System.out.println("MyNode.setData");
this.data=data;
}
}
让桥方法不创造。因此,在运行时,类MyNode
有两种方法:setData(Integer)
和setData(Object)
,其中last从Node
继承。当我们打电话setData(new Inetegr(5))
时会调用setData(Integer)
。如果我们写Object o= new Integer(5); setData(o);
,则会调用setData(Object)
。这不是真的。 所以有两个问题:
答案 0 :(得分:2)
我是否理解正确引入桥接方法的原因?
我想是的。如果编译器没有生成桥接方法,那么子类中的方法将是超类方法的重载版本,而不是重写版本。你似乎已经明白了。
桥接方法创建的必要条件和条件是什么?
扩展或实现参数化类型时,键入erasure会更改超类中方法的签名。
如果我们写
Object o= new Integer(5); setData(o);
,则会调用setData(Object)
。事实并非如此。
我不明白你是什么意思。您应该在非通用代码上测试此行为。当方法重载时,方法调用将绑定到编译时根据您传递的参数的声明类型决定哪个方法。由于在这种情况下声明的类型是Object
,因此它将调用setData(Object)
版本。
答案 1 :(得分:1)
这是应用桥接技术的编译器,而不是我们。在您的情况下,编译器将在此处插入桥接
class MyNode extends Node<Integer> {
public void setData(Object data) {
setData((Integer) data);
}
...
这就是使用
的原因 Node<Integer> n = new MyNode();
n.setData(1);
Node没有setData(Integer)它有setData(Object)。 MyNode桥接方法setData(Object)覆盖它。 JVM检测到实际类型的n是MyNode并调用MyNode.setData(Object),它将重定向到setData(Integer)。
应用桥接方法的另一种情况是协变返回类型
class X implements Cloneable {
@Override
pubic X clone() {
...
}
需要实际覆盖Object.clone。请注意,在字节码中,签名方法包括返回类型