[英]ArrayList with generics declaration in Java
以下代碼給出了行l.add
的錯誤
List<? extends Number> l = new ArrayList<Integer>();
l.add(1);
並強迫我把它寫成l.add(1, null);
為什么會這樣?
對於變量l
的通配符,編譯器不知道(或關心) Number
參數的哪個子類(或Number
本身)。 它可以是ArrayList<Double>
或ArrayList<BigInteger>
。 它不能保證什么傳遞中的類型安全add
,因為類型擦除時,JVM無法捕捉類型不匹配任。 因此,編譯器通過禁止此類調用add
來保留類型安全,除非該值為null
,可以是任何類型。
要add
到編譯,您必須將l
聲明為:
List<? super Integer> l = new ArrayList<Integer>();
或者您可以刪除通配符:
List<Integer> l = new ArrayList<Integer>();
它一定要是:
List<? super Integer> l = new ArrayList<Integer>();
l.add(1);
注意<? super Integer>
<? super Integer>
聲明。 它被稱為上限通配符 。
它有什么作用?
它將ArrayList
元素的Runtime類型限制為Integer
的超類之一,例如Integer
, Number
或Object
,這意味着您可以將l
分配給:
new ArrayList<Integer>
new ArrayList<Number>
new ArrayList<Object>
在這三種情況下,語句l.add(1)
完全有效,因此沒有編譯時錯誤。
更多信息:
List<? extends Number>
List<? extends Number>
與List<T extends Number>
。 對於List<T extends Number>
, l.add(new Integer(1))
將起作用。
如果使用? extends Number然后你不能引用類型,但你仍然可以使用((List<Integer>)list).add((int) s)
。
你可以寫:
List<? extends Number> l = new ArrayList<>();
((List<Integer>)l).add((int) 1);
代替。
泛型是關於“類型安全和不變性”的。
有2個與您的問題相關的方案。
您的第一個陳述是關於持有參考。
List<? extends Number> l = new ArrayList<Integer>();
這里,編譯器確保l
可以保存擴展Number的對象的Type List的引用。 例如: List<Integer>
, List<BigInteger>
, List<Double>
等。
在我們的例子中,它是List<Integer>
。 到現在為止還挺好。 現在我允許添加到l
? 用戶可能想要添加任何內容(擴展Number
,例如Double
, BigInteger
或Integer
)。 這會打破類型安全。 因此,為了克服這個問題,編譯器確保不允許用戶添加到這種類型的引用。
這種引用主要用於我們只迭代一種列表時。
例如:
// Here numbers can take reference of List type of objects which extends Number.
public void printValue(List<? extends Number> numbers){
// Iterate through all the numbers.
for(Number number: numbers){
System.out.println(number.intValue());
}
}
現在進入本討論的第二個場景,即修改列表。 為此,編譯器希望用戶在進行修改之前確保類型安全。
這可以通過<? super T>
<? super T>
。
List<? super Number> n = new ArrayList<Number>();
這里編譯器允許將Number的子類型添加到n
。
BigInteger b = new BigInteger("4");
Double d = new Double(2);
n.add(b); // valid
n.add(d); // valid
//Compiler won't allow here.
n.add(new CustomNumber()); // CustomNumber is not a subtype of Number. It addition in "n" is Invalid.
簡單來說, List<? extends Number>
List<? extends Number>
聲明未指定類型的元素列表。 您只需指定元素的類型擴展類Number。 l
可以是List<Integer>
或List<Double>
。
編譯器將允許將列表的元素分配給Number,因為它知道l
中的任何內容是Number或其子類。
但它不允許向列表中添加任何元素,因為變量l
可以包含僅接受整數的List<Integer>
,或者只接受List<Double>
精度的List<Double>
。 列表不接受任何類型的接受。 在某種意義上, List<? extends Number>
List<? extends Number>
是一個只讀列表。
如果你需要l
作為數字列表,也許你將它傳遞給需要List<Number>
,那么你必須將它初始化為ArrayList<Number>()
。
但是如果您始終將Integers與該列表一起使用,則應將其聲明為List<Integer>
並使用ArrayList<Integer>
對其進行初始化。 請記住,Integer是一個最終類,它允許編譯器比使用Numbers更多地優化代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.