Java: use polimorfismo o parámetros de tipo acotado

Pregunta:

Supongamos que tengo esta jerarquía de clases …

public abstract class Animal {
    public abstract void eat();
    public abstract void talk();
}
class Dog extends Animal {
    @Override
    public void eat() {
    }

    @Override
    public void talk() {
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
    }

    @Override
    public void talk() {
    }
}

Y luego tengo …

public static <T extends Animal> void addAnimal(T animal) {
    animal.eat();
    animal.talk();
}

public static void addAnimalPoly(Animal animal) {
    animal.eat();
    animal.talk();
}

¿Cuál es la diferencia al utilizar parámetros de tipo acotado o polimorfismo?

¿Y cuándo usar uno u otro?

Respuesta:

Estos dos ejemplos son equivalentes y, de hecho, se compilarán en el mismo código de bytes.

Hay dos formas en que agregar un tipo genérico acotado a un método como en su primer ejemplo hará cualquier cosa.

Pasar el parámetro de tipo a otro tipo

Estas dos firmas de métodos terminan siendo las mismas en el código de bytes, pero el compilador impone la seguridad de tipos:

public static <T extends Animal> void addAnimals(Collection<T> animals)

public static void addAnimals(Collection<Animal> animals)

En el primer caso, solo se permite una Collection (o subtipo) de Animal . En el segundo caso, se permite una Collection (o subtipo) con un tipo genérico de Animal o un subtipo.

Por ejemplo, en el primer método se permite lo siguiente, pero no en el segundo:

List<Cat> cats = new ArrayList<Cat>();
cats.add(new Cat());
addAnimals(cats);

La razón es que el segundo solo permite colecciones de animales, mientras que el primero permite colecciones de cualquier objeto que sea asignable a un animal (es decir, subtipos). Tenga en cuenta que si esta lista fuera una lista de animales que contienen un gato, cualquiera de los métodos lo aceptaría: el problema es la especificación genérica de la colección, no lo que realmente contiene.

Devolver objetos

La otra vez que importa es con la devolución de objetos. Supongamos que existió el siguiente método:

public static <T extends Animal> T feed(T animal) {
  animal.eat();
  return animal;
}

Podrías hacer lo siguiente con él:

Cat c1 = new Cat();
Cat c2 = feed(c1);

Si bien este es un ejemplo artificial, hay casos en los que tiene sentido. Sin genéricos, el método tendría que devolver Animal y necesitaría agregar conversión de tipos para que funcione (que es lo que el compilador agrega al código de bytes de todos modos detrás de escena).

Leave a Comment

Your email address will not be published.

Scroll to Top

istanbul avukat

-

web tasarım