泛型类型擦除ClassCastException

时间:2012-09-09 10:15:24

标签: java generics

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

为什么此代码会在n.setData("Hello");处抛出异常,而实际应该在Integer x = mn.data;处抛出异常?

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

4 个答案:

答案 0 :(得分:2)

因为您正在尝试将String值设置为Integer变量。

答案 1 :(得分:1)

您已通过调用

T定义了Node类型
MyNode mn = new MyNode(5);

Integer类型。通过调用n.setData("Hello");,您尝试传入一个Integer字段的String变量。节点n仅是Integer类型节点mn的参考。

答案 2 :(得分:1)

我认为教程中有一个小错误:他们应该说错误是在n.setData("Hello");

这是因为当您致电n.setData("Hello");时,您调用了桥接方法:n.setData(Object object) 类上的MyNode ,否则您将遇到编译时错误。

但是桥接方法看起来像这样:

// Bridge method generated by the compiler
//
public void setData(Object data) {
    setData((Integer) data);
}

您看到网桥试图在setData(Integer anInt)上使用强制转换来调用data。此演员表失败,因为您提供了String

在这个例子中,有趣的是,在使用@Override注释时,即使技术上没有覆盖,也没有编译时错误,但编译器会在以后覆盖。这里的注释非常有用,可以告知setData(Object object) MyNode不会Node上的System.out。这解释了为什么您没有看到任何{{1}}消息。

答案 3 :(得分:0)

因为n的类型实际上是Integer,它是从mn收到的。

这与List list = new ArrayList();

的原理相同

此处的列表实际上是ArrayList,但仅使用List接口引用。同样,即使nNode,它的实现也是MyNode,只接受Integer。这就是为什么你可以在String

中添加setData()

阅读编辑示例后

该页面表示如下创建桥接方法:

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

    // ...
}

桥接方法执行以下操作

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

这里尝试将String“Hello”的数据转换为Integer。因此抛出了错误。