Java泛型知識總結

2022-06-08 18:02:30

泛型

前言

在沒有泛型之前,程式設計師必須使用Object編寫適用於多種型別的程式碼。很繁瑣,也不安全。
泛型的引入使Java有了一個很強的型別系統,允許設計者詳細地描述變數和方法的型別要如何變化。
在普通的情況下,實現泛型程式碼很容易。在更高階的情況下,我們的目標是提供讓其他程式設計師可以輕鬆使用的類和方法,這對實現者來說會非常複雜。

為什麼要使用泛型

用泛型編寫的程式碼可以對多種不同物件的型別進行重用。

沒有泛型之前,使用Object(繼承)實現不同型別物件間的匹配。這種方法有兩個弊端

  • 獲取一個值時必須進行強制轉換(繁瑣)
  • 編譯期沒有錯誤檢查(不安全)

因此,泛型提供了一種解決方案:型別引數(type parameter)。 使程式碼更具有可讀性。
編譯器也可以充分利用這個型別資訊。呼叫get的時候不需要強制轉換。編譯器還知道add方法有一個型別為String的型別引數,這比Object型別要安全。現在,編譯器可以檢查,防止你插入錯誤型別的物件。編譯期出現錯誤比執行期出現類的強制轉換異常要好的多。

泛型類

有一個或多個型別變數的類。

例如:定義一個型別變數T,用 <> 括起來,放在類名後邊。泛型類還可以有多個型別變數,<T, U>。
變數型別可以應用於方法的返回值型別以及欄位和區域性變數。

使用具體的型別替換型別變數來範例化反省型別,可以把結果想像成一個普通類。

泛型方法

泛型方法可以定義在普通類中,也可以定義在泛型類中。

注意,泛型變數要放在方法返回值前。

呼叫泛型方法的方式(例子是呼叫靜態方法):

  • ArrAlg.<String>getMiddle(); 注意呼叫格式
  • ArrAlg.getMiddle(); 簡單呼叫

型別變數的限定

場景:某個方法引數為泛型T,在方法體中要呼叫compareTo方法來比較大小,既然使用了泛型,說明該方法可以傳入任何引數物件,那麼如何知道T所屬的類有一個compareTo方法呢?

解決這個問題的方法就是限制T只能是實現了Comparable介面的類。可以通過對變數型別T設定一個限定來實現這一點:public static <T extends Comparable> T min(T[] t)

此時,在呼叫泛型方法min時只能傳遞實現了Comparable介面的型別物件的引數。

語法就是:<T extends BoundingType>,T和限定類可以是類也可以是介面。

一個型別變數或萬用字元可以有多個限定:

  • 型別變數用逗號分隔
    • <T, U extends Comparable>
  • 限定型別用&分隔
    • <T extends Comparable & Serializable>

注意: 可以限定多個介面,類最多隻能限定一個。如果有一個類作為限定,這個類必須是第一個限定。

泛型程式碼和虛擬機器器

無論何時定義一個泛型,都會自動提供一個原始型別(raw type)。這個原始型別就是去掉型別引數後的泛型型別名。對於無限定的變數替換為Object。

原始型別第一個限定型別來替換型別變數,如果沒有給定限定,則替換為Object。例如:

public class Interval<T extends Comparable & Serializable> {
    private T lower;
}
// Comparable為第一個限定型別,所以使用它來替換
public class Interval {
    private Comparable lower;
}

泛型轉換的步驟

  • 對原始方法Pair.getFirst呼叫返回Object型別
  • 將返回的Object型別轉換為Employee型別

泛型轉換規則

  • 虛擬機器器中沒有泛型,只有普通的類和方法
  • 所有的型別引數都會替換為他們的限定型別
  • 會合成橋方法來保持多型
  • 為保持類的安全性,必要時會插入強制型別轉換

@SuppressWarnings("unchecked")

這個註解會關閉程式碼檢查

泛型的限制與侷限性

  • 泛型不能使用基本資料型別
  • 型別比較只適用於原始型別
  • 不能建立泛型陣列

萬用字元

泛型萬用字元搭配集合使用一般在方法的引數中比較常見
方法中的引數是一個集合,集合如果攜帶了萬用字元,要特別注意如下:
1 集合的型別會提升為Object型別。
2 方法中的引數是一個集合,集合如果攜帶了萬用字元,那麼此集合不能進行新增和修改操作 , 可以刪除和獲取
在集合中泛型是不支援多型的,如果為了匹配任意型別,我們就會使用泛型萬用字元了。

<?> 可以表示任意型別

受限萬用字元

對泛型做約束,給泛型指定型別時,只能是某個類的父類別或子類。

  • 下限
    • ? super 型別
  • 上限
    • ? extends 型別

visualgo.net