2011-09-08 141 views
2

在java通用中,我明白通配符是什麼,超級和擴展,但沒有得到爲什麼不允許我添加任何東西,爲什麼允許我在層次結構中添加upto SomeType,但不在層次結構中?java泛型和通配符

class Animal {} 
class Cat extends Animal{} 

下面的方法可以採取動物或動物即貓子的名單,但沒有別的 ,我不允許添加任何東西,如果嘗試添加,停止編譯器我爲什麼?

void addAminal(List<? extends Aminal> aList){ 
     aList.add(new Cat()); // compiler error 
     aList.add(new Animal()); // compiler error 
} 

現在下面的方法可以採取動物或任何超類型動物的任何名單,但動物沒有子類型,我可以在層次結構中添加個動物或物體更低,所以當我嘗試添加對象,編譯器抱怨爲什麼?

void addAnimal(List<? super Animal> aList){ 
    aList.add(new Animal()); // no error 
    aList.add(new Cat());  // no error 
    aList.add(new Object()); // compiler error why ? 
} 

感謝 阿里亞

+1

我建議你看看[Java泛型指南](http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf)和其他有關[協變和反變化](http ://stackoverflow.com/questions/2501023/demonstrate-covariance-and-contravariance-in-java)。 – dm3

+0

我不得不承認這是一個幹讀,但@ dm3鏈接的Java泛型的PDF有寶貴的信息。它面向那些瞭解Java基礎知識但不太瞭解泛型的人。換句話說,從這個問題來看,它是爲你寫的,巴拉特! :-) – corsiKa

+0

參考這裏 - http://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java – IsAs

回答

4

假設你定義一個新的類:

class Tabby extends Cat {} 

然後你做了以下內容:

List<Tabby> aList = new ArrayList<Tabby>(); 
addAnimal(aList); 

毫無疑問,這個名單不應該有一個動物甚至是一個不是虎斑貓的貓,但是如果編譯器沒有fl ag錯誤,那就是你會有的。

原因是hou've指定addAnimal需要列出一些可以擴展Animal的內容,但是這可能會造成嚴重的限制。然而,這將彙編:

void addAnimal(List<Animal> aList){ 
    aList.add(new Cat()); // OK 
    aList.add(new Animal()); // OK 
} 

採用super也將工作,因爲無論CatAnimal的一個實例是Animal任何父類的實例。

+0

感謝您的答覆泰德。我的疑問是List <?延伸Aminal>將是動物或動物亞型的列表,因此它應該完美地發現將動物或亞類動物添加到列表<?擴展Aminal>,因爲我們可以使用列表 l = new ArrayList (); l.add(new Animal()); l.add(new Cat()),這個工作,所以當它是List <?延伸Aminal>爲什麼它不起作用? – Kabeer

+0

它不工作,因爲'List <?擴展動物>'不是可以包含動物或動物亞型的列表。它是Animal的一個子類型的列表,它不會接受任何不屬於該子類型的子類型。 (特別是,它可能不會接受動物,就像我的第一個例子)。只需使用'List '作爲你的方法的正式參數,你就可以走了。 –

0

泛型只允許您添加類型爲(或子類型)的對象作爲類型參數。如果你輸入<? extends Animal>這意味着列表中有一些類型是動物的一個子類。既然您正在嘗試添加貓,您必須確定它確實是貓的列表,而不是狗的列表。
基本上,當你使用通配符時,你將無法將新項目添加到這樣的列表中(注意:我沒有完整的知識,這可能不完全正確,但它看起來像這樣。錯了)

如果你想能夠添加任何動物到列表中,只需使用List<Animal>

+0

感謝您的回覆史蒂文。我知道你在說什麼。我沒有得到的是爲什麼<?擴展動物>不允許我添加任何東西,該列表可能包含動物或動物的子類型,有什麼危害? – Kabeer

+0

它可能不包含「動物或子類型」。它是一個類型的列表(由'?'表示),它是Animal的一個子類。檢查Ted Hopp的例子,在那裏他嘗試使用你的代碼將一個Cat添加到Tabbies列表中,這顯然是不允許的。 – Steven

1

List<? extends Animal>表示List<X>其中XAnimal的未知亞型。

因此它具有

void add(X item); 
X get(int i); 

你不能叫加(貓),因爲我們不知道貓是X的一個亞型由於X不明,唯一的價值,我們知道方法

X的子類型是 null,所以你可以 add(null)但沒有別的。

我們可以做Animal a = list.get(i),因爲該方法返回XXAnimal的子類型。因此,我們可以撥打get(i)並將回報值視爲動物。

相反,List<? super Animal>意味着List<Y>其中Y是一個未知的超級類型Animal。現在我們可以撥打add(cat),因爲Cat是動物的一個亞型,動物是Y的亞型,因此Cat是Y的亞型,而add(Y)接受Cat。另一方面,Animal a = list.get(0)現在不起作用,因爲Animal不是返回類型的超類型Y; Y唯一已知的超類型是Object,所以我們所能做的只是Object o = list.get(0)

0

嗯,當你說ArrayList <?擴展動物>你指定這個列表將包含任何類型的動物或任何從動物繼承的特定類型(如?指特定/確定類型),但有些東西確定。因此,最終,由於泛型使用Eraser概念(它用一個非泛型上限替換程序中的每個泛型),因此該列表應該包含特定類型,但由於(<?extends Animal>)你不知道哪個具體的類型是那個。因此,即使類型是從Animal繼承的,也不允許添加。

但是當你說ArrayList <?超動物「,這意味着數組列表包含來自動物的特定類型,即,其基數或超類型爲動物的物體。因此將動物或動物衍生的任何東西傳入此列表是安全的。列表按這種方式處理,並允許按照上述方式添加對象。因此它有效。

希望它有幫助!