首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java 泛型通配符疑問:List 為何不能 add(new Apple())?

     編輯:程式設計綜合問答

現象代碼


List list = new ArrayList(); // 假設 Apple extends Fruit
list.add(new Apple()); // 編譯錯誤!
list.add(new Fruit()); // 編譯錯誤!
list.add(null);        // 唯一允許

核心原理:PECS (Producer Extends, Consumer Super)

  • `` 表示**「Fruit 或其子類的某具體類型」**,但編譯器**不知道具體是哪個子類**。
  • 呼叫 `add(Apple)`:若實際類型是 `List`,加入 `Apple` 會破壞類型安全 → **禁止**。
  • 呼叫 `get()`:返回類型保證是 `Fruit` (或子類) → **安全**,可作為**生產者**讀取。

對比:``


List list2 = new ArrayList(); // Food 是 Fruit 父類
list2.add(new Fruit()); // ✓ 允許
list2.add(new Apple()); // ✓ 允許 (Apple 是 Fruit)
list2.add(new Food());  // ✗ 編譯錯誤 (實際可能是 List)
Fruit f = list2.get(0); // ✗ 返回 Object,需強轉
  • `` 表示**「Fruit 或其父類的某具體類型」**,可安全**寫入** Fruit 及其子類 → **消費者**。
  • 讀取時只保證是 `Object`。

為何書籍說「不能放 Apple」?

書籍正確。**`List` 禁止任何非 null 的 `add` 操作**,因為無法保證運行時類型兼容。你的測試代碼若「能放」,可能是:

  1. 使用了**原始類型** `List list = new ArrayList();` (無泛型檢查,編譯警告但通過)。
  2. 測試環境 JDK 版本極舊 (早期泛型實現有 bug)。
  3. 代碼實際是 `List list = new ArrayList<>(); list.add(new Apple());` (具體類型而非通配符)。

正確使用場景

場景聲明操作
方法只讀取元素`void print(List list)``for(Fruit f: list) ...`
方法只寫入元素`void addFruits(List list)``list.add(new Apple());`
既讀又寫`void process(List list)`無通配符,具體類型

型變總結

List  是 List 的子類型 (協變 Covariant)
List  是 List  的子類型 (逆變 Contravariant)
List  不是 List 的子類型 (不變 Invariant)

Java 泛型**預設不變**,通配符提供受限協變/逆變能力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved