2009-03-24 7 views
102

Estoy usando Eclipse para ayudarme a limpiar algunos códigos para usar los genéricos Java correctamente. La mayoría de las veces hace un excelente trabajo al inferir tipos, pero hay algunos casos donde el tipo inferido tiene que ser lo más genérico posible: Objeto. Pero Eclipse parece darme una opción para elegir entre un tipo de Objeto y un tipo de '?'.¿Cuál es la diferencia entre? y Object en genéricos Java?

Entonces, ¿cuál es la diferencia entre:

HashMap<String, ?> hash1; 

y

HashMap<String, Object> hash2; 
+1

Consulte el tutorial oficial sobre [Comodines] (http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html). Lo explica bien y da un ejemplo de por qué es necesario sobre simplemente usar Object. –

Respuesta

103

Una instancia de HashMap<String, String> partidos Map<String, ?> pero no Map<String, Object>. Digamos que quiere escribir un método que acepta mapas de String s a cualquier cosa: Si usted escribiría

public void foobar(Map<String, Object> ms) { 
    ... 
} 

no se puede suministrar una HashMap<String, String>. Si escribe

public void foobar(Map<String, ?> ms) { 
    ... 
} 

¡funciona!

Una cosa a veces mal entendida en los genéricos de Java es que List<String> no es un subtipo de List<Object>. (Pero String[] es de hecho un subtipo de Object[], esa es una de las razones por las que genéricos y matrices no se combinan bien (los arreglos en Java son covariantes, los genéricos no, son invariantes)).

muestra: Si desea escribir un método que acepta List s de InputStream s y subtipos de InputStream, que iba a escribir

public void foobar(List<? extends InputStream> ms) { 
    ... 
} 

Por cierto: Joshua Bloch's Effective Java es un excelente recurso cuando Me gustaría entender las cosas no tan simples en Java. (Su pregunta anterior también está muy bien cubierta en el libro.)

+1

¿Es esta la forma correcta de usar ResponseEntity en el nivel del controlador para todas las funciones de mi controlador? – Purmarili

3

No puede colocar nada con seguridad en Map<String, ?>, porque no sabe de qué tipo se supone que son los valores.

Puede poner cualquier objeto en Map<String, Object>, porque se sabe que el valor es Object.

+0

"No se puede colocar nada con seguridad en el mapa " False. PUEDES, ese es su propósito. –

+0

Mal, Ben. Hacer esto producirá advertencias "sin marcar". El propósito de los comodines es escribir código que pueda operar en cualquier tipo genérico. – erickson

+1

Ben está equivocado, el único valor que puede poner en una colección del tipo es nulo, mientras que puede poner cualquier cosa en una colección del tipo . –

7

Es fácil de entender si recuerda que Collection<Object> es solo una colección genérica que contiene objetos del tipo Object, pero Collection<?> es un tipo estupendo de todos los tipos de colecciones.

+1

Hay que señalar que esto no es exactamente fácil ;-), pero es correcto. –

23

Otra forma de pensar acerca de este problema es que

HashMap<String, ?> hash1; 

es equivalente a

HashMap<String, ? extends Object> hash1; 

Pareja este conocimiento con el "Obtener y Colocar Principio" en la sección (2.4) desde Java Generics and Collections:

El Obtener y Colocar Principio: utilizar un extiende comodín cuando se consigue solamente valores de una estructura, utilice súper comodín cuando se pone solamente valores en una estructura, y no use un comodín cuando los obtenga y coloque.

y el comodín puede comenzar a tener más sentido, con suerte.

+0

Si "?" te confunde, "? extends Object" probablemente te confunda más. Tal vez. –

+0

Tratando de proporcionar "herramientas de pensamiento" para permitir razonar sobre este tema difícil. Proporcionó información adicional sobre la extensión de comodines. –

+1

Gracias por la información adicional. Aún lo estoy digiriendo. :) – skiphoppy

1

Las respuestas anteriores cubierta covarianza mayoría de los casos, pero perder una cosa: "?"

es inclusivo de "Objeto" en la jerarquía de clases. Se podría decir que String es un tipo de Objeto y Objeto es un tipo de?. No todo coincide con Objeto, pero todo coincide?

int test1(List<?> l) { 
    return l.size(); 
} 

int test2(List<Object> l) { 
    return l.size(); 
} 

List<?> l1 = Lists.newArrayList(); 
List<Object> l2 = Lists.newArrayList(); 
test1(l1); // compiles because any list will work 
test1(l2); // compiles because any list will work 
test2(l1); // fails because a ? might not be an Object 
test2(l2); // compiled because Object matches Object 
Cuestiones relacionadas