簡體   English   中英

ArrayList,帶有Java中的泛型聲明

[英]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的超類之一,例如IntegerNumberObject ,這意味着您可以將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個與您的問題相關的方案。

  1. 持有參考類型。
  2. 修改該引用的內容。

您的第一個陳述是關於持有參考。

List<? extends Number> l = new ArrayList<Integer>();

這里,編譯器確保l可以保存擴展Number的對象的Type List的引用。 例如: List<Integer>List<BigInteger>List<Double>等。

在我們的例子中,它是List<Integer> 到現在為止還挺好。 現在我允許添加到l 用戶可能想要添加任何內容(擴展Number ,例如DoubleBigIntegerInteger )。 這會打破類型安全。 因此,為了克服這個問題,編譯器確保不允許用戶添加到這種類型的引用。

這種引用主要用於我們只迭代一種列表時。

例如:

// 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM