java泛型(噁心)

一.術語較多

泛型類型 (泛型)                               :List<E>

泛型方法                                         :static <E> List<E> asList(E[] a)

原始類型(原生態類型)(raw type): List<E> 對應的原始類型就是 List

參數化類型                                     :List<String> 

形式類型參數                                 :List<E>的E

實際類型參數(類型參數的實例)      :List<String> 的 String

type of                                             :<>

通配符                                              :

二.注意

規定:Father是son的父類。

 1.形式類型參數指定爲Father,傳入子類,自動向上轉型。

List<Father> list = new ArrayList<>();
list.add(new Son());

   形式參數指定爲Son,傳入父類,顯示強制向下轉型。

List<Son> list = new ArrayList<>();
list.add((Son) new Father());

2.泛型類型轉換爲原始類型,編譯器對實際類型參數無法檢測了。

List<Father> before = new ArrayList<>();
before.add(new Father());
        
List after = before;
after.add("hello world");

before添加的是對象,將before賦值給原始類型after後,
檢測不到實際類型參數Father的存在,就添加了字符串對象。
這是不安全的操作。

3.List<? extends Father>:只能get 不能add

原因:

不知道具體類型參數是什麼,也就不知道具體泛型類的內部元素是什麼,所以add的值不能保證向下轉型成功。

但是上限是Father類型,返回值用Father來接受一定沒問題。

4.List<? super Father>     :  只能add 不能get

原因:

不知道具體類型參數是什麼,但是指定了最低限度是Father類型,也就是實際List內部存儲的是Father以及Father超類類型。add的時候有一個要求:只能設置Father 以及 Father的子類。因爲一定能保證向上轉型。

但是返回值是不能確定的,如果實際返回的是Father的父類對象,拿Father來接收,會拋出異常。

三.疑惑

看Arraylist源碼看到一處代碼:

E elementData(int index) {
    return (E) elementData[index];
}

 上面類型擦除之後不就變成:

Object elementData(int index) {
    return (Object) elementData[index];
}

 那強轉有什麼意義呢?而且,在下面我們實際使用的時候,是怎麼直接可以賦值給String變量的呢?

實際使用:

ArrayList<String> list = new ArrayList<String>();
list.add("hello");

String s = list.get(0);

解答:

1.編寫(E)的意義:原來這是編譯期時編譯器的類型檢查,在代碼編譯時,編譯器認爲E是真實存在的類型,就好比我們使用時傳入的String類型,所以我們需要進行強轉,但是當按下運行編譯的那一刻,這個E就會被擦出了。

2.如何直接賦值的呢?原來編譯器會對代碼編譯爲字節碼的時候做手腳,會加上檢查類型轉換的字節碼指令

附加:

就拿上面實際使用的例子生成的字節碼:

可以看到紅色框框的checkcast指令,引用了常量表中的String類型。實際對象的類型信息是可以通過對象頭中的class指針獲取。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章