2010-10-26 8 views
5

Oto przykład jakiegoś kodu pracuję nad:Java rodzajowych - Oczekiwany rodzaj powrotu inny niż rzeczywisty

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

Chodźmy dalej zakładać, że będzie wiele różnych konkretne implementacje FooMaker. Napisałem więc kod do wykorzystania FooMakers.

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

Druga linia kodu powoduje problem, zaćmienie mówi mi, że kod powinien być:

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

mam problemy ze zrozumieniem, dlaczego deklaracja Foo jako sparametryzowane typu w liście musi odejść z dala, aby typ zwrotu był poprawny.

Wszelkie pomysły?

+0

Co oznacza "T extum Enum & FooType"? T musi być enum i rozszerzyć FooType, ale nie można rozszerzyć enum! –

+0

W przypadku generycznych słów kluczowych słowo "rozszerza" służy do opisu zaimplementowanych interfejsów. FooType jest również interfejsem i nadal używasz słowa kluczowego extends. – Nick

Odpowiedz

1

Spróbuj to zamiast:

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

Problem polega na tym, że jeśli zostało to dozwolone: ​​

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

Następnie za tym idzie, to byłby już można też uciec:

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

Co spowodowałoby unieważnienie ogólnej umowy zwróconej listy.

Aby temu zapobiec, kompilator języka Java zmusza typ zwracany jako oparty na bazie wieloznacznej, co oznacza, że ​​Foo może być używany jako typ zwracany (w celu wyciągania elementów z listy), ale nie będzie można dodawać symboli wieloznacznych. oparte typy Foo na twoją listę.

+0

To naprawdę ma sens, unieważnienie jest tam, gdzie wszystko się psuje, Twoja sugestia działa tak, jak jest reklamowana, dzięki za pomoc. – Nick

0

Ponieważ zgłaszasz maker jako FooMaker<?>. Dlaczego nie zadeklarowałbyś tego jako typu AwesomeFooMaker, jeśli wiesz, co konkretnie zwraca: TAwesomeFooMaker?

+0

Będę edytować mój kod smidge. Właściwie to nie wiem, który FooMaker dostanę. – Nick

+2

To naprawdę nie ma znaczenia. Deklarując parametr type jako "?", Stwierdzasz: "Nie mam pojęcia, jaki typ to zwróci", a kompilator zasadniczo działa tak, jakby każda metoda związana z parametrem typu była teraz "?", Nawet jeśli jest to 'List ' Nie mogłeś użyć 'FooMaker maker'? –

+0

Typ powrotu interfejsu to List >, z moją deklaracją mówię, że może to być dowolny typ T. Nawet jeśli zadeklaruję FooMaker Wciąż mam podobny błąd, próbuję zrozumieć, dlaczego typ sparametryzowany Foo jest ignorowany – Nick

1

zwykle:

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

Wybrałem drugiego faceta jako odpowiadającego na pytanie, ponieważ on zawarł sposób obejścia moich ograniczeń, ale doceniam twój wkład dlaczego nie działa tak jak się spodziewałem +1 – Nick

Powiązane problemy