2012-07-18 13 views
7

bien, así que Java no permite lo siguiente:Genéricos y comodines: Java le gusta "nueva Foo <Bar<?>>"

Foo<?> hello = new Foo<?>(); 

Esto hace sentido-- después de todo, ¿cuál es el punto de genéricos si estás solo voy a boxear/unbox todo de todos modos?

Lo que es raro, es Java no permite esto:

Foo<Bar<?>> howdy = new Foo<Bar<?>>(); 

Por supuesto, este hecho lleva a cabo más, aunque en algún momento, no habría un yeso para conseguir lo Bar está trabajando. Pero si Java está bien con algunos especificidad, ¿por qué no se permite esto ?:

Foo<? extends Mal> bonjour = new Foo<? extends Mal>(); 

La única razón por la que pido es que estoy fijación a confiar en el "comodín dentro de un parámetro de clase de un constructor ", y seriamente quisiera saber las implicaciones/intenciones detrás de esto.

EDIT: Para aclarar mi pregunta, ¿con qué motivo se permiten/rechazan estas declaraciones? Soy consciente de que "Java no permite comodines en los constructores", pero la pregunta es: ¿por qué toda esta rareza? ¿Por qué no se permiten comodines delimitados si los comodines anidados están bien?

Respuesta

5

En cuanto a la justificación: new Foo<?> probablemente debería escribirse como new Foo<Object>, por lo que la restricción del compilador obliga a escribir el código lo más legible posible. El último ejemplo también podría ser new Foo<Mak>(), ya que no hay nada que pueda hacer en un Foo<? extends Mal> que no puede hacer en un Foo<Mal>.Tenga en cuenta que el inverso no es verdadero: un Foo<Mal> podría aceptar Mal argumentos donde no lo hace un Foo<? extends Mal>.

Por otro lado, es posible que desee un objeto Foo que pueda manejar objetos Bar de cualquier tipo, por lo que Foo<Bar<?>> tiene mucho sentido. Este sería el caso si solo accede a los métodos Bar que no se basan en el argumento de tipo. No hay nada para que el compilador se queje aquí.

+0

Creo que entiendo lo que estás diciendo: si un constructor acepta una clase param 'Mal', la instancia inherentemente acepta cualquier cosa que sea una subclase de' Mal' (aunque una _referencia_ a la instancia no podría apuntar a una genérico con una subclase a menos que se especifique un comodín.) – Philip

+0

Mirando mi comentario más de un año después ... Estoy bastante seguro de que esa es una de las cosas más incomprensibles que he dicho. – Philip

1

Cuando crea una instancia de un tipo parametrizado, debe especificar un tipo. ? y ? extends Mal no son tipos. Bar<?> es un tipo. Puede encontrar más información sobre este page.

Aquí es un ejemplo para su segundo caso:

Bar<Object> bar1 = ...; 
Bar<String> bar2 = ...; 
List<Bar<?>> list = new ArrayList<Bar<?>>(); 
list.add(bar1); 
list.add(bar2); 

Se puede imaginar para almacenar instancias de barras en una lista, pero no es necesario conocer sus parámetros de tipo.

3

La razón sus primer y tercer declaraciones no funcionan es porque de JLS §15.9:

Es un error de compilación si alguno de los argumentos de tipo utilizados en una expresión de creación de la instancia clase son de tipo comodín argumentos (§4.5.1).

En su primera declaración, ? es un tipo de comodín. En su tercera declaración, ? extends Mal es un tipo de comodín.

El motivo por el que su segunda declaración hace es porque Bar<?> no es un tipo de comodín. Bar<?> es del tipo Bar.

¿Qué quiere decir con "comodín dentro de un parámetro de clase de un constructor"?

+0

Bueno, sí, son comodines y no se permiten comodines en esos casos, pero mi pregunta es, ¿por qué? ¿Por qué se tomó esta decisión de diseño? ¿Por qué el tercer bloque de código es menos legítimo que el segundo? – Philip

+0

Con esto me refiero a algo en forma de 'nuevo Foo > ' – Philip

+0

@Phillip El primer y el tercer bloque de códigos son prácticamente lo mismo. Para el primero, el '?' Podría ser reemplazado por 'Object',' Mal', 'SubclassOfMal',' SubSubclassOfMal', etcétera. Para el tercero, el '?' Podría reemplazarse con cualquiera de los anteriores, excepto por 'Object'. Todavía hay un número infinito de tipos reales que podrían coincidir con '?', Y el compilador no puede manejar eso. – Jeffrey

1

new Foo<?> se puede reemplazar de manera equivalente con new Foo<SomeRandomTypeIMadeUp> donde SomeRandomTypeIMadeUp es cualquier tipo que satisfaga el límite de ese parámetro de tipo. La opción más simple es simplemente seleccionar el límite superior de ese parámetro de tipo, p. si es class Foo<T extends X>, entonces new Foo<X> sería suficiente.

Puede preguntar, ¿por qué es que puedo elegir cualquier parámetro de tipo arbitrario, incluso uno que puede no tener absolutamente ninguna conexión con el resto de mi programa? ¿No es eso inseguro? La respuesta es no, porque eso es exactamente lo que significa Foo<?> - el parámetro de tipo puede ser cualquier cosa, y no puede depender de lo que sea. Esto demuestra lo absurdo de lo que estás pidiendo que hagas. Algo creado con new Foo<?> sería completamente inútil, porque no se puede hacer nada con eso que dependa del tipo de parámetro de tipo.

Los tipos con comodines son generalmente útiles. Por ejemplo, puede tener un argumento de tipo List<?> y puede pasarle cualquier tipo de List, y simplemente saca cosas de la lista. Pero en ese caso, no estás creando la lista. La función que creó la lista y se la pasó probablemente tenía algún parámetro de tipo no comodín. En el ámbito de esa función, aún puede poner cosas en la lista y hacer cosas útiles con ella. Si una función fuera a crear un List<?>; esto sería bastante inútil: no puedes poner ningún elemento excepto null en él.

Es por eso que no está permitido hacer new Foo<?>: Es completamente inútil; probablemente estés usando genéricos incorrectamente si quieres usarlo. Y en el caso extremadamente raro en que realmente lo desea, hay un sustituto listo, new Foo<AnyTypeThatSatisfiesTheBounds>.

Foo<Bar<?>> es muy diferente. Bar<?> es un tipo específico. Foo<Bar<?>> no significa que pueda asignarle Foo<Bar<Something>>; más bien, eso es ilegal; los parámetros de tipo Foo deben coincidir si no son comodines. También a diferencia de un comodín, con un List<Bar<?>>, puede poner objetos en él y quitarle objetos.

Cuestiones relacionadas