简体   繁体   English

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

[英]Type erasure - Generics - getting ClassCastException not where expected

I was going through this page, just playing with the examples it provides. 我正在浏览此页面,只是在玩它提供的示例。

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

I am using Java 8. 我正在使用Java 8。

According to this tutorial page, the ClassCastException should be thrown at that line 200, but actually it's thrown earlier - at the line marked as 100. Why?! 根据本教程页面, ClassCastException应该在该行200处抛出,但实际上它是在更早的位置-在标记为100的行上抛出的。为什么?! Is the tutorial outdated (not applicable to Java 8)? 教程是否过时(不适用于Java 8)?

Then I asked for all methods of n and I can see the method setData(Object) is there, it's in the Object pointed to by n (this is the so-called bridge method, I assume). 然后我询问了n所有方法,然后可以看到方法setData(Object)在其中,它位于n指向的Object中(我认为这是所谓的桥接方法)。

OK, so why do I get the exception at the line marked as 100? 好的,为什么在标记为100的行上出现异常? Is the compiler transforming my set call to this n.setData((Integer)"Hello"); 编译器是否将我的set调用转换为此n.setData((Integer)"Hello"); If so, seems the tutorial is outdated indeed. 如果是这样,该教程似乎确实过时了。

Could anyone explain this? 有人可以解释吗?

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

OK, well, I figured it out shortly after posting the question here. 好的,好吧,我在这里发布问题后不久就搞清楚了。

Actually the exception thrown at line 200: this is not a fact, the tutorial is just hypothetically mentioning that. 实际上,在第200行抛出了异常:这不是事实,本教程只是假设性地提到了这一点。 Further down in the tutorial, it's clear that the bridge setData method contains a type cast to Integer . 在本教程的setData ,很显然,桥setData方法包含类型转换为Integer的类型。

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

That's what's causing my problem and my confusion. 那就是造成我的问题和困惑的原因。

In any case, this tutorial page seems a bit confusing, but OK, maybe it's just me. 无论如何,本教程页面似乎有点令人困惑,但是可以,也许只是我一个人。

I'm inclined to say that the tutorial is just wrong. 我倾向于说该教程是错误的。 It would be correct if class MyNode were not involved, or if MyNode inherited Node<T> generically, instead of specifying by the type parameter concretely. 如果不涉及MyNode类,或者MyNode继承了Node<T> ,而不是通过type参数具体指定,那将是正确的。 Once MyNode defines a specific value for the type parameter, however, type erasure no longer applies to it. 但是,一旦MyNode为type参数定义了特定的值,类型擦除就不再适用于它。

Yes, the tutorial confuses me a lot. 是的,本教程使我非常困惑。 the comments in the following code doesn't indicate what happens when jvm executes these codes. 以下代码中的注释并不指示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.

It's just assumed that setData in Node was not overridden. 只是假设Node中的setData没有被覆盖。

But actually the bridge method overrides the setData in Node and made it seems like it was overridden by the setData in MyNode. 但是实际上bridge方法会覆盖Node中的setData,并使其似乎被MyNode中的setData覆盖。

And that will be more like a polymorphism is such a case. 那就更像是多态。

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

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