泛型萬用字元使用指南
學習使用泛型程式設計時更困惑的一個方面是確定何時使用上界萬用字元以及何時使用下界萬用字元,此頁面提供了設計程式碼時要遵循的一些準則。
對於本文的討論,將變數看作提供的兩個功能之一是有幫助的:
- 一個“In”變數
“in”變數向程式碼提供資料,想象一下帶有兩個引數的複製方法:copy(src, dest)
,src
引數提供要複製的資料,因此它是“in”引數。
- 一個“Out”變數
“out”變數儲存資料以供其他地方使用,在複製示例中,copy(src, dest)
,dest
引數接受資料,因此它是“out”引數。
當然,一些變數既用於“in”又用於“out”目的 — 該場景也在指南中解決。
在決定是否使用萬用字元以及適合使用哪種型別的萬用字元時,可以使用“in”和“out”原則,以下列表提供了遵循的準則:
- 使用
extends
關鍵字定義帶有上界萬用字元的“in”變數。 - 使用
super
關鍵字定義帶有下界萬用字元的“out”變數。 - 在可以使用
Object
類中定義的方法訪問“in”變數的情況下,使用無界萬用字元。 - 在程式碼需要作為“in”和“out”變數訪問變數的情況下,不要使用萬用字元。
這些指南不適用於方法的返回型別,應該避免使用萬用字元作為返回型別,因為它強制程式設計師使用程式碼來處理萬用字元。
由List<? extends ...>
定義的列表可以非正式地認為是隻讀的,但這不是一個嚴格的保證,假設你有以下兩個類:
class NaturalNumber {
private int i;
public NaturalNumber(int i) { this.i = i; }
// ...
}
class EvenNumber extends NaturalNumber {
public EvenNumber(int i) { super(i); }
// ...
}
考慮以下程式碼:
List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35)); // compile-time error
因為List<EvenNumber>
是List<? extends NaturalNumber>
的子型別,你可以將le
賦給ln
,但是你不能使用ln
將自然數新增到偶數列表中,以下列表中的操作是可能的:
- 你可以新增
null
。 - 你可以呼叫
clear
。 - 你可以獲取迭代器並呼叫
remove
。 - 你可以捕獲萬用字元並寫入從列表中讀取的元素。
你可以看到List<? extends NaturalNumber>
定義的列表在嚴格意義上不是隻讀的,但你可能會這樣想,因為你無法儲存新元素或更改列表中的現有元素。