2009-12-03 22 views
15

Me gustaría utilizar una lista genérica, pero el método de inicialización solo arroja un List. El siguiente código funciona bien:Genéricos y el signo de interrogación

List tmpColumnList = aMethodToInitializeTheColumnList(); 
tmpColumnList.add("ANICELITTLECOLUMN"); 

Java acusa que estoy usando un tipo de crudo y que debería paramerize la lista. Así que agregué el signo de interrogación para parametrizar esta lista.

List<?> tmpColumnList = aMethodToInitializeTheColumnList(); 
tmpColumnList.add("ANICELITTLECOLUMN"); 

El problema es: Ahora el método add(..) ya no funciona.
No puedo asegurar que la lista solo contenga String s como aMethodToInitializeTheColumnList() no está implementado en mi código.

¿Cuál es mi error?

Gracias!

+1

¿Cómo funcionó en el primer fragmento? Falta 'new' ... – Abel

+3

Abel: Una llamada de función inicializa la Lista. Lo agregaré para aclarar esto. – guerda

+0

¿Soluciona el método de inicialización? –

Respuesta

26

Del tutorial de genéricos. Gracias a Michael's answer!

No es seguro para añadir objetos arbitrarios a ella sin embargo:

Collection<?> c = new ArrayList<String>(); 
c.add(new Object()); // Compile time error 

Ya que no saben lo que el elemento tipo de c significa, no podemos añadir objetos a la misma . El método add() toma argumentos de tipo E, el tipo de elemento de la colección. Cuando el parámetro de tipo real es?, Significa algún tipo desconocido. Cualquier parámetro que pase para agregar tendría que ser un subtipo de este tipo desconocido. Dado que no sabemos qué tipo es, no podemos pasar . La única excepción es null, que es un miembro de cada tipo.

+4

Perdonen mi ignorancia (no soy Java). ¿Cuál es el propósito de tenerlo si no funciona? – jww

+4

@noloader: el propósito es este: si tiene un parámetro de método de tipo 'Colección ', puede pasar una 'Colección ', una 'Colección ' o una 'Colección ', y dentro del método puede obtener el contenido de esas colecciones como tipo 'Objeto'. No es posible agregar nada a la colección, ya que garantiza que las restricciones de tipo original no se violen. –

17

Probablemente desee utilizar List<String>, así es como se pretende utilizar los genéricos, es decir, agregar información sobre qué tipo de objetos habrá en una colección. Si en realidad va a tener una lista que contiene tipos mixtos (que suele ser un signo de mal diseño) use List<Object>

Para obtener más información sobre el uso de comodines, consulte Generics Tutorial. Pero en realidad solo son relevantes al definir sus propias clases genéricas o métodos con parámetros genéricos.

+0

Gracias por la pista. No puedo asegurar que esta lista solo contenga cadenas. – guerda

+1

En ese caso, podría usar List , o tal vez alguna otra cosa, dependiendo de lo que usted sabe que contendrá la lista (por ejemplo List ) – Fortega

+0

En el Tutorial de Generics existe la solución, vea mi propia respuesta. Consideraré aceptar tu respuesta porque me diste la pista. – guerda

16

Si usa <?>, quiere decir que no va a utilizar el tipo parametrizado en ningún lado. Vaya al tipo específico (en su caso, parece List<String>) o al muy genérico List<Object>

+0

No quiero especificarlo, pero ¿por qué falla el método 'add' normal? – guerda

+2

Bueno, el compilador impone la coherencia semántica. Usted dice que no usará el tipo parametrizado, por lo que no le permite. El método 'add' espera un parámetro cuyo tipo es el parámetro genérico, por lo que no puede usarlo si no especifica uno. – Romain

+3

Porque el tipo es * desconocido *. La compilación no tiene posibilidad de determinar si un 'String' sería apropiado, por lo que no puede agregar' String' a la lista. (En realidad, no está permitido agregar nada a esa lista, excepto 'null'.) – Bombe

2

El List<?> significa que la lista es (o podría ser) tipada, pero el tipo es desconocido **. Así que agregarle algo podría estar mal **, si te encuentras fuera del tipo. Debido a que es desconocido, estás advertido.

Puede usar List<Object>, lo que significa una lista que puede contener cualquier tipo.

+0

No solo estoy advertido, ¡el código falla en tiempo de compilación! – guerda

+0

@furtelwart Cierto, mi redacción fue mal elegida :-). Pero el objetivo de este error en tiempo de compilación es que el compilador señala que el código es potencialmente incorrecto. Por cierto, es el objetivo del subsistema Generics implementado, buscar la seguridad de los códigos en tiempo de compilación y agregar conversiones en tiempo de ejecución ... – KLE

+0

Perdonen mi ignorancia (no soy Java). ¿Cuál es el propósito de tenerlo si no funciona? – jww

8

Otra opción en este caso sería declarar su lista a ser un

List<? super String> 

ya que estos modelos exactamente lo que sabe sobre ella. Usted dice que no sabe exactamente cuáles son sus límites de tipo, pero desde su segunda línea es justo suponer que debe ser capaz de contener cadenas.

Esto compila y en mi opinión, es un poco mejor que un List<Object>, ya que codifica su incertidumbre en cuanto a lo que realmente puede ir en la lista. Básicamente, solo puede agregarle cadenas, pero cuando llame al get(), el elemento devuelto podría ser cualquier cosa (y Java inferirá correctamente que este tipo es Object).

En términos prácticos, la única diferencia entre esto y List<Object> es que esta última permitiría tmpColumnList.add(3) o tmpColumnList.add(new Thread()) etc. Me gusta mucho más la semántica que desarrolla, así como el sentido práctico.

Cuestiones relacionadas