13.6 Herencia y polimorfismo en Java: constructores y herencia
La herencia es uno de los pilares de la programación orientada a objetos (OOP) y permite que una clase herede características de otra clase. En Java, la herencia se implementa con la palabra clave extends
. El polimorfismo, por otro lado, es la capacidad que tiene un método de tener varias formas, es decir, un mismo método puede comportarse de manera diferente dependiendo del contexto en el que sea llamado. Ambos conceptos son fundamentales para crear aplicaciones flexibles y reutilizables.
Constructores y herencia
Cuando hablamos de constructores en un contexto de herencia, es importante comprender cómo los constructores de la clase base (superclase) se ven afectados por la clase derivada (subclase). En Java, la primera tarea de cualquier constructor de subclase es llamar a un constructor de superclase. Si no hacemos esto explícitamente, el compilador intentará llamar al constructor predeterminado (sin argumentos) de la superclase. Si la superclase no tiene un constructor predeterminado, tendremos que llamar explícitamente a un constructor existente usando la palabra clave super
.
superclase de clase pública {
Superclase pública() {
// Constructor predeterminado
}
Superclase pública (int arg) {
// Constructor con argumentos
}
}
La subclase de clase pública extiende la superclase {
Subclase pública() {
súper(); // Llama al constructor predeterminado de la superclase
}
Subclase pública (int arg) {
super(arg); // Llama al constructor con argumentos de la Superclase
}
}
Tenga en cuenta que si no llama explícitamente al constructor de la superclase usando super()
, el compilador lo hará por usted, siempre que haya un constructor predeterminado disponible. Si la superclase no tiene un constructor predeterminado y el programador no llama explícitamente a otro constructor, el compilador emitirá un error.
Herencia y encapsulación
La herencia también debe usarse con precaución en relación con la encapsulación. Si una clase base tiene campos privados, la subclase no puede acceder directamente a ellos. La subclase puede acceder a estos campos sólo a través de métodos públicos o protegidos (con la palabra clave protected
) de la clase base. Esto es importante para mantener la integridad de los datos y la abstracción de la clase base.
Polimorfismo
El polimorfismo en Java se logra principalmente mediante el método de anulación. Cuando una subclase proporciona una implementación específica para un método que ya existe en la superclase, decimos que el método ha sido anulado. Esto permite que una referencia de tipo de superclase apunte a un objeto del tipo de subclase y a la versión correcta del método que se llamará, dependiendo del tipo de objeto.
clase pública Animal {
public void emitSound() {
System.out.println("El animal emite un sonido");
}
}
perro de clase pública extiende Animal {
@Anular
public void emitSound() {
System.out.println("El perro ladra");
}
}
clase pública principal {
público estático vacío principal (String [] argumentos) {
Animal miAnimal = nuevo Perro();
miAnimal.emitSound(); // Salida: El perro ladra
}
}
En este ejemplo, incluso si la referencia myAnimal
es del tipo Animal
, el método emitSound()
que se llama es el del clase Perro
, ya que el objeto real es un Perro
. Esta es una demostración del polimorfismo en acción.
Consideraciones finales
La herencia y el polimorfismo son fundamentales para la reutilización de código y la creación de sistemas que sean fáciles de mantener y expandir. Sin embargo, estos conceptos deben usarse con discernimiento. La herencia puede generar jerarquías de clases complicadas y difíciles de entender si no se planifica bien. El polimorfismo, aunque poderoso, puede hacer que el código sea más difícil de seguir porque el comportamiento exacto del código puede no estar claro a primera vista.
Es importante recordar que la herencia sólo debe aplicarse cuando una relación "es un" tiene sentido. Usar la herencia para reutilizar código puede resultar tentador, pero puede conducir a una estructura de clases inapropiada. La composición, es decir, utilizar objetos de otras clases como campos, suele ser una mejor alternativa a la herencia.
En resumen, la herencia y el polimorfismo son herramientas poderosas en la caja de herramientas de un programador de Java, pero como todas las herramientas, deben usarse correctamente para lograr los mejores resultados. Comprender cómo interactúan los constructores con la herencia es un paso importante para dominar estos conceptos y crear aplicaciones sólidas y flexibles.