2010-10-26 52 views
5

這裏不同的預期返回類型的一些代碼我工作的一個例子:Java泛型 - 比實際

public interface FooMaker<T extends Enum<T> & FooType> 
{ 
     public List<Foo<T>> getFoos(String bar); 
} 

讓我們進一步假設會有FooMaker許多不同的具體實現。所以我寫了一些代碼來利用FooMakers。

FooMaker<?> maker = Foos.getRandomMaker(); 
List<Foo<?>> fooList = maker.getFoos("bar"); //error here! 

的第二行代碼導致該問題,日食告訴我的代碼應該是:

FooMaker<?> maker = Foos.getRandomMaker(); 
List<?> fooList = maker.getFoos("bar"); 

我無法理解爲什麼富的聲明中列出的參數化類型已去爲了使返回類型正確。

任何想法?

+0

'T擴展Enum &FooType'是什麼? T必須是枚舉並擴展FooType,但是不能擴展枚舉! – 2010-10-26 13:37:19

+0

使用泛型時,關鍵字「extends」用於描述實現的接口。 FooType也是一個接口,你仍然可以使用extends關鍵字。 – Nick 2010-10-26 15:01:32

回答

1

試試這個:

List<? extends Foo<? extends Enum<?>>> fooList = maker.getFoos("bar"); 

的問題是,如果已被允許:

List<Foo<?>> fooList = maker.getFoos("bar"); 

然後推而廣之,你會一直也能夠脫身:

Foo<?> foo1 = new Foo<String>(); 
Foo<?> foo2 = new Foo<Integer>(); 
fooList.add(foo1); 
fooList.add(foo2); 

這將使返回列表的通用合同無效。

爲了避免這種情況,java編譯器強制返回類型是基於通配符的,這意味着Foo可以用作返回類型(將元素從列表中拉出),但是您將無法添加通配符 - 基於Foo的類型到您的列表。

+0

這實際上是非常有意義的,失效是所有事情都會發生重大變化的地方,您的建議可以像廣告中那樣工作。 – Nick 2010-10-26 15:08:28

0

因爲您聲明makerFooMaker<?>。如果你知道什麼具體的TAwesomeFooMaker返回,你爲什麼不宣稱它是AwesomeFooMaker的類型?

+0

我會編輯我的代碼smidge。我其實不知道我會得到哪個FooMaker。 – Nick 2010-10-26 12:57:19

+2

這並不重要。通過將類型參數聲明爲'''''''''''''''''''''''''''''''''''''''''''''我不知道會返回什麼樣的類型,編譯器本質上就好像任何與類型參數相關的方法現在都是'?',即使它是'List ' 。你不能使用'FooMaker'?extends FooType> maker'? – 2010-10-26 13:01:37

+0

接口的返回類型是List >,我的聲明我說它可以是任何類型T.即使我聲明FooMaker <?extends FooType>我還是得到了一個類似的錯誤,我試圖理解爲什麼Foo參數化類型被忽略 – Nick 2010-10-26 13:11:25

1

平常:

class Bar {} 
class Baz {} 

FooMaker<?> maker = new FooMaker<Bar>(); 
List<Foo<?>> fooList = maker.getFoos("bar"); //error here! 
fooList.add(new Foo<Baz>());     //cock-up here! 
+0

我選擇了另一個人回答這個問題,因爲他包含了解決我的限制的方法,但是我很欣賞你的輸入關於爲什麼它不能按我期望的那樣工作+1 – Nick 2010-10-26 15:09:15