首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 泛型陣列創建完全指南:從擦除陷阱到 Array.newInstance 最佳實踐

     編輯:Java 相關知識

核心問題:無法直接 `new T[]`

因類型擦除,執行期 T 變為 Object,new T[10] 實際為 new Object[10],強轉 (T[]) 會在執行期拋 ClassCastException。

四種嘗試方案對比(源自 Think in Java)

方案一:強轉 Object 陣列 → 編譯警告,執行期崩潰

Generic<Integer>[] arr = (Generic<Integer>[]) new Object[10]; // ClassCastException

方案二:內部用 Object[],取值強轉 → 取單元素可行,取陣列仍崩潰

class Holder<T> {
    private Object[] arr;
    public T get(int i) { return (T) arr[i]; }      // OK
    public T[] toArray() { return (T[]) arr; }      // ClassCastException
}

方案三:內部用 T[] 但建構時強轉 → 同上,rep() 回傳陣列會崩潰

方案四(正解):傳入 Class<T> 型別權杖,用 Array.newInstance

public class ArrayMaker<T> {
    private final Class<T> type;
    public ArrayMaker(Class<T> type) { this.type = type; }

    @SuppressWarnings("unchecked")
    public T[] createArray(int size) {
        return (T[]) Array.newInstance(type, size); // 關鍵:執行期擁有真實型別
    }

    public List<T> createList() { return new ArrayList<>(); }

    public static void main(String[] args) {
        ArrayMaker<Type> am = new ArrayMaker<>(Type.class);
        System.out.println(Arrays.toString(am.createArray(10))); // [type, type, ...]
        System.out.println(am.createList());
    }
}
class Type { @Override public String toString() { return "type"; } }

為何 Array.newInstance 可行?

  • Array.newInstance(Class<?> componentType, int length) 為原生方法,直接在 JVM 層面分配指定元件型別的陣列
  • 繞過擦除,執行期陣列真實型別為 T[],instanceof、getClass() 均正確
  • 仍需 @SuppressWarnings("unchecked") 抑制編譯器未檢查警告

實戰建議

  1. 能用 List 就用 List:List<T> 無陣列擦除問題,API 豐富
  2. 必須用陣列:採用「型別權杖 + Array.newInstance」模式
  3. 框架開發:公共 API 若回傳泛型陣列,文檔註明呼叫端需傳 Class<T>
  4. 反射場景:Method.getGenericReturnType() 可獲取泛型資訊,配合型別權杖實現安全轉換

進階:變長參數與泛型陣列

// 編譯器會為 varargs 隱式建立陣列,同樣受擦除影響
// 安全做法:@SafeVarargs 抑制警告,且方法內不將陣列逸出
@SafeVarargs
public static <T> void safeVarargs(T... args) { ... }
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved