2010-10-26 15 views
5

Ecco un esempio di codice su cui sto lavorando:Java Generics - tipo di ritorno atteso diverso da quello attuale

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

di più scontato ci saranno molte implementazioni concrete diverse di FooMaker Let. Così ho scritto un codice per utilizzare i FooMakers.

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

La seconda riga di codice causa il problema, eclissi mi dice che il codice dovrebbe essere:

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

Sto avendo difficoltà a capire il motivo per cui la dichiarazione Foo come il tipo parametrico in lista deve andare via per rendere corretto il tipo di ritorno.

Qualche idea?

+0

Che farò 'T estende Enum & FooType' essere? T deve essere un enum ed estendere FooType, ma non puoi estendere un enum! –

+0

Con i generici, la parola chiave "extends" viene utilizzata per descrivere le interfacce implementate. FooType è anche un'interfaccia e useresti ancora la parola chiave extends. – Nick

risposta

1

Prova a modificare:

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

Il problema è che se questo è stato permesso:

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

Poi, per estensione, si sarebbero già stati in grado di farla franca con questo così:

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

tali da inficiare il contratto generico della lista restituita.

Per evitare ciò, il compilatore java impone che il tipo di ritorno sia basato su caratteri jolly, ovvero che Foo può essere utilizzato come tipo di ritorno (per estrarre elementi dall'elenco) ma non sarà possibile aggiungere caratteri jolly. tipi di Foo basati sulla tua lista.

+0

Questo in realtà ha perfettamente senso. L'invalidazione è dove tutto viene colpito. Il tuo suggerimento funziona come pubblicizzato. Grazie per l'aiuto. – Nick

0

Perché si dichiara maker come FooMaker<?>. Perché non dovresti dichiararlo come il tipo di AwesomeFooMaker se sai cosa restituisce lo TAwesomeFooMaker specifico?

+0

Modificherò il mio codice su smidge. In realtà non saprò quale FooMaker otterrò. – Nick

+2

Non importa. Dichiarando il parametro type come '?' Stai affermando "Non ho idea di quale tipo tornerà" e il compilatore agisce essenzialmente come se qualsiasi metodo correlato al parametro type fosse ora '?', Anche se è 'List ' Non potresti usare 'FooMaker maker'? –

+0

Il tipo di ritorno dell'interfaccia è List >, con la mia dichiarazione sto dicendo che potrebbe essere di qualsiasi tipo T. Anche se dichiaro FooMaker creatore, ho ancora un errore simile Sto cercando di capire perché il tipo di parametro Foo viene ignorato – Nick

1

usuale:

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

Ho scelto l'altro come risposta alla domanda perché ha incluso un modo per aggirare i miei limiti, ma apprezzo il tuo contributo sul perché non funziona come mi aspettavo. +1 – Nick