ProgramaciónDesarrollador Java

¿Qué es el polimorfismo en Java, cómo se implementa y para qué sirve?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

Historia de la pregunta:

El polimorfismo es uno de los principios clave de la programación orientada a objetos (OOP), que ha sido soportado en Java desde su creación. Permite que un objeto se comporte de manera diferente dependiendo de su tipo real durante la ejecución del programa, incluso si se utiliza una referencia de tipo base.

Problema:

Sin polimorfismo, el código se vuelve inflexible, a menudo aparecen construcciones redundantes del tipo switch-case o if-else para trabajar con objetos de diferentes tipos. Esto complica el mantenimiento y la expansión del código. El polimorfismo resuelve el problema de la necesidad de escribir código repetido para diferentes tipos.

Solución:

El polimorfismo en Java se implementa a través de la herencia y las interfaces. Permite:

  • que una referencia de tipo padre apunte a un objeto de tipo hijo;
  • invocar métodos sobreescritos sin conocer el tipo específico del objeto en tiempo de compilación.

Ejemplo de código:

class Animal { void speak() { System.out.println("Animal habla"); } } class Dog extends Animal { @Override void speak() { System.out.println("El perro ladra"); } } class Cat extends Animal { @Override void speak() { System.out.println("El gato maulla"); } } public class PolyDemo { public static void main(String[] args) { Animal a1 = new Dog(); Animal a2 = new Cat(); a1.speak(); // El perro ladra a2.speak(); // El gato maulla } }

Características clave:

  • Permite ampliar y modificar sistemas sin cambiar el código existente.
  • Proporciona un bajo acoplamiento entre componentes.
  • A través del polimorfismo se implementan patrones de diseño (por ejemplo, Strategy, Command).

Preguntas engañosas.

¿Cuál es la diferencia entre sobrecarga (overloading) y sobreescritura (overriding) de métodos en el polimorfismo?

La sobrecarga es la definición de varios métodos con el mismo nombre, pero con una firma diferente en una clase. La sobreescritura es la definición de un método en una subclase con la misma firma que en la clase padre.

class Example { void foo(int x) {} void foo(String y) {} // esto es sobrecarga } class Base { void foo() {} } class Child extends Base { @Override void foo() {} // esto es sobreescritura }

¿Puede haber polimorfismo sin herencia?

En el sentido clásico en Java, no: el polimorfismo requiere la existencia de una jerarquía de herencia o una interfaz implementada.

¿Se pueden invocar métodos de la subclase desde una referencia de la clase padre?

Solo se pueden invocar los métodos definidos en la clase padre o sobreescritos en la subclase. Los métodos que solo existen en la subclase no pueden ser llamados sin un casting de tipo.

Animal a = new Dog(); a.speak(); // se puede // a.fetch(); // error de compilación, incluso si Dog tiene el método fetch()

Errores típicos y antipatrón

  • Sobreescritura de métodos sin la anotación @Override — el compilador no detectará un error de mismatched signature.
  • Casting de tipos sin comprobar a través de instanceof, lo que provoca ClassCastException.
  • Uso del polimorfismo donde sería más sencillo utilizar composición.

Ejemplo de la vida real

Caso negativo

En el proyecto se implementaron las clases Dog, Cat, Cow, pero el código utilizado trabajaba directamente con los tipos, llamando a los métodos a través de casting explícitos e instanceof:

Ventajas:

  • Implementación rápida de nuevos tipos de animales.

Desventajas:

  • Crecimiento de if-else.
  • Violación de los principios de OOP.
  • Complejidad en la escalabilidad.

Caso positivo

Herencia de Animal con un speak() virtual. Toda la interacción a través del tipo base Animal.

Ventajas:

  • Flexibilidad al agregar nuevos tipos.
  • Sencillez en las pruebas.

Desventajas:

  • Más complicado si los objetos no están necesariamente relacionados, a veces la composición sería más preferible.