[英]generic type erasure ClassCastException
package practice;
class Node<T> {
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); }
@Override
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
}
public class Practice {
public static void main(String[] s)
{
MyNode mn = new MyNode(5);
Node n = mn; // A raw type - compiler throws an unchecked warning
n.setData("Hello"); // Causes a ClassCastException to be thrown.
Integer x = mn.data;
}
}
Why does this code throw exception at n.setData("Hello");
为什么这段代码会在
n.setData("Hello");
抛出异常n.setData("Hello");
when actually it should throw the exception at Integer x = mn.data;
实际上它应该在
Integer x = mn.data;
抛出异常Integer x = mn.data;
? ?
http://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html http://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html
因为您正在尝试将String值设置为Integer变量。
You have already defined the type T
for Node
by calling 您已经通过调用为
Node
定义了类型T
MyNode mn = new MyNode(5);
namely Integer
type. 即
Integer
类型。 By calling n.setData("Hello");
通过调用
n.setData("Hello");
you are attempting to pass in a String variable for an Integer field. 您正在尝试为Integer字段传递String变量。 Node
n
is merely a reference for the Integer
typed Node mn
. 节点
n
仅仅是Integer
类型节点mn
的参考。
I think there is a small mistake in the tutorial: they should have said that the error is thrown at line n.setData("Hello");
我认为教程中有一个小错误:他们应该说错误是在
n.setData("Hello");
行n.setData("Hello");
That's because when you call n.setData("Hello");
那是因为当你调用
n.setData("Hello");
you call the bridge method: n.setData(Object object)
on MyNode
class, otherwise you would have a compile time error. 你在
MyNode
类上调用bridge方法: n.setData(Object object)
,否则会产生编译时错误。
But the bridge method looks like this: 但是桥接方法看起来像这样:
// Bridge method generated by the compiler
//
public void setData(Object data) {
setData((Integer) data);
}
You see that the bridge tries to invoke the setData(Integer anInt)
with a cast on the data
. 您会看到网桥尝试使用对
data
setData(Integer anInt)
来调用setData(Integer anInt)
。 And this cast fails because you provided a String
. 此演员表失败,因为您提供了一个
String
。
What's also interesting at this example is that you get no compile time error when using @Override
annotation even that you technically don't override, but the compiler overrides later. 在这个例子中有趣的是,使用
@Override
注释时没有编译时错误,即使您在技术上没有覆盖,但编译器稍后会覆盖。 The annotation is very very useful here to inform that the setData(Object object)
will be called on MyNode
not on Node
. 注释在这里非常有用,以告知将在
MyNode
上调用setData(Object object)
而不是在Node
上调用。 This explains why you don't see any of the System.out
messages. 这解释了为什么您没有看到任何
System.out
消息。
Because the type of n
is actually Integer
, which it received from mn
. 因为
n
的类型实际上是从mn
收到的Integer
。
It's the same principle as List list = new ArrayList();
它与
List list = new ArrayList();
原理相同List list = new ArrayList();
The list here is actually an ArrayList
, but only referenced using the List interface. 这里的列表实际上是一个
ArrayList
,但只使用List接口引用。 Similarly, even though n
is a Node
, it's implementation is a MyNode
which only accepts Integer
. 同样,即使
n
是一个Node
,它的实现也是一个只接受Integer
的MyNode
。 That's why you can put a String
in setData()
这就是你可以在
setData()
放置一个String
的原因
After reading the edit example 阅读编辑示例后
The page says that a bridge method is created as follows : 该页面表示如下创建桥接方法:
class MyNode extends Node {
// Bridge method generated by the compiler
//
public void setData(Object data) {
setData((Integer) data);
}
public void setData(Integer data) {
System.out.println("MyNode.setData");
super.setData(data);
}
// ...
}
The bridge method does the following 桥接方法执行以下操作
public void setData(Object data) {
setData((Integer) data);
}
Here it is trying to cast data which is the String
"Hello" into an Integer
. 这里它试图将
String
“Hello”的数据转换为Integer
。 Hence the error is thrown. 因此抛出了错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.