我有以下類:另一個Java泛型的問題
interface Able{/* ... */}
class A implements Able{/* ... */}
,我有
Map<String,? extends Able> as;
as = new HashMap<String, A>();
爲什麼下面導致錯誤:
as.put("a", new A());
任何想法?
我有以下類:另一個Java泛型的問題
interface Able{/* ... */}
class A implements Able{/* ... */}
,我有
Map<String,? extends Able> as;
as = new HashMap<String, A>();
爲什麼下面導致錯誤:
as.put("a", new A());
任何想法?
對java泛型的引用很好(jdk site)。
確實@Oli_Charlesworth給出了一個很好的答案,但也許這一個會更完整。
在Collection<? extends Able>
中,您不能插入任何正確的東西。
如果你有
class A implements Able {...}
和
class B implement Able {...}
然後,Collection<? extends Able>
是一個超級型兩種:
Collection<A>
Collection<B>
因此它是合法的,寫這樣
一些聲明//Code snippet 01
Collection< ? extends Able > list;
Collection<A> listA;
Collection<B> listB;
list = listA;
list = listB;
這確實是通配符號Collection<? extends Able>
存在的原因。
但是,在這裏事情變得更有趣:
在Collection<A>
只能插入對象是A
(包括子類)。 Collection<B>
也一樣。在這兩個你不能添加的東西,只是Able
。例如:
//Code snippet 02
listA.add(new A()); //valid at compile-time
listA.add(new B()); //not valid at compile-time
listB.add(new B()); //valid at compile-time
listB.add(new A()); //not valid at compile-time
因此,如果組我們在code snippets 01 & 02
看見,你就會明白,這是絕對不可能的編譯器接受像聲明:
Collection< ? extends Able > list;
list.add(new A()); //not allowed, will work only if list is List<A>
list.add(new B()); //not allowed, will work only if list is List<B>
所以,是的,超類型Collection< ? extends Able >
不接受添加任何內容。更通用的類型提供了子類型的功能交集,因此,子類型的功能更少。在這裏,我們失去了添加A
對象和B
對象的能力。這些功能將在隨後的層次結構發生......它甚至意味着我們不能在超類中添加任何東西Collection< ? extends Able >
附記:
另外,還要注意在Collection<Able>
你可以添加任何你希望是這樣的:
Collection<Able> list;
list.add(new A()); //valid
list.add(new B()); //valid
但是,Collection<Able>
不是Collection<A>
和Collection<B>
一個超類。與任何繼承關係一樣,這意味着子類可以做任何超類可以做的事情,因爲繼承是專業化的。所以,這意味着我們可以將A對象和B對象添加到Collection<A>
和Collection<B>
的兩個子類,事實並非如此。所以,因爲它不是一個超你不能有:
Collection<Able> list;
Collection<A> listA;
Collection<B> listB;
list = listA; //not valid because there is no inheritance hierarchy
list = listB; //not valid because there is no inheritance hierarchy
注意繼承是hyperonimic關係(泛化/特化)和集合定義meronimic關係(容器/ containee)。將兩者正式結合起來讓人頭痛,儘管人類模糊的生物很容易使用它,例如法語形容詞:synecdocque。 :)
您的答案不僅僅是好的,爲什麼我不能將A的實例添加到集合<?擴展Able>,儘管A實際上是Able類型的...... 這裏的類型un-safety在哪裏? Thnx :) – elmorabea
你可以這樣做,如果一個集合<?擴展Able>將是一個集合,但事實並非如此。那點。它可能是,但它可能不是,所以這是不安全的。 – Snicolas
從http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html:
There is, as usual, a price to be paid for the flexibility of using wildcards. That price is that it is now illegal to write into [a wildcard-based container]. For instance, this is not allowed:
public void addRectangle(List<? extends Shape> shapes) { shapes.add(0, new Rectangle()); // Compile-time error! }
You should be able to figure out why the code above is disallowed. The type of the second parameter to
shapes.add()
is? extends Shape
-- an unknown subtype ofShape
. Since we don't know what type it is, we don't know if it is a supertype ofRectangle
; it might or might not be such a supertype, so it isn't safe to pass aRectangle
there.
您無法插入任何類型的任何對象集合中使用通配符聲明「?」
一旦你定義一個集合作爲列表只能插入「空」
,編譯器無法知道它的安全添加SubAble。
如果Collection<SubSubAble>
已被分配給Collection<Able>
會怎麼樣?這將是一個有效的任務,但添加一個SubAble會污染該集合。
「如果收藏已分配給SubAble,該怎麼辦?」那是什麼意思? –
對不起,需要將它們標記爲代碼段,否則仿製零件不會顯示 – fmucar
Map<String,? extends Able> as;
意味着 「任何地圖,具有字符串鍵,和值是的能子類型」。因此,舉例來說,你可以做到以下幾點:
Map<String,? extends Able> as = new HashMap<String, SubSubAble>();
現在讓我們來看看下面這個例子:
Map<String,? extends Able> as = new HashMap<String, SubSubAble>();
as.put("key", new A());
如果它是正確的,你會完成其HashMap中的內容{「鑰匙」,新的A()} - 這是類型錯誤!
Collection<?>
是超類型的各種收集。它不是a集合可以容納任何類型。至少這是我對整個概念的誤解。
我們可以用它,我們不關心泛型類型,就像這個例子:
public static void print(Collection<?> aCollection) {
for (Object o:aCollection) {
System.out.println(o);
}
}
如果我們選擇,而不是簽名:
public static void print(Collection<Object> aCollection)
我們會我們只限於Collection<Object>
類型的集合 - 換句話說,這種方法不會接受Collection<String>
類型的值。
所以一個Collection<?>
類型不,可以採取任何類型的集合。它只需要未知類型。由於我們不知道該類型(它的未知;)),所以我們永遠不能添加一個值,因爲java中的類型不是未知類型的子類。
如果我們添加邊界(如<? extends Able>
),類型爲仍然未知。
您正在尋找地圖聲明,其值全都實現了Able
接口。正確的聲明很簡單:
Map<String, Able> map;
假設我們有兩種類型A
和B
子類化Able
和兩個附加的地圖
Map<String, A> aMap;
Map<String, B> bMap;
和希望,方法返回的任何地圖,其值實現Able
接口:然後我們使用通配符:
public Map<String, ? extends Able> createAorBMap(boolean flag) {
return flag ? aMap: bMap;
}
(再次帶有約束,我們不能將新的鍵/值對添加到由此方法返回的映射)。
一個好辦法理解這個問題是讀什麼通配符的意思是:「一個地圖一種類型的擴展能的String類型的密鑰和值」
Map<String,? extends Able> as;
不允許添加操作的原因是因爲他們「打開了大門」在集合中引入了不同的類型,這與打字系統有衝突。 例如
class UnAble implements Able;
Map<String,UnAble> unableMap = new HashMap<String,UnAble>();
Map<String,? extends Able> ableMap = unableMap;
ableMap.put("wontwork",new A()); // type mismatch: insert an A-type into an Unable map
正確的使用通配符建設將是:
Result processAble(Map<String,? extends Able>) { ... read records & do something ... }
Map<String,A> ableMap = new HashMap<String,A>;
ableMap.put("willwork",new A());
processAble(as);
processAble(unableMap); // from the definition above
什麼錯誤是什麼呢? – Bohemian