【问题标题】:Type Erasure tutorial on JavaJava 类型擦除教程
【发布时间】:2016-03-13 12:09:56
【问题描述】:

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

sn-ps代码如下:

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("你好");导致方法 setData(Object) 被执行 在 MyNode 类的对象上。 (MyNode 类继承 来自节点的 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 方法,该方法又调用 setData(Integer) ,这是应该抛出类转换异常的地方。但是甲骨文的教程特意说事实并非如此。那么我的理解有什么问题呢?请帮我理解。

【问题讨论】:

  • 是的,看来教程是错误的。 setData 应该抛出运行时错误。

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


【解决方案1】:

如果我的理解是正确的,MyNode 类应该有两个方法
无效集合数据(对象); //桥接方法
void setData(Integer);

确实如此。 MyNode 类将具有以上两种方法。

MyNode.class 上执行javap 也会显示出来。请参阅以下两种方法在 **

之间突出显示
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 的编译器,我不确定哪个是正确的)?

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

【讨论】:

  • 那么教程错了吗?我想他们只需要被告知,以便他们可以更新他们的教程。顺便问一下你用的是Oracle的编译器吗?
  • @AshishDaggubatti 我将阅读本教程并对此发表评论。是的,我的是 Oracle JDK。
  • @AshishDaggubatti 嗯..我看起来教程是误导关于何时确切地提出 ClassCastException。一方面它显示ClassCastException 将在Integer x = mn.data; 语句中引发,然后在最后它说生成的bridge method 将调用setData((Integer) data);,这似乎是自相矛盾的,理想情况下,这就是ClassCastException真的是养的。除非我们误解了本教程,我对此表示怀疑:-)
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多