简体   繁体   English

泛型类型擦除ClassCastException

[英]generic type erasure ClassCastException

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

Why does this code throw exception at n.setData("Hello"); 为什么这段代码会在n.setData("Hello");抛出异常n.setData("Hello"); when actually it should throw the exception at Integer x = mn.data; 实际上它应该在Integer x = mn.data;抛出异常Integer x = mn.data; ?

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

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

You have already defined the type T for Node by calling 您已经通过调用为Node定义了类型T

MyNode mn = new MyNode(5);

namely Integer type. Integer类型。 By calling n.setData("Hello"); 通过调用n.setData("Hello"); you are attempting to pass in a String variable for an Integer field. 您正在尝试为Integer字段传递String变量。 Node n is merely a reference for the Integer typed Node mn . 节点n仅仅是Integer类型节点mn的参考。

I think there is a small mistake in the tutorial: they should have said that the error is thrown at line n.setData("Hello"); 我认为教程中有一个小错误:他们应该说错误是在n.setData("Hello");n.setData("Hello");

That's because when you call n.setData("Hello"); 那是因为当你调用n.setData("Hello"); you call the bridge method: n.setData(Object object) on MyNode class, otherwise you would have a compile time error. MyNode调用bridge方法: n.setData(Object object) ,否则会产生编译时错误。

But the bridge method looks like this: 但是桥接方法看起来像这样:

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

You see that the bridge tries to invoke the setData(Integer anInt) with a cast on the data . 您会看到网桥尝试使用对data setData(Integer anInt)来调用setData(Integer anInt) And this cast fails because you provided a String . 此演员表失败,因为您提供了一个String

What's also interesting at this example is that you get no compile time error when using @Override annotation even that you technically don't override, but the compiler overrides later. 在这个例子中有趣的是,使用@Override注释时没有编译时错误,即使您在技术上没有覆盖,但编译器稍后会覆盖。 The annotation is very very useful here to inform that the setData(Object object) will be called on MyNode not on Node . 注释在这里非常有用,以告知将在MyNode上调用setData(Object object)而不是在Node上调用。 This explains why you don't see any of the System.out messages. 这解释了为什么您没有看到任何System.out消息。

Because the type of n is actually Integer , which it received from mn . 因为n的类型实际上是从mn收到的Integer

It's the same principle as List list = new ArrayList(); 它与List list = new ArrayList();原理相同List list = new ArrayList();

The list here is actually an ArrayList , but only referenced using the List interface. 这里的列表实际上是一个ArrayList ,但只使用List接口引用。 Similarly, even though n is a Node , it's implementation is a MyNode which only accepts Integer . 同样,即使n是一个Node ,它的实现也是一个只接受IntegerMyNode That's why you can put a String in setData() 这就是你可以在setData()放置一个String的原因

After reading the edit example 阅读编辑示例后

The page says that a bridge method is created as follows : 该页面表示如下创建桥接方法:

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

    // ...
}

The bridge method does the following 桥接方法执行以下操作

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

Here it is trying to cast data which is the String "Hello" into an Integer . 这里它试图将String “Hello”的数据转换为Integer Hence the error is thrown. 因此抛出了错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM