Java上的类型Erasure教程

时间:2016-03-13 12:09:56

标签: java generics type-erasure java-bridge-method

我正在阅读Oracle上的泛型跟踪(Type Erasure),但我无法理解以下部分。

代码段如下所示:

public 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;
    }
}

public class MyNode extends Node<Integer> {
    public MyNode(Integer data) { super(data); }

    public void setData(Integer data) {
        System.out.println("MyNode.setData");
        super.setData(data);
    }
}

该踪迹提到了以下内容:

请考虑以下代码:

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.

在类型擦除之后,此代码变为:

MyNode mn = new MyNode(5);
Node n = (MyNode)mn;         // A raw type - compiler throws an unchecked warning
n.setData("Hello");
Integer x = (String)mn.data; // Causes a ClassCastException to be thrown.

引自同一教程 -

以下是代码执行时发生的事情

  • n.setData(&#34;你好&#34);导致方法setData(Object)被执行 在MyNode类的对象上。 (MyNode类继承 来自Node的setData(Object)。)
  • 在setData(Object)的主体中,n引用的对象的数据字段被分配给String。
  • 可以访问通过mn引用的同一对象的数据字段,并且预期它是一个整数(因为mn是一个节点的MyNode。
  • 尝试将String分配给Integer会导致Java编译器在赋值时插入的转换中出现ClassCastException。

我无法理解为什么尝试检索数据会导致异常。至于我的理解不应该设置数据本身抛出一个异常(这是我的编译器发生的事情,但因为我没有使用Oracle的编译器,我不确定哪个是正确的)?

如果我的理解是正确的,MyNode类应该有两种方法:

void setData(Object); //bridge method
void setData(Integer);

因此,在Node上调用setData(Object)应该正确调用MyNode中的bridge方法,而MyNode又调用setData(Integer),这是应该抛出类抛出异常的地方。但甲骨文&#39;教程中不再说这不是这种情况。那么我的理解有什么问题?请帮我理解。

2 个答案:

答案 0 :(得分:0)

  

如果我的理解是正确的,MyNode类应该有两种方法   void setData(Object); //桥法   void setData(Integer);

这是事实。 MyNode类将具有以上两种方法。

javap上执行MyNode.class也可以显示它。请参阅**

之间突出显示的以下方法
javap MyNode.class
Compiled from "MyNode.java"  
public class com.demo.generics.demo.MyNode extends com.demo.generics.demo.Node<j
ava.lang.Integer> {
  public com.demo.generics.demo.MyNode(java.lang.Integer);
  **public void setData(java.lang.Integer);**
  public static void main(java.lang.String[]);
  **public void setData(java.lang.Object);**
}
  

因此,在Node上调用setData(Object)应该正确地调用桥   MyNode中的方法,它反过来调用setData(Integer)就在哪里   应该抛出类转换异常。

这也是事实。调用它会导致以下异常:

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at com.demo.generics.demo.MyNode.setData(MyNode.java:1)
    at com.demo.generics.demo.MyNode.main(MyNode.java:14)

MyNode.java:14是我打电话给n.setData("Hello");

的地方
  

这是在我的编译器上发生的事情,但由于我没有使用Oracle的编译器,我不确定哪个是正确的)?

这不依赖于编译器,它应该是相同的。

答案 1 :(得分:0)

昨天我在阅读文档时遇到了这个问题。我在Oracle错误跟踪器中打开了bug,并添加了此问题作为参考。