¿Son realmente necesarios los generics de comodín?

por ejemplo:

public String add(Set t){ ...; } public  String add(Set t){ ...; } 

El primero utiliza generics comodín; El segundo es la forma normal de un método genérico. ¿Cual es la diferencia?

¿En qué situación necesitamos generics comodín, no la forma normal de generics?

Aquí es una situación donde se requieren comodines. Este método toma una List> , que es una lista de listas. El método puede agregar listas de diferentes tipos de componentes en él:

 public void foo(List> t) { t.add(new ArrayList()); t.add(new ArrayList()); } 

No puede hacer esto usando parámetros de tipo genérico sin comodines. Por ejemplo, lo siguiente no funciona:

 public  void foo(List> t) { t.add(new ArrayList()); // does not compile t.add(new ArrayList()); // does not compile } 

Dado que se agregó el soporte para generics, el uso de un tipo parametrizado sin proporcionar un parámetro de tipo generalmente causa una advertencia del comstackdor. Por otro lado, hay situaciones en las que no le importa en absoluto cuál sea el parámetro de tipo (es decir, no use el tipo en ningún lugar) o, lo que es peor, es posible que no sepa qué es T en absoluto y que use permite express eso sin causar una advertencia del comstackdor.

Posible caso de uso para el caso “no importa” (muy simple por brevedad, pero se entiende la idea):

 public void clearList(List list) { list.clear(); } 

Un ejemplo para el caso de “no sé”: una firma de método real de la clase Class :

 static Class forName(String className); 

Aquí el método devuelve un objeto de algún tipo de Class . Class es genérica pero, por supuesto, no conoce el tipo porque depende del parámetro className que se resuelve en el tiempo de ejecución. Por lo tanto, no puede poner T aquí ya que T no se conoce en el momento de la comstackción (incluso para un sitio de llamada en particular), y usar solo la Class sin parámetro de tipo sería una mala práctica y causaría una advertencia del comstackdor.

La forma de comodín es cuando no te importa qué tipos de objetos estás manejando.

La forma genérica le permite agregar restricciones en el tipo de objetos manejados.

Un ejemplo de caso de uso podría ser el siguiente: un repository genérico con métodos de agregar / actualizar / eliminar, usted define el comportamiento común usando el tipo genérico:

 public class Repository{ public void add(T t){...} public void update(T t){...} public void remove(T t){...} } 

Luego, para hacer un repository para Apple y Banana , simplemente extienda esta clase y reemplace T con el tipo real:

 public class AppleRepo extends Repository {} public class BananaRepo extends Repository {} 

Si el repository genérico se declarara como Repository , No sería bueno porque no está restringido a Banana, y usted no podría usar métodos específicos de Banana dentro de él sin lanzar objetos;

También los generics le permiten express más restricciones, por ejemplo

 Repository 

le permite restringir la clase de repository genérico a frutas. Y podrás realizar llamadas a los métodos de Fruit en su código.

No hay diferencia en llamar a los métodos.

En el segundo método ( add(Set) ) puede crear variables de tipo T :

 public  String add(Set t){ T item = t.iterator().next(); //.... } 

Eso le da algún tipo de verificación adicional. En el primer método te quedas con usar Object .