La primera firma dice: list1 es una lista de Es.
La segunda firma dice: list es una lista de instancias de algún tipo, pero no conocemos el tipo.
La diferencia se hace evidente cuando tratamos de cambiar el método por lo que toma un segundo argumento, que debe ser añadido a la lista dentro del método:
import java.util.List;
public class Experiment {
public static <E> void funct1(final List<E> list1, final E something) {
list1.add(something);
}
public static void funct2(final List<?> list, final Object something) {
list.add(something); // does not compile
}
}
El primero se trabaja muy bien. Y no puedes cambiar el segundo argumento en algo que compile realmente.
En realidad, yo acaba de encontrar una demostración aún más agradable de la diferencia:
public class Experiment {
public static <E> void funct1(final List<E> list) {
list.add(list.get(0));
}
public static void funct2(final List<?> list) {
list.add(list.get(0)); // !!!!!!!!!!!!!! won't compile !!!!!!!!!
}
}
Uno puede ser que ¿por qué necesitamos <?>
cuando sólo restringe lo que podemos hacer con ella (como @Babu_Reddy_H hizo en los comentarios) . Veo los siguientes beneficios de la versión de comodín:
La persona que llama tiene que saber menos sobre el objeto que pasa Por ejemplo si tengo un mapa de Listas:. Map<String, List<?>>
me puede pasar los valores de acuerdo a su función sin especificando el tipo de los elementos de la lista. Así que
Si entrego objetos con esta configuración, limito activamente lo que la gente sabe sobre estos objetos y lo que pueden hacer con él (siempre que se mantengan alejados de la transmisión insegura).
Estos dos tienen sentido cuando los combino: List<? extends T>
. Por ejemplo, considere un método List<T> merge(List<? extends T>, List<? extends T>)
, que combina las dos listas de entrada con una nueva lista de resultados. Claro que podrías introducir dos parámetros de tipo más, pero ¿por qué querrías? Sería más de especificar cosas.
- finalmente comodines puede tener límites más bajos, por lo que con las listas que puede hacer el trabajo
add
método, mientras que get
no te da nada útil. Por supuesto, eso desencadena la siguiente pregunta: ¿por qué los genéricos no tienen límites más bajos?
Para una respuesta más en profundidad, véase: When to use generic methods and when to use wild-card? y http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203
Si String se refiere a 'java.lang.String', creo que funct2 es bastante redundante en las expresiones de comodines, ya que' java.lang.String' es la clase final y no se puede extender. – nhahtdh
Esto es extraño porque técnicamente no se puede extender String ya que es una clase final. –
Sin embargo, no hay ninguna restricción en el uso de la función 2: ya que permite subclases de Cadena (aunque imposible) o la clase de Cadena en sí ... – ria