泛型類

爲何要有泛型類

在擁有泛型以前,泛型程序設計是由繼承實現的。好比:arraylist,在擁有泛型以前arraylist其實只維護一個object引用的數組。java

使用繼承的問題在於獲取值時必須強制類型轉換,編譯器也沒法檢查傳入參數類型。c++

因此泛型類的好處在於:使程序擁有更好的安全性和可讀性。數組

定義簡單的泛型類

public class A<T>
{
    private T first;
    private T second;
 
    public A(T first,T second){
        this.first=first;
        this.second=second;
    }
}

類型變量通常使用大寫,且比較短。java庫中,E表明集合類中的元素類型,K和V分別表明表的關鍵字與值得類型。T表明任意類型。安全

泛型類能夠看做是普通類工廠。測試

泛型方法。

能夠在普通類中定義一個泛型方法。this

class A{
    public static <T>  T f(T a){
        return a;
    }
}

類型變量的限定

須要對類型變量加以約束時使用extens,好比:翻譯

public static <T extends Comparable> T min(T[]a)...

此時min方法只能被實現了Comparable接口的類的數組調用。限制多個接口時使用&隔開。設計

泛型代碼和虛擬機

類型擦除

泛型類型會被擦除,替換位限定類型,若是沒有限定類型則使用Object。因此java中不會出現c++中的模板代碼膨脹(每一個模板的實例化會產型不通的類型)code

爲了提高效率,應該將標籤接口放在邊界列表的尾部,由於若是將非標籤接口放在後面。編譯器要在必要時插入強制類型轉換。對象

使用類型擦除實現泛型的最主要動機爲使泛化的客戶端可使用非泛化的類庫,反之亦然,這是遷移兼容性,爲了兼容jdk1.5以前的類庫,而且保證當一個庫轉變爲泛型以後不會影響到依賴於它的代碼和程序.

翻譯泛型表達式

擦除返回類型後,編譯器要插入強制類型轉化。

翻譯泛型方法

類型擦除後會有兩個不一樣的方法,因此編譯器就要生成橋方法。

總結

  • 虛擬機中沒有泛型,只有普通的類和方法。
  • 全部的類型參數都用他們的限定類型替換
  • 橋方法被合成來保持動態
  • 爲保持類型安全性,必要時插入強制類型轉換

約束和侷限性

基本是由類型擦除引發的

  • 不能用基本類型實例化類型參數

類型擦除後 object不能存儲基本類型的值

  • 運行時類型查詢只適用於原始類型

虛擬機中的對象總有一個特定的非泛型類型,所以全部的類型查詢只產生原始類型。

if(a instanceof Pair<T>)//ERROR

只能測試a是不是一個任意類型的pair

  • 不能建立參數化類型的數組

Pair<String>[] table = new Pair<String>[10];//ERROR

可是能夠聲明通配類型的數組而後類型轉換。
Pair<String>[] table = (Pair<String>[])new Pair<?>[10];

可是結果並不安全,推薦使用ArrayList<Pair<String>>

### 類型擦除的補償
可讓泛型類保有一個Class對象,在初始化時傳入一個Class對象,轉而使用動態的isInstance()方法檢測類型代替不可以使用的instanceof.

也可使用class對象.newInstance()建立實例,代替不可用的new關鍵字

相關文章
相關標籤/搜索