擦除类型和桥接方法说明
Erasure type and Bridging Method clarification
以下代码取自泛型的 Oracle 文档 -
class Node<T> {
public T data;
public Node(T data) { this.data = data; }
public void setData(T data) {
System.out.println("Node.setData");
this.data = data;
}
}
class MyNode extends Node<Integer> {
public MyNode(Integer data) { super(data); }
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
public static void main(String[] args) {
MyNode mn = new MyNode(5);
Node n = mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = mn.data; // Causes a ClassCastException to be thrown.
}
}
我对这段代码的理解 -
问 - 方法 setData
是被覆盖还是重载?
我的理解 - 因为 MyNode
正在扩展 Node<Integer>
,类型参数 T
的值被设置为 Integer
。
所以 class Node
有方法 setData(Integer data)
as T= Integer
class MyNode
有方法 setData(Integer data)
。
覆盖 因为签名相同。
问- setData 方法是否在擦除后被覆盖?
我的理解 -
我们擦除后 <T>
set 方法变为 Node
变为 setData(Object data)
和 Mynode
的设置方法将是 - setData(Integer data)
因为没有类型参数,没有什么可以删除的。
但这是超载。
问 - 我们想要重载或覆盖?
我的理解 - 从擦除之前定义的方法来看,我们想要覆盖。
Q - 那么如何实现擦除后覆盖?
我的理解 - 通过 桥接方法。例如:
setData(Object data){
setData((Integer) Data);
}
我的理解正确吗?
此外,class MyNode extends Node<Integer>
何时将 Integer
传递给 <T>
?什么时候调用 super?
- 是的,方法
setData
被覆盖。
从用户的角度来看,它看起来好像 setData(T data)
被 setData(Integer i)
覆盖了,即当您调用 setData(42)
时,它会用 "MyNode" 打印一些东西,而不是 "Node"。
在类型擦除方法签名级别,这将通过添加到 MyNode
的合成桥方法 setData(Object)
来实现,即如果您使用 [=19= 反编译 MyNode.class
],你会看到两个方法:
public void setData(java.lang.Integer);
public void setData(java.lang.Object);
语言规范说"override",我不知道为什么会有人想要其他东西。
不清楚你说的"achieve overriding after erasure"是什么意思。类型擦除发生在类型检查和确定什么覆盖什么之后。 "achieve" 没有任何意义,它只是事物工作的顺序(另请参阅 this comment)。覆盖原始 setData(Object)
的合成桥接方法看起来像你写的(小错别字):
setData(Object data){
setData((Integer) data);
}
至少 the documentation says 是这样。但这是一个synthetic方法,它是由编译器自动生成的。如果它出现在源代码中,它会给你编译错误。
以下代码取自泛型的 Oracle 文档 -
class Node<T> {
public T data;
public Node(T data) { this.data = data; }
public void setData(T data) {
System.out.println("Node.setData");
this.data = data;
}
}
class MyNode extends Node<Integer> {
public MyNode(Integer data) { super(data); }
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
public static void main(String[] args) {
MyNode mn = new MyNode(5);
Node n = mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = mn.data; // Causes a ClassCastException to be thrown.
}
}
我对这段代码的理解 -
问 - 方法 setData
是被覆盖还是重载?
我的理解 - 因为 MyNode
正在扩展 Node<Integer>
,类型参数 T
的值被设置为 Integer
。
所以 class Node
有方法 setData(Integer data)
as T= Integer
class MyNode
有方法 setData(Integer data)
。
覆盖 因为签名相同。
问- setData 方法是否在擦除后被覆盖? 我的理解 -
我们擦除后 <T>
set 方法变为 Node
变为 setData(Object data)
和 Mynode
的设置方法将是 - setData(Integer data)
因为没有类型参数,没有什么可以删除的。
但这是超载。
问 - 我们想要重载或覆盖?
我的理解 - 从擦除之前定义的方法来看,我们想要覆盖。
Q - 那么如何实现擦除后覆盖?
我的理解 - 通过 桥接方法。例如:
setData(Object data){
setData((Integer) Data);
}
我的理解正确吗?
此外,class MyNode extends Node<Integer>
何时将 Integer
传递给 <T>
?什么时候调用 super?
- 是的,方法
setData
被覆盖。 从用户的角度来看,它看起来好像
setData(T data)
被setData(Integer i)
覆盖了,即当您调用setData(42)
时,它会用 "MyNode" 打印一些东西,而不是 "Node"。在类型擦除方法签名级别,这将通过添加到
MyNode
的合成桥方法setData(Object)
来实现,即如果您使用 [=19= 反编译MyNode.class
],你会看到两个方法:public void setData(java.lang.Integer); public void setData(java.lang.Object);
语言规范说"override",我不知道为什么会有人想要其他东西。
不清楚你说的"achieve overriding after erasure"是什么意思。类型擦除发生在类型检查和确定什么覆盖什么之后。 "achieve" 没有任何意义,它只是事物工作的顺序(另请参阅 this comment)。覆盖原始
setData(Object)
的合成桥接方法看起来像你写的(小错别字):setData(Object data){ setData((Integer) data); }
至少 the documentation says 是这样。但这是一个synthetic方法,它是由编译器自动生成的。如果它出现在源代码中,它会给你编译错误。