java - Java 类型删除教程

标签 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("你好");导致方法 setData(Object) 被执行 在 MyNode 类的对象上。 (MyNode类继承 来自节点的 setData(Object)。)
  • 在setData(Object)的主体中,将n引用的对象的data字段赋值给一个String。
  • 可以访问通过 mn 引用的同一对象的数据字段,它应该是一个整数(因为 mn 是一个 MyNode,它是一个节点。
  • 尝试将字符串分配给整数会导致 Java 编译器在分配时插入的强制转换引发 ClassCastException。

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

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

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

因此,在 Node 上调用 setData(Object) 应该正确地调用 MyNode 中的桥接方法,而 MyNode 又会调用 setData(Integer),这是应该抛出类转换异常的地方。但是 Oracle 的教程特意指出事实并非如此。那么我的理解有什么问题呢?请帮助我理解。

最佳答案

If my understanding is right the class MyNode should have two methods
void setData(Object); //bridge method
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);**
}

So calling setData(Object) on Node should rightfully call the bridge method in MyNode which in turn calls setData(Integer) which is where the class-cast exception should be thrown.

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

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");

的地方

this is what happens on my compiler but since I am not using Oracle's compiler I am not sure which is right)?

这与编译器无关,它应该是相同的。

关于java - Java 类型删除教程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35970031/

相关文章:

ios - 泛型的偏函数应用

c# - 使用 GetType() 创建 List<T>

c++ - 有没有办法让一组未初始化的类在调用 delete[] 时不会被破坏?

javap 和泛型的类型删除

c# - 为什么这个泛型类会产生编译器错误?

java - 为 toString 更改 HashMap 的键值分隔符

java - 限制Java子接口(interface)中的泛型类型

java - macOS:在应用程序中嵌入 OpenJDK 11 仍会引发 java 6 警报

Scala:基于类型参数过滤集合

Java Swing : Autoscrolling using JList and JScrollPane