2010-10-26 8 views
5

Aquí está un ejemplo de un código que estoy trabajando:Java Generics - Esperado tipo de retorno diferente a la real

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

de Supóngase además habrá muchas diferentes implementaciones concretas de FooMaker Let. Así que escribí un código para utilizar los FooMakers.

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

La segunda línea de código hace que el tema, eclipse me dice que el código debe ser:

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

estoy teniendo problemas para entender por qué la declaración de Foo como el tipo parametrizado en la lista tiene que ir de distancia para hacer que el tipo de devolución sea correcto.

¿Alguna idea?

+0

¿Qué 'T extiende Enum & FooType' ser? T tiene que ser una enumeración y extender FooType, ¡pero no se puede extender una enumeración! –

+0

Con genéricos, la palabra clave "extends" se usa para describir las interfaces implementadas. FooType también es una interfaz y aún usaría la palabra clave extends. – Nick

Respuesta

1

probar este lugar:

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

El problema es que si esto se ha permitido:

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

Entonces, por extensión, que habría sido capaz de salirse con la suya también:

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

Lo que invalidaría el contrato genérico de la lista devuelta.

Para evitar esto, el compilador java obliga al tipo de retorno a estar basado en comodines, lo que significa que Foo puede usarse como un tipo de retorno (para sacar elementos de la lista) pero no podrá agregar caracteres comodín. tipos Foo basados ​​en su lista.

+0

Eso tiene mucho sentido en realidad. La invalidación es donde todo se vuelve loco. Su sugerencia funciona como se anuncia. Gracias por la ayuda. – Nick

0

Porque declara maker como FooMaker<?>. ¿Por qué no lo declararía como el tipo de AwesomeFooMaker si sabe qué datos específicos TAwesomeFooMaker devuelve?

+0

Voy a editar mi código un smidge. De hecho, no sabré qué FooMaker obtendré. – Nick

+2

Realmente no importa. Al declarar el parámetro type como '?' Usted está diciendo "No tengo idea de qué tipo volverá esto 'y el compilador esencialmente actúa como si cualquier método relacionado con el parámetro type ahora es'? ', Incluso si es' List ' ¿No podría usar 'FooMaker maker'? –

+0

El tipo de devolución de la interfaz es List >, con mi declaración estoy diciendo que podría ser cualquier tipo T. Incluso si declaro FooMaker fabricante, sigo recibiendo un error similar. Estoy tratando de entender por qué se está ignorando el tipo parametrizado de Foo. – Nick

1

usual:

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

Elegí al otro tipo como respuesta a la pregunta porque incluía una forma de evitar mis limitaciones, pero aprecio su aporte sobre por qué no funciona como esperaba. +1 – Nick