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

為什么這段代碼會在n.setData("Hello");拋出異常n.setData("Hello"); 實際上它應該在Integer x = mn.data;拋出異常Integer x = mn.data;

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

因為您正在嘗試將String值設置為Integer變量。

您已經通過調用為Node定義了類型T

MyNode mn = new MyNode(5);

Integer類型。 通過調用n.setData("Hello"); 您正在嘗試為Integer字段傳遞String變量。 節點n僅僅是Integer類型節點mn的參考。

我認為教程中有一個小錯誤:他們應該說錯誤是在n.setData("Hello");n.setData("Hello");

那是因為當你調用n.setData("Hello"); MyNode調用bridge方法: n.setData(Object object) ,否則會產生編譯時錯誤。

但是橋接方法看起來像這樣:

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

您會看到網橋嘗試使用對data setData(Integer anInt)來調用setData(Integer anInt) 此演員表失敗,因為您提供了一個String

在這個例子中有趣的是,使用@Override注釋時沒有編譯時錯誤,即使您在技術上沒有覆蓋,但編譯器稍后會覆蓋。 注釋在這里非常有用,以告知將在MyNode上調用setData(Object object)而不是在Node上調用。 這解釋了為什么您沒有看到任何System.out消息。

因為n的類型實際上是從mn收到的Integer

它與List list = new ArrayList();原理相同List list = new ArrayList();

這里的列表實際上是一個ArrayList ,但只使用List接口引用。 同樣,即使n是一個Node ,它的實現也是一個只接受IntegerMyNode 這就是你可以在setData()放置一個String的原因

閱讀編輯示例后

該頁面表示如下創建橋接方法:

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 因此拋出了錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM