第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機(jī)立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

關(guān)于在 Java 中創(chuàng)建通用列表數(shù)組的錯誤

關(guān)于在 Java 中創(chuàng)建通用列表數(shù)組的錯誤

慕斯709654 2023-03-23 15:17:32
第一個代碼:List<Integer>[] array = (List<Integer>[]) new Object[size]; 它將給出以下異常:java.lang.ClassCastException: class [Ljava.lang.Object; cannot be cast to class [Ljava.util.List; ([Ljava.lang.Object; and [Ljava.util.List; are in module java.base of loader 'bootstrap')為什么這是錯誤的?我只是按照Effective Java Third Edition Page 132 的方法:第二個代碼:E[] array = (E[]) new Object[size];但是我發(fā)現(xiàn)以下代碼有效第三代碼:List<Integer>[] array = (List<Integer>[]) new List[size];我的問題:為什么第一個代碼是錯誤的,但Effective Java中建議使用第二個代碼?我有什么誤解嗎?例如:為什么下面的代碼運行良好,但第一個代碼是錯誤的?public class Test<E>{    E[] array;    public Test(){        array = (E[]) new Object[10];    }    public E set(E x){        array[0] = x;        System.out.println(array[0]);        return array[0];    }    public static void main(String[] args){        Test<List<Integer>> test = new Test<>();        List<Integer> list = new ArrayList<>();        list.add(1);        test.set(list);    }}誰能解釋為什么第三個代碼是正確的但下面的代碼是錯誤的?第四個代碼:List<Integer>[] array = new List<Integer>[size];
查看完整描述

3 回答

?
飲歌長嘯

TA貢獻(xiàn)1951條經(jīng)驗 獲得超3個贊

第一碼

List<Integer>[] array = (List<Integer>[]) new Object[size];

第一個代碼失敗的原因是因為轉(zhuǎn)換并沒有改變數(shù)組的實際類型,它只是讓編譯器接受代碼是有效的。想象一下,如果您有另一個對底層對象數(shù)組的引用:

final int size = 2;

Object[] objectArr = new Object[size];

List<Integer>[] integerArr = (List<Integer>[]) objectArr; // Does not work

objectArr[0] = "foobar";

List<Integer> i = integerArr[0]; // What would happen ??

上面的代碼編譯得很好,因為你強(qiáng)制編譯器接受它的強(qiáng)制轉(zhuǎn)換。但是您已經(jīng)可以看到為什么強(qiáng)制轉(zhuǎn)換在運行時工作會是一個問題:您最終會得到一個List<Integer>[]現(xiàn)在包含一個 的String,這是沒有意義的。所以語言不允許這樣做。

第二碼

E[] array = (E[]) new Object[size];

Java 中的泛型有點奇怪。由于各種原因,例如向后兼容性,泛型基本上被編譯器擦除并且(大部分)不會出現(xiàn)在編譯代碼中(類型擦除)。相反,它將使用一系列規(guī)則JLS 規(guī)范)來確定代碼中應(yīng)該使用哪種類型。對于基本的 unbouded 泛型;這種類型將是Object。因此,假設(shè)沒有綁定E,編譯器將第二個代碼更改為:

 Object[] array = (Object[]) new Object[size];

因此,由于兩個數(shù)組在擦除后具有完全相同的類型,因此在運行時沒有問題,并且轉(zhuǎn)換基本上是多余的。

值得注意的是,這僅在E不受限制的情況下才有效。例如,這將在運行時失敗并顯示ClassCastException

public static <E extends Number> void genericMethod() {

    final int size = 5;

    E[] e = (E[]) new Object[size];

}

那是因為Ewill be erased to Number,你會遇到和第一個代碼一樣的問題:


Number[] e = (Number[]) new Object[size];

在使用代碼時記住擦除很重要。否則,您可能會遇到代碼行為與您預(yù)期不同的情況。例如,下面的代碼編譯和運行沒有異常:


public static <E> void genericMethod(E e) {

    final int size = 2;

    Object[] objectArr = new Object[size];

    objectArr[0] = "foobar";


    @SuppressWarnings("unchecked")

    E[] integerArr = (E[]) objectArr;

    integerArr[1] = e;


    System.out.println(Arrays.toString(integerArr));

    System.out.println(e.getClass().getName());

    System.out.println(integerArr.getClass().getName());

}


public static void main(String[] args) {

    genericMethod(new Integer(5)); // E is Integer in this case

}

第三碼

List<Integer>[] array = (List<Integer>[]) new ArrayList[size];

與上面的情況類似,第三個代碼將被擦除為以下內(nèi)容:

 List[] array = (List[]) new ArrayList[size];

這沒問題,因為ArrayListList.

第四碼

List<Integer>[] array = new ArrayList<Integer>[size];

以上不會編譯。規(guī)范明確禁止使用具有泛型類型參數(shù)的類型創(chuàng)建數(shù)組:

如果正在初始化的數(shù)組的組件類型不可具體化(第 4.7 節(jié)),則會出現(xiàn)編譯時錯誤。

具有不是無限通配符 ( ?) 的泛型參數(shù)的類型不滿足可具體化的任何條件

當(dāng)且僅當(dāng)滿足以下條件之一時,類型才可具體化:

  • 它指的是非泛型類或接口類型聲明。

  • 它是一種參數(shù)化類型,其中所有類型參數(shù)都是無限通配符(第 4.5.1 節(jié))。

  • 它是原始類型 (§4.8)。

  • 它是原始類型(§4.2)。

  • 它是一種數(shù)組類型 (§10.1),其元素類型是可具體化的。

  • 它是一個嵌套類型,其中對于由“.”分隔的每個類型 T,T 本身是可具體化的。


查看完整回答
反對 回復(fù) 2023-03-23
?
慕萊塢森

TA貢獻(xiàn)1810條經(jīng)驗 獲得超4個贊

雖然我沒有時間深入挖掘JLS,但我可以暗示您要看得更遠(yuǎn)(盡管每次我這樣做,都不是一次愉快的旅行)。

List<Integer>[] array = (List<Integer>[]) new Object[size];

這不會編譯,因為它們是可證明的不同類型(搜索JLS這樣的概念)。簡而言之,編譯器“能夠”看到這些類型不可能與可能被強(qiáng)制轉(zhuǎn)換的類型相同,因此失敗。

另一方面:

array = (E[]) new Object[10];

這些不是可證明的不同類型;編譯器無法判斷這一定會失敗。這里的另一件事是,編譯器不會以任何形式或形狀強(qiáng)制轉(zhuǎn)換為泛型類型,您可以輕松地做這樣的事情(仍然可以編譯):

String s[][][] = new String[1][2][3];
array = (E[]) s; // this will compile, but makes little sense

第二點是類型擦除(又有JLS)。

編譯代碼后,E[]在運行時,是Object[](除非有界限,但這里不是這種情況),很明顯你可以把任何你想要的東西放進(jìn)去。


查看完整回答
反對 回復(fù) 2023-03-23
?
MM們

TA貢獻(xiàn)1886條經(jīng)驗 獲得超2個贊

Java 中數(shù)組和泛型之間的交互是混亂的,因為它們建立在不同的假設(shè)之上。Java 數(shù)組有運行時類型檢查,泛型只有編譯時類型檢查。


Java 通過結(jié)合編譯時和運行時檢查來實現(xiàn)類型安全。轉(zhuǎn)換繞過了大部分編譯時檢查,但仍然有運行時檢查。數(shù)組與其包含的元素類型具有本質(zhì)上相同的類型兼容性規(guī)則。所以:


Object[] a = new String[size]; //ok, but be aware of the potential for an ArrayStoreException

String[] a = new Object[size]; //compile error

String[] a = (String[]) new Object[size]; //runtime error

當(dāng) Sun 決定將泛型添加到 Java 時,他們決定使用泛型的代碼應(yīng)該在現(xiàn)有的 JVM 上運行,因此他們決定通過擦除來實現(xiàn)泛型。泛型類型只存在于編譯時,在運行時它們被普通類型取代。


所以在擦除之前我們有以下語句。


List<Integer>[] array = (List<Integer>[]) new Object[size];

E[] array = (E[]) new Object[size];

List<Integer>[] array = (List<Integer>[]) new List[size];

擦除后我們有。


List[] array = (List[]) new Object[size]; //run time error.

Object[] array = (Object[]) new Object[size]; //no error.

List[] array = (List[]) new List[size]; //no error.

E[] array = (E[]) new Object[size];應(yīng)謹(jǐn)慎使用該結(jié)構(gòu),它違反了 Java 的正常類型模型,如果數(shù)組返回到非泛型上下文,將導(dǎo)致令人困惑的 ClassCastException 。不幸的是,通常沒有更好的選擇,因為類型擦除,泛型類型無法找出它的元素類型并構(gòu)造正確類型的數(shù)組。


查看完整回答
反對 回復(fù) 2023-03-23
  • 3 回答
  • 0 關(guān)注
  • 189 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號