En este artículo vamos a cubrir una de las dudas más habituales que se producen con el manejo Java Generics, el uso del caracter “?” al que se le suele denominar wildcard . Vamos a suponer un ejemplo sencillo en el que tenemos dos clases. La clase Persona y la clase Deportista.
Podemos crearnos una lista de Personas la cual tenemos que recorrer e imprimir por pantalla. El programa Java sería así de sencillo :
package com.arquitecturajava; import java.util.ArrayList; import java.util.List; public class PrincipalDeportista { public static void main(String[] args) { List<Persona> listaPersonas=new ArrayList<Persona>(); listaPersonas.add(new Persona("pepe")); listaPersonas.add(new Persona("maria")); imprimir(listaPersonas); } public static void imprimir(List<Persona> lista) { for(Persona p:lista) { System.out.println(p.getNombre()); } } }
Mostramos tambien la clase:
package com.arquitecturajava; public class Persona {   private String nombre; public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public Persona(String nombre) { super(); this.nombre = nombre; } }
El programa simplemente construye una lista de Personas la rellena y luego la recorre.
Esto es fácil de hacer. Ahora bien que pasaría si realizáramos una modificación a la lista y esta lista fuera de Deportistas. El código quedaría de la siguiente forma:
package com.arquitecturajava; import java.util.ArrayList; import java.util.List; public class Principal { public static void main(String[] args) { List<Deportista> listaPersonas=new ArrayList<Deportista>(); listaPersonas.add(new Deportista("pepe","futbol")); listaPersonas.add(new Deportista("maria","tenis")); imprimir(listaPersonas); } public static void imprimir(List<Persona> lista) { for(Persona p:lista) { System.out.println(p.getNombre()); } } }
Lamentablemente este código no compila y da el siguiente error:
The method imprimir(List<Persona>) in the type Principal is not applicable for the arguments (List<Deportista>)
Parece extraño ya que estamos pasando una lista de Deportista que también son Personas . Sin embargo tenemos que darnos cuenta de lo siguiente. Una lista de Personas y una lista de Deportistas son dos tipos diferentes y no están relacionados. Aunque los objetos que ellos almacenen si lo estén.
Así pues al tratarse de dos tipos de objetos que realmente no están relacionados por herencia no nos podemos apoyar en el polimorfismo para gestionarles de forma común. Vamos a ver una solución.
Java Generics y Wildcard (?)
El caracter Wildcard(?) aporta una solución y nos vale para decirle al lenguaje Java que cuando usemos un tipo genérico se puede aplicar cualquier tipo al parámetro lista
vamos a verlo:
public static void imprimir(List&lt;?&gt; lista) { for(Persona p:lista) { System.out.println(p.getNombre()); } }
De esta forma añadiremos flexibilidad ya que podemos pasar cualquier tipo como parámetro genérico. Sin embargo tenemos todavia un problema al recorrer la lista de Personas estamos obligando a que la clase sea de tipo Persona cosa que el caracter de Wildcard no obliga. Así pues seguiremos con problemas de compilación, para evitar esto podemos añadir al Wildcard una restricción.
public static void imprimir(List&lt;? extends Persona&gt; lista) { for(Persona p:lista) { System.out.println(p.getNombre()); } }
Ahora sí que podremos trabajar tranquilos con los genéricos y los tipos.
Otros artículos :
Muchad gracias! por compartir tus conocimientos.
de nada 🙂
Déjenlo a si para que les funcione
package com.arquitecturajava;
import java.util.ArrayList;
import java.util.List;
public class Principal {
public static void main(String[] args) {
List listaPersonas=new ArrayList();
listaPersonas.add(new Deportista(“pepe”));
listaPersonas.add(new Deportista(“maria”));
imprimir(listaPersonas);
}
public static void imprimir(List lista) {
for(Persona p:lista) {
System.out.println(p.getNombre());
}
}
[…] artículos relacionados: Introducción Java Generics , Java Generics WildCard, Java Generics […]
[…] artículos relacionados: Java Generics , Java Generics WildCard<?> , Oracle Java […]
Buenas He seguido la explicación pero me he topado con varias cosas que no comprendo y quisiera comentartelas 1º – En la clase Principal , List tiene entre parentesis , la clase Deportista pero no la veo creada por ninguna parte – ¿ Debo crearla e introducirle al constructor de esta clase 2 parametros tipo String , los atributos y metodos que necesita ? public class Principal { public static void main(String[] args) { List listaPersonas=new ArrayList(); listaPersonas.add(new Deportista(“pepe”,”futbol”)); listaPersonas.add(new Deportista(“maria”,”tenis”)); imprimir(listaPersonas); } – ¿ No se debería de llamar PrincipalDeportista ? – En todo caso lo que hice fue… Read more »
[…] artículos relacionados: Java Generics , Java Generics WildCards, Java Set y […]
Hoy aprendi un par de cosas nuevas. Generics y WildCards… Gracias.
me alegro 🙂
[…] artículos relacionados : Java Generics , Java Generic y WildCards , Java […]
Hola, antes que nada darte las gracias por tu explicación. Me queda una duda que he visto en un examen de certificación.
Si tienes:
public class Abu{
void saludar(E e){}
static void main(String[] args){
//Abu obj1 = new Padre();
//Abu obj1 = new Padre();
obj1.saludar( new Abu());
obj1.saludar(new Padre());
obj1.saludar(new Hijo());
}
public class Padre extends Abu{}
public class Hijo extends Padre{}
Si descomentamos la 1 entonces las tres llamadas a saludar dan error de compilación.
Si descomentamos la 2 entonces la primera llamada a saludar da error de compilación.
No entiendo bien lo que esta pasando, ¿podrías ayudarme?
Gracias.
Recuerda que no puedes pasar al método saludar una clase Hijo saludar que pongas saludar (E extends Padre e)
La verdad es que no entiendo muy bien la respuesta, o quizás haya algún error en la propia pregunta. Si pudieras explicarlo más al detalle te lo agradecería.
Un saludo!
Estoy un poco perdido me puedes volver a hacer la pregunta? gracias 🙂
Hola Anne yo me imagino que la clase padre e hijo son inner class y esas clases pueden ser static o dinamicas. pero mira esto estan instentando instanicar la clase padre dentro del metodo main static lo que sucede es que este caso la clase padre para poder ser instaniada dentro del metodo main debe ser static en este caso. recuerde que no puedes llamar metodo non-static dentro de un contexto static pero si puedes instancias clases si no son inner clases. por otro lado tambien data un error a llamar el metodo saludar() porque estas enviando un objeto new… Read more »
Hola Pues de ser asi como entonces se trata este tipo de parametros cuando hay recursividad por ejempo?, trato de hacer lo siguiente: /** * Cambia el contenido de un list especificado * * @param container * @param fld_name * @param buffer */ public void list(Container container, String fld_name, ListModel buffer) { for (Component comp : container.getComponents()) { if (comp instanceof JList) { if (((JList) comp).getName() != null) { if (((JList) comp).getName().contentEquals(fld_name)) { ((JList) comp).setModel((ListModel) buffer); } } } else if (comp instanceof Container) { list((Container) comp, fld_name, (ListModel) buffer); } } } Siempre me salta el warning: warning: [unchecked]… Read more »
Deberias definir la clase como generica 🙂
Wow, tu siempre tan claro con los temas, muchas gracias !!!
gracias