10 分鐘閱讀

Java-泛型

多重型態參數

在 Java 中,泛型(Generics)讓我們可以將「型態」延後到使用時才指定,讓程式更具彈性與可重用性。

舉例來說,你可以建立一個通用的 Example<K, V> 類別,用來表示一個 key 對應一個 value

class Example<K, V>{
}

//人對應一個名子(字串)
Example<String, Person> ex1 = new Example<String, Person>(); 

//區域對應一個數字
Example<Integer, Region> ex2 = new Example<Integer, Region>();

泛型參數的使用範圍

有兩個地方你無法在類別裡面使用泛型參數

  1. 不能用在靜態變數上
  2. 泛型類別的型別參數(例如 T)不能直接用在靜態方法中,不論是方法的參數還是回傳值,因為靜態方法不屬於任何具體型別的物件

錯誤範例

class Gen<T>{
    static T value;
    public static void test1(T v1){
    }
    public static T test2(){
    }
}

泛型的靜態變數

即使你使用不同的型別來建立泛型類別實例,這些實例共用同一個靜態變數。因為靜態變數是類別層級的,而不是泛型實例化後各自擁有的。

方法自帶的泛型

class Box<T> {
    public static <U> U echo(U value) {
        return value;
    }
}

這裡的 <U> 是屬於這個方法本身的泛型參數,與類別的 T 無關,因此合法、可編譯

小結

錯誤場景 編譯結果
static T someVar; 編譯錯誤
public static T method() 編譯錯誤
public static void method(T t) 編譯錯誤
public static <U> U method(U u) 合法

Java 的泛型(Generics)只能使用參考型別(Reference Type),不能用原始型別(Primitive Type)

  • 原始型別(primitive types):像 intdoublecharboolean,這些是效率較高的基本資料型別,不是物件。

  • 參考型別(reference types):像 IntegerDoubleCharacterBoolean,這些是物件(classes),包裝了原始型別。

List<int> numbers = new ArrayList<>(); // 錯誤!不能用原始型別 int

List<Integer> numbers = new ArrayList<>(); // 用 Integer(參考型別)包裝 int

這是因為 Java 的泛型設計時,是用「類別」來實作的,所以泛型只能接受 物件型別(即參考型別)

一般方法參數可以用 int

泛型的限制只出現在「泛型參數」中,但一般方法中的參數可以是任何型別

public void printInt(int value) {
    System.out.println(value);
}

Java 有一種自動轉換稱為「裝箱與拆箱(Boxing / Unboxing)

List<Integer> list = new ArrayList<>();
list.add(10); // 自動 boxing: int → Integer
int x = list.get(0); // 自動 unboxing: Integer → int

泛型支援原始型別,可以考慮 Java 8 之後的 IntStreamOptionalInt 或一些特殊的泛型工具(如 Guava 的 PrimitiveSpecialized),或使用泛型+手動處理 boxing/unboxing

標籤:

更新時間: