Guía de programación en Java > Herencia
Introducción
La herencia es uno de los pilares fundamentales de la Programación Orientada a Objetos (POO). Permite crear nuevas clases basadas en otras existentes, reutilizando y extendiendo su funcionalidad. En esta sesión aprenderás:
- cómo funcionan las clases derivadas
- el uso de la palabra clave
super
y - la sobrescritura de métodos.
¿Qué es la herencia?
La herencia permite que una clase adquiera los atributos y métodos de otra clase. A la clase que hereda se le llama clase derivada, clase hija o subclase. La otra clase se denomina clase base o superclase.
Sintaxis básica:
class Superclase {
// Atributos y métodos de la superclase
}
class Subclase extends Superclase {
// Atributos y métodos adicionales de la subclase
}
La herencia con un ejemplo
Imagina que estás diseñando personajes para un videojuego. Tienes un personaje genérico llamado «PersonajeBase» que todos los demás personajes deben tener. Este personaje tiene cosas básicas como:
- Nombre (por ejemplo, «Mario»).
- Vida (por ejemplo, 100 puntos).
- Poder atacar (¡obvio!).
Pero también tienes personajes específicos como un guerrero y un mago. Ambos tienen esas cosas básicas, pero también tienen algo especial:
- El guerrero tiene una espada.
- El mago tiene un hechizo.
Cómo funciona la herencia
En lugar de escribir TODO desde cero para cada personaje (guerrero, mago, etc.), dices:
- El guerrero hereda de PersonajeBase.
- Es decir, el guerrero obtiene automáticamente nombre, vida y la habilidad de atacar.
- Solo tienes que añadir lo que lo hace especial: la espada.
- El mago hereda de PersonajeBase.
- También tiene nombre, vida y la habilidad de atacar.
- Y le añades su característica única: el hechizo.
Ventajas de la herencia:
- Reutilización de código: No necesitas escribir el mismo código varias veces.
- Extensibilidad: Puedes agregar nueva funcionalidad a las clases existentes.
- Organización: Facilita la estructuración del código en jerarquías lógicas.
Traducción a código sencillo
// Clase base: lo básico que todos los personajes tienen
class PersonajeBase {
String nombre;
int vida;
void atacar() {
System.out.println(nombre + " ataca con fuerza.");
}
}
// Clase guerrero que hereda de PersonajeBase
class Guerrero extends PersonajeBase {
String arma = "Espada";
void atacar() {
System.out.println(nombre + " ataca con su " + arma + ".");
}
}
// Clase mago que hereda de PersonajeBase
class Mago extends PersonajeBase {
String hechizo = "Bola de Fuego";
void atacar() {
System.out.println(nombre + " lanza un " + hechizo + ".");
}
}
// Ejemplo en acción
public class Main {
public static void main(String[] args) {
Guerrero guerrero = new Guerrero();
guerrero.nombre = "Thor";
guerrero.vida = 150;
guerrero.atacar(); // Thor ataca con su Espada.
Mago mago = new Mago();
mago.nombre = "Merlín";
mago.vida = 100;
mago.atacar(); // Merlín lanza un Bola de Fuego.
}
}
- La clase
PersonajeBase
es como una receta genérica. Todos los personajes tienen las mismas «bases» gracias a ella. - Las clases
Guerrero
yMago
son recetas más específicas que añaden detalles únicos (espada o hechizo). - Herencia significa: «No escribas lo mismo dos veces. Usa lo que ya tienes y solo agrega lo que sea diferente.»
¿Por qué es útil?
- Ahorras tiempo: No tienes que copiar y pegar el mismo código para cada tipo de personaje.
- Es fácil de actualizar: Si cambias algo en la clase base, todos los personajes heredan automáticamente esos cambios.
- Es lógico: Refleja cómo funcionan las cosas en la vida real. Por ejemplo, todos los perros «heredan» características básicas como ladrar, pero algunos son más rápidos o tienen habilidades especiales.
Clases derivadas
Cuando una clase deriva de otra, hereda todos sus atributos y métodos públicos y protegidos. Sin embargo, los atributos y métodos privados no son accesibles directamente desde la subclase.
Ejemplo básico:
class Animal {
String nombre;
void comer() {
System.out.println(nombre + " está comiendo.");
}
}
class Perro extends Animal {
void ladrar() {
System.out.println(nombre + " está ladrando.");
}
}
public class Main {
public static void main(String[] args) {
Perro miPerro = new Perro();
miPerro.nombre = "Rex";
miPerro.comer();
miPerro.ladrar();
}
}
Salida:
Rex está comiendo.
Rex está ladrando.
Uso de super
La palabra clave super
se utiliza en una subclase para:
- Acceder a los atributos y métodos de la superclase.
- Invocar el constructor de la superclase.
Ejemplo de super
para acceder a métodos:
class Animal {
void sonido() {
System.out.println("El animal hace un sonido.");
}
}
class Gato extends Animal {
void sonido() {
super.sonido(); // Llama al método de la superclase
System.out.println("El gato dice: miau.");
}
}
public class Main {
public static void main(String[] args) {
Gato miGato = new Gato();
miGato.sonido();
}
}
Salida:
El animal hace un sonido.
El gato dice: miau.
Ejemplo de super
en constructores:
class Persona {
String nombre;
Persona(String nombre) {
this.nombre = nombre;
}
}
class Estudiante extends Persona {
String grado;
Estudiante(String nombre, String grado) {
super(nombre); // Llama al constructor de la superclase
this.grado = grado;
}
void mostrarInfo() {
System.out.println("Nombre: " + nombre + ", Grado: " + grado);
}
}
public class Main {
public static void main(String[] args) {
Estudiante estudiante = new Estudiante("Ana", "10°");
estudiante.mostrarInfo();
}
}
Salida:
Nombre: Ana, Grado: 10°
Sobrescritura de métodos
La sobrescritura permite que una subclase proporcione una implementación específica de un método ya definido en su superclase.
Reglas para sobrescribir:
- El método debe tener el mismo nombre, tipo de retorno y parámetros que el método de la superclase.
- El método sobrescrito no puede tener una visibilidad más restrictiva.
- Se utiliza la anotación
@Override
para indicar que un método está siendo sobrescrito (opcional, pero recomendable).
Ejemplo de sobrescritura:
class Animal {
void sonido() {
System.out.println("El animal hace un sonido.");
}
}
class Perro extends Animal {
@Override
void sonido() {
System.out.println("El perro dice: guau.");
}
}
public class Main {
public static void main(String[] args) {
Animal miAnimal = new Animal();
miAnimal.sonido();
Animal miPerro = new Perro(); // Polimorfismo
miPerro.sonido();
}
}
Salida:
El animal hace un sonido.
El perro dice: guau.
Ventajas y limitaciones de la herencia
Ventajas:
- Reutilización de código: Menos código duplicado.
- Facilidad de mantenimiento: Los cambios en la superclase se reflejan en las subclases.
- Extensibilidad: Posibilidad de agregar nueva funcionalidad.
Limitaciones:
- Acoplamiento: Las subclases dependen de la superclase, lo que puede dificultar cambios en el futuro.
- No siempre es la mejor solución. Si las clases no tienen una relación natural de «es un(a)», considera usar composición en lugar de herencia.
Ejercicio Propuesto
- Crea una clase
Vehiculo
con los atributos:marca
(String)modelo
(String)
mostrarInfo()
que imprima la información del vehículo. - Crea una subclase
Coche
que extiendaVehiculo
y añada:puertas
(int)
mostrarInfo()
para incluir el número de puertas. - Crea una subclase
Motocicleta
que extiendaVehiculo
y añada:tipo
(String)
mostrarInfo()
para incluir el tipo de motocicleta. - En una clase
Main
, crea objetos deCoche
yMotocicleta
y llama a sus métodosmostrarInfo()
.
Resumen
- La herencia permite crear clases basadas en otras, reutilizando y extendiendo su funcionalidad.
super
se usa para acceder a atributos, métodos y constructores de la superclase.- La sobrescritura de métodos permite personalizar el comportamiento de una subclase.
Con estos conceptos, podrás construir jerarquías de clases más complejas y reutilizables. ¡Practica con los ejercicios para dominar la herencia! 🚀
Deja una respuesta