Buscar
Social
Ofertas laborales ES

Foro sobre Java SE > Dudas sobre Genéricos y Polimorfismo

Hola, buenas tardes. A pesar que he leído la documentación sobre Generics, no entiendo su funcionamiento.

Por ejemplo, qué diferencia hay entre estas 2 clases:


public class Box {
private Object object;

public void set(Object object) { this.object = object; }
public Object get() { return object; }
}


public class Box<T> {
// T stands for "Type"
private T t;

public void set(T t) { this.t = t; }
public T get() { return t; }
}

Que es lo que hace esta clase? Que diferencia habria con una clase normal?

Otra duda: Polimorfismo

Cómo funciona el polimorfismo? Según tengo entendido el polimorfismo significa que distintos tipos de objetos (subtipos de una clase) pueden ser manejados como un solo.

¿Cuál es la diferencia entre? :


List lista = new ArrayList();

Y:


ArrayList lista = new ArrayList();

Bien, esto no me queda claro. Podrían darme un ejemplo de comportamiento polimórfico por favor?

Ya he revisado los docs de Oracle, pero se me dificulta la lectura por estar en inglés.


Gracias de antemano.

noviembre 7, 2013 | Unregistered CommenterNadie

Sobre los Genéricos:

La primera clase representa una caja que contiene un Object. Cualquier clase hereda de Object, por lo que en esa "caja" se puede meter cualquier objeto, por ejemplo un String:


String stringPrueba= "Prueba";

Box caja = new Box();
caja.set(stringPrueba);

El problema que tenemos al trabajar de esta manera es que no sabemos qué hay realmente dentro de la caja, sólo que es un Object, y si no controlamos los tipos podemos recibir una ClassCastException en ejecución al hacer el cast al objeto que nos interesa:


String objeto = "Prueba";

Box caja = new Box();
caja.set(caja);

// Aquí se producirá una java.lang.ClassCastException
// porque String no se puede convertir a Integer
Integer objetoDevuelto = (Integer) caja.get();

Para evitar la Exception tenemos que asegurarnos de qué tipo es:


String stringRecuperado = null;
Integer integerRecuperado = null;

Object objetoRecuperado = caja.get();

if(objetoRecuperado instanceof String){

  stringRecuperado = (String) objetoRecuperado;

if(objetoRecuperado instanceof Integer){

  integerRecuperado = (Integer) objetoRecuperado;

}

Para evitarlo y no tener errores en tiempo de ejecución (sólo sabremos qué hemos guardado en la caja durante la ejecución) se utilizan genéricos.

En el segundo ejemplo que has puesto, T representa el tipo de objeto que Box va a almacenar. La ventaja que tenemos es que el propio compilador nos avisará si intentamos almacenar cualquier otra cosa:


String stringPrueba = "Esto es una prueba";
Integer integerPrueba = new Integer(1);

Box<String> caja = new Box<String>(); //En esta instancia, T será String

caja.set(stringPrueba); //OK porque stringPrueba es un String

// No hace falta hacer cast porque sabemos que es un String
String objetoRecuperado = caja.get();

// El compilador nos marca la línea como error:
// The method set(String) in the type Box<String> is not applicable
// for the arguments (Integer)
caja.set(integerPrueba);

noviembre 10, 2013 | Registered CommenterUnai Valle

Un ejemplo de polimorfismo:

Imagínate que tenemos que usar este método:


public void darDeAlta(List usuarios);

Como parámetro vamos a recibir un objeto que herede de la interfaz List. En el API de Collections existen varias implementaciones de List, como ArrayList o LinkedList, así que el programador que tenga que usar ese método va a poder usar la implementación que más le guste o le convenga.


// Podemos usar ArrayList
List usuariosArrayList = ArrayList();

usuariosArrayList .add(usuario1);

darDeAlta(usuariosArrayList );

//O podemos usar LinkedList
List usuariosLinkedList = new LinkedList();

usuariosArrayList .add(usuario1);

darDeAlta(usuariosLinkedList);

Si hubiéramos definido el método como:


public void darDeAlta(LinkedList usuarios);

Obligaríamos a que todo el mundo usase LinkedList.


// NO podemos usar ArrayList
List usuariosArrayList = ArrayList();

usuariosArrayList .add(usuario1);

darDeAlta(usuariosArrayList );

// SÍ podemos usar LinkedList
List usuariosLinkedList = new LinkedList();

usuariosArrayList .add(usuario1);

darDeAlta(usuariosLinkedList);

Si durante la ejecución vemos que tenemos que hacer muchas inserciones y quisiéramos optimizar el proceso usando ArrayList no podríamos. Por eso es buena práctica trabajar con interfaces.

noviembre 10, 2013 | Registered CommenterUnai Valle

Muchas gracias por tus respuestas amigo. El tema de genericos me quedo claro.

El tema de polimorfismo, aún no me queda muy claro.

¿El polimorfismo va siempre vinculado a la Ligadura dinamica?

¿Que ventajas tengo con Ligadura dinámica sobre estática?

Si por ejemplo, tengo una clase abstracta Animal y otras dos que heredan de ella: Perro y Gato:

Interface IAnimal:

public interface IAnimal {

public void comunicarse();

}

Clase Animal:

public abstract class Animal implements IAnimal {

private String nombre = "No especificado";

public void setNombre(String nombre) {
this.nombre = nombre;
}

public String nombre() {
return this.nombre;
}

}

Clase Gato:

public class Gato extends Animal {

public setNombre(String nombre) {
super.setNombre(nombre);
}

public String getNombre () {
return this.nombre;
}

// Gato tiene que implementar el metodo comunicarse de IAnimal
public void comunicarse() {
System.out.println("Miau, yo soy un gato, Miau..");
}

} // fin clase Gato

Clase Perro:

public class Perro extends Animal {

public void setNombre(String nombre) {
this.nombre = nombre;
}

public String getNombre() {
return this.nombre;
}

// Perro tiene que implementar el metodo comunicarse de IAnimal
public void comunicarse() {
System.out.println("Whoof, Whoof, Soy un perro.");
}

} // fin clase perro

Main:

public class PruebaPolimorfica {

public static void main(String... args) {

Animal perro = new Perro();
perro.setNombre("Cancerbero");
System.out.println("Soy un:\t" + perro.getNombre());
perro.comunicarse();

Animal gato = new Gato();
gato.setNombre("Atenea");
System.out.println("Me llamo:\t" + gato.getNombre());
gato.comunicarse();
}
}


Qué diferencia hay entre esto:


Animal perro = new Perro();
perro.setNombre("Cancerbero");
System.out.println("Me llamo:\t" + perro.getNombre());
perro.comunicarse();

Perro perro = new Perro();
perro.setNombre("Cancerbero");
System.out.println("Me llamo:\t" + perro.getNombre());
perro.comunicarse();

La variable de referencia de la superclase, solo podra utilizar los metodos que su subclase hereda, pero también metodos propios de la superclase?

Saludos y disculpa las preguntas xD

noviembre 10, 2013 | Unregistered CommenterNadie