类型擦除 - 泛型 - 使ClassCastException不在预期的位置

时间:2015-10-14 14:52:21

标签: java generics type-erasure

我正在浏览此页面,只是玩它提供的示例。

http://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html

我使用的是Java 8。

根据本教程页面,ClassCastException应该在第200行抛出,但实际上它已经被抛出 - 在标记为100的行上。为什么?!教程是否过时(不适用于Java 8)?

然后我问了n的所有方法,我可以看到方法setData(Object)就在那里,它位于n所指向的对象中(就是这样) - 称为桥接方法,我假设)。

好的,为什么我会在标记为100的行中获得异常?编译器是否将我的set调用转换为此n.setData((Integer)"Hello");如果是这样,那么教程似乎确实已经过时了。

有人可以解释一下吗?

import java.lang.reflect.Method;

public class Test010 {

    public static void main(String[] args) {
        MyNode mn = new MyNode(5);
        Node n = mn; // A raw type - compiler throws an unchecked warning
        Method meth[] = n.getClass().getMethods();
        n.setData("Hello"); // 100 //
        System.out.println("001");
        Integer x = mn.data; // 200 // // Causes a ClassCastException to be thrown.
    }

}

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

3 个答案:

答案 0 :(得分:4)

好吧,好吧,我在这里发布问题后不久就明白了。

实际上在第200行抛出的异常:这不是事实,教程只是假设提到了这一点。在本教程的后面,很明显桥setData方法包含一个强制转换为Integer的类型。

public void setData(Object data) {
    setData((Integer) data);
}

这就是导致我的问题和困惑的原因。

无论如何,这个教程页面看起来有点令人困惑,但好吧,也许只是我。

答案 1 :(得分:1)

我倾向于说教程是错的。如果没有涉及类MyNode,或者MyNode一般地继承Node<T>,而不是具体地通过类型参数指定,那将是正确的。但是,一旦MyNode定义了type参数的特定值,类型擦除就不再适用于它。

答案 2 :(得分:0)

是的,该教程使我非常困惑。以下代码中的注释并不表示jvm执行这些代码时会发生什么。

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.

只是假定Node中的setData没有被覆盖。

但是实际上bridge方法会覆盖Node中的setData,并使其似乎被MyNode中的setData覆盖。

这种情况更像是多态。