13.4 Herencia y polimorfismo en Java: uso de 'super' para acceder a miembros de la superclase
La herencia es uno de los pilares fundamentales de la Programación Orientada a Objetos (POO), y Java, al ser un lenguaje que adopta este paradigma, ofrece mecanismos robustos para implementarla. La herencia permite que una clase herede características de otra clase, promoviendo la reutilización de código y la creación de una jerarquía de clases. El polimorfismo, a su vez, es la capacidad de un objeto de ser referenciado de diversas formas, principalmente a través de su clase base o interfaces. Ambos conceptos son esenciales para comprender y desarrollar aplicaciones Java eficientes.
Cuando una clase hereda de otra, la clase que hereda se llama subclase, mientras que la clase de la que hereda se llama superclase. La subclase hereda campos y métodos de la superclase y también puede agregar nuevos campos y métodos o anular métodos heredados. Sin embargo, puede haber situaciones en las que la subclase quiera acceder a los miembros (campos o métodos) de la superclase. Aquí es donde el uso de la palabra clave super
se vuelve relevante.
Acceder a miembros de la superclase con 'super'
La palabra clave super
en Java se utiliza dentro de una subclase y sirve para hacer referencia directa a la superclase inmediata. Se utiliza principalmente en tres situaciones:
- Para llamar al constructor de la superclase.
- Para acceder a un miembro de la superclase que ha sido oculto por la subclase (por ejemplo, un campo con el mismo nombre).
- Para invocar un método de superclase que ha sido anulado por la subclase.
Llamar al constructor de superclase
Cuando se crea una instancia de una subclase, se llama al constructor de la superclase antes que al constructor de la subclase. Si la superclase no tiene un constructor sin argumentos (es decir, un constructor predeterminado), necesitarás llamar explícitamente a un constructor específico de la superclase usando super
. Esto se hace en la primera línea del constructor de la subclase:
base de clase { Base(int x) { System.out.println("Constructor base con valor " + x); } } clase Derivada extiende Base { Derivada(int x, int y) { super(x); // Llama al constructor de la clase base System.out.println("Constructor derivado con valor " + y); } }
Acceder a miembros ocultos de la superclase
Si una subclase define un campo con el mismo nombre que un campo de superclase, el campo de superclase está oculto dentro de la subclase. Para acceder al campo oculto de la superclase, puede utilizar super
:
base de clase { número entero; } clase Derivada extiende Base { número entero; void setNumber(int número) { este.número = número; // Asigna al campo de subclase super.número = número + 10; // Asigna al campo de superclase } }
Invocar métodos anulados de superclase
Cuando una subclase anula un método de superclase, aún puede llamar a la versión del método de la superclase usando super
. Esto es útil cuando desea ampliar la funcionalidad del método anulado, en lugar de reemplazarlo por completo:
base de clase { espectáculo vacío() { System.out.println("Mostrar desde la base"); } } clase Derivada extiende Base { espectáculo vacío() { Súper show(); // Llama al método show() de la superclase System.out.println("Mostrar derivada"); } }
Polimorfismo y herencia
El polimorfismo en Java está estrechamente relacionado con la herencia. Mediante polimorfismo, los objetos de una subclase pueden tratarse como objetos de la superclase. Esto permite que los métodos o variables de referencia de la superclase se utilicen para hacer referencia a objetos de cualquier subclase, lo que permite la ejecución de métodos anulados específicos de la subclase. La decisión sobre qué método invocar se toma en tiempo de ejecución (enlace tardío), lo que se conoce como polimorfismo en tiempo de ejecución o polimorfismo dinámico.
Por ejemplo, considere una superclase llamada Animal
y las subclases Dog
y Cat
. Si ambas subclases anulan un método makeSound()
de la superclase, un método que recibe una referencia de Animal
puede invocar makeSound()
y el sonido se producirá dependiendo de si el objeto referenciado es un Perro
o un Gato
.
clase animal { vacío hacerSonido() { System.out.println("Sonido animal genérico"); } } clase Perro extiende Animal { vacío hacerSonido() { System.out.println("Oof oof"); } } clase Gato extiende Animal { vacío hacerSonido() { System.out.println("Miau"); } } clase pública PruebaPolimorfismo { público estático vacío principal (String [] argumentos) {Animal miAnimal = nuevo Perro(); miAnimal.makeSound(); // Producirá "Guau guau" miAnimal = nuevo Gato(); miAnimal.makeSound(); // Producirá "Miau" } }
Este ejemplo ilustra la flexibilidad y el poder del polimorfismo en Java, donde la implementación específica de un método está determinada por el tipo real del objeto y no por el tipo de la variable de referencia.
Conclusión
La herencia y el polimorfismo son conceptos clave en la programación orientada a objetos y se utilizan ampliamente en Java para crear programas flexibles y reutilizables. La palabra clave super
juega un papel importante en la herencia, permitiendo que las subclases interactúen con los miembros de la superclase de forma controlada. El polimorfismo, por otro lado, permite la interacción con objetos de diferentes clases a través de una interfaz común. Comprender estos conceptos y saber aplicarlos es fundamental para cualquier programador Java que quiera crear sistemas robustos y mantenibles.