標籤:多態 getx catch 參數 有一個 共用 靜態變數 class類 類型擦除
1 意義
泛型程式設計意味著編寫的代碼可以被很多不同類型的對象所重用。
常見應用 : ArrayList
2 K T V E ? object等的含義
類型變數使用大寫形式
E – Element (在集合中使用,因為集合中存放的是元素)
T – Type(Java 類)(需要時還可以用臨近的字母U和S)表示任意類型 S、U、V – 2nd、3rd、4th types
K – Key(鍵)
V – Value(值)
N – Number(數實值型別)
? – 表示不確定的java類型(無限制萬用字元類型)
Object – 是所有類的根類,任何類的對象都可以設定給該Object引用變數,使用的時候可能需要類型強制轉換,但是用使用了泛型T、E等這些標識符後,在實際用之前類型就已經確定了,不需要再進行類型強制轉換。
3 泛型方法
public static <T> T getXXX(){
}
類型變數放在修飾符的後面,傳回型別的前面
變數類型的限定
<T extends Comparable> T
一個類型變數或萬用字元可以有多個限定
T extends Comparable & Serializable
限定類型用&分隔,逗號用來分隔類型變數
在Java的繼承中,可以根據需要擁有的多個介面超類型,但限定中至多有一個類,如果用一個類作為限定,它必須是限定列表中的第一個。
4 泛型代碼和虛擬機器
Java中的泛型基本上都是在編譯器這個層次來實現的。
在產生的Java位元組代碼中是不包含泛型中的類型資訊的。
使用泛型的時候加上的型別參數,會被編譯器在編譯的時候去掉。 其實編譯器通過Code sharing方式為每個泛型型別建立唯一的位元組碼錶示,並且將該泛型型別的執行個體都映射到這個唯一的位元組碼錶示上。將多種泛型類形執行個體映射到唯一的位元組碼錶示是通過類型擦除(type erasue)實現的。
無論何時定義一個泛型型別,都自動提供一個相應的原始類型(raw type)。原始類型的名字就是刪除型別參數後的泛型型別名。擦除(erased)類型變數,並替換為限定類型(無限定的變數用Object)
4.1
類型擦除
類型擦除指的是通過型別參數合并,將泛型型別執行個體關聯到同一份位元組碼上。編譯器只為泛型型別產生一份位元組碼,並將其執行個體關聯到這份位元組碼上。類型擦除的關鍵在於從泛型型別中清除型別參數的相關資訊,並且再必要的時候添加類型檢查和類型轉換的方法。 類型擦除可以簡單的理解為將泛型java代碼轉換為普通java代碼,只不過編譯器更直接點,將泛型java代碼直接轉換成普通java位元組碼。
類型擦除的主要過程如下:
1.將所有的泛型參數用其最左邊界(最頂級的父類型)類型替換。
2.移除所有的型別參數。
PS:
1.虛擬機器中沒有泛型,只有普通類和普通方法,所有泛型類的型別參數在編譯時間都會被擦除,泛型類並沒有自己專屬的Class類對象。比如並不存在List<String>.class或是List<Integer>.class,而只有List.class。
2.建立泛型對象時請指明類型,讓編譯器儘早的做參數檢查(Effective Java,第23條:請不要在新代碼中使用原生態類型)
3.不要忽略編譯器的警告資訊,那意味著潛在的ClassCastException等著你。
4.靜態變數是被泛型類的所有執行個體所共用的。對於聲明為MyClass<T>的類,訪問其中的靜態變數的方法仍然是 MyClass.myStaticVar。不管是通過new MyClass<String>還是new MyClass<Integer>建立的對象,都是共用一個靜態變數。
5.泛型的型別參數不能用在Java異常處理的catch語句中。因為異常處理是由JVM在運行時刻來進行的。由於類型資訊被擦除,JVM是無法區分兩個異常類型MyException<String>和MyException<Integer>的。對於JVM來說,它們都是 MyException類型的。也就無法執行與異常對應的catch語句。
5 泛型轉換
Java虛擬機器中沒有泛型,只有普通的類和方法
所有的型別參數都用它們的限定類型替換
橋方法被合成來保持多態
為保持型別安全,必要時插入強制類型轉換
6 約束與局限性
- 不能用基本類型執行個體化型別參數
- 運行時類型查詢只適用於原始類型
- 不能建立參數化型別的數組
- Varargs警告
- 不能執行個體化類型變數
- 泛型類的靜態上下文中類型變數無效
- 不能拋出或捕獲泛型類的執行個體
- 注意擦除後的衝突
7 萬用字元類型7.1 <? extends T>
表示類型的上界,表示參數化型別的可能是T 或是 T的子類
7.2 <? super T >
表示類型下界(Java Core中叫超類型限定),表示參數化型別是此類型的超類型(父類型),直至Object
帶有超類型限定的萬用字元可以向泛型對象寫入,帶有子類型限定的萬用字元可以從泛型對象讀取。
7.3 無限定萬用字元 <?>
ps:
如果要從集合中讀取類型T的資料,並且不能寫入,可以使用 ? extends 萬用字元;(Producer Extends)
如果要從集合中寫入類型T的資料,並且不需要讀取,可以使用 ? super 萬用字元;(Consumer Super)
如果既要存又要取,那麼就不要使用任何萬用字元。
Java基礎文法<十二> 泛型程式設計