![](/img/trans.png)
[英]Java Generics WildCard - How can I use generic with Lambda here?
[英]Can I use generics wildcard in List declaration?
考慮以下代碼:
class Super {}
class Sub extends Super {}
class Test {
public static void main(String[] args) {
List<? extends Super> list = new ArrayList<Sub>(); //1
list.add(new Sub()); //2
}
}
第1行編譯成功,但第2行編譯失敗:
The method add(capture#2-of ? extends Super) in the type List<capture#2-of ? extends Super> is not applicable for the arguments (Sub)
我的問題是:
1)為什么第1行成功編譯?
2)第1行是聲明列表(或其他集合)的一種良好做法嗎?
3)為什么在第1行中將list聲明為Sub類型后,第2行為什么編譯失敗?
4)Eclipse的自動完成功能說,列表中現在僅允許“ null”元素。 為什么?
非常感謝!
1)為什么第1行成功編譯?
第一行進行編譯,因為List<Sub>
是List<? extends Super>
子類List<? extends Super>
List<? extends Super>
,並且只有在List不允許您向其添加任何新成員的情況下才可以。
?
意味着您並不完全知道它是List<Sub>
或List<Sub1>
,因此允許將新元素添加到列表中是不安全的,因此也不允許這樣做。
2)第1行是聲明列表(或其他集合)的一種良好做法嗎?
如果您已經知道它將成為List<Sub>
那么我找不到任何用處,但是當您將List傳遞給其他類(如Utilities)時,會使用通配符。
3)為什么在第1行中將list聲明為Sub類型后,第2行為什么編譯失敗?
因為正如我已經解釋的那樣,當您不知道確切類型時,將任何元素添加到列表都是不安全的。
4)Eclipse的自動完成功能說,列表中現在僅允許“ null”元素。 為什么?
因為null
是每種引用類型,所以這就是為什么您可以為任何對象分配null
值的原因。
使用泛型時,請務必記住Josh Bloch的PECS(生產者擴展消費者超級用戶)規則
好的參考文獻:
如第1行所示,捕獲聲明在方法參數中很有用。 請參見Collection.addAll(Collection<? extends E>)
。 如果您需要帶有擴展Super
的列表,只需使用List<Super>
。
您已將list
聲明為,可以將其分配給Super
類的任何子類型。 因此,分配一個Sub
type列表就可以了,Compiler允許進行編譯。 但這並不意味着您可以在其中添加特定的對象類型。
<? extends Super>
<? extends Super>
並非意味着,您可以添加Super的任何子類型。 這意味着,您可以為其分配任何子類型集合。
1)為什么第1行成功編譯?
您基本上將列表定義為包含擴展(或為Super
)的任何類型的元素,即,編譯器知道該列表中的每個元素至少應具有Super
的屬性。
由於Sub
是Super
的子類,因此任何僅包含Sub
元素的列表也滿足所有元素都是Super
實例的要求, List<? extends Super> list = new ArrayList<Sub>();
List<? extends Super> list = new ArrayList<Sub>();
是正確的。
2)第1行是聲明列表(或其他集合)的一種良好做法嗎?
作為取決於個人風格的局部變量,恕我直言。 以這種方式聲明參數(或實例/靜態變量)時,通常不僅是好的樣式,而且也是必需的。
考慮一種迭代數字集合並返回總和的方法。 您可以將參數聲明為Collection<Number>
但是如果沒有討厭的轉換,就無法傳遞Collection<Integer>
。 如果參數聲明為Collection<? extends Number>
Collection<? extends Number>
您可以傳遞Collection<Integer>
。
3)為什么在第1行中將list聲明為Sub類型后,第2行為什么編譯失敗?
原因是編譯器不知道列表中元素的確切類型。 是Super
列表還是Sub
列表?
以List<? extends Number> list
為例 List<? extends Number> list
。 您不知道您是否具有List<Number>
, List<Double>
或List<Integer>
,因此無法確定list.add( new Integer(1) );
會沒事的。 編譯器就是這樣看的。
4)Eclipse的自動完成功能說,列表中現在僅允許“ null”元素。 為什么?
我不得不在這里猜測,但是將null
添加到列表中就可以了,因為無論實際列表聲明的是哪種類型,您都可以始終將null
轉換為該類型。
1)為什么第1行成功編譯?
您將list
聲明為“源自Super
的事物的列表”。 您為其分配一個Sub
列表。 Sub
是“源自Super
東西”。
2)第1行是聲明列表(或其他集合)的一種良好做法嗎?
不可以。通配符用於功能參數。 局部變量應在其泛型參數中盡可能具體,以避免出現您所面臨的問題。
3)為什么在第1行中將list聲明為Sub類型后,第2行為什么編譯失敗?
謬論。 list
被聲明為具有“源自Super
元素”的元素,而不是您聲稱的Sub
。 而且您不能將Sub
添加到列表中,因為“東西”可能不是Sub
; 它可能是Sub2
,並且添加等同於此非法分配:
class Super {}
class Sub extends Super {}
class Sub2 extends Super {}
Sub2 s = new Sub();
此處的主要誤解似乎是您認為通配符會在賦值時被替換。 不是。 它仍然是通配符,並且僅進行兼容性檢查。
4)Eclipse的自動完成功能說,列表中現在僅允許“ null”元素。 為什么?
null
是唯一具有任何可能引用類型的值,因此無論通配符代表什么,都與列表兼容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.