La herencia es uno de los pilares de la programación orientada a objetos. Permite que una clase adquiera las propiedades y comportamientos de otra, promoviendo la reutilización del código y una estructura más clara.
1. ¿Qué es la herencia?
La herencia permite que una clase (llamada subclase) herede atributos y métodos de otra clase (llamada superclase). Esto crea una relación «es un» entre las clases.
Sintaxis básica:
class Subclase extends Superclase { // Nuevos atributos y métodos de la subclase }
Ejemplo básico:
public class Animal { public void comer() { System.out.println("Este animal está comiendo."); } } public class Perro extends Animal { public void ladrar() { System.out.println("El perro está ladrando."); } } public class Principal { public static void main(String[] args) { Perro miPerro = new Perro(); miPerro.comer(); // Método heredado miPerro.ladrar(); // Método de la subclase } }
Salida:
Este animal está comiendo. El perro está ladrando.
2. Características clave de la herencia
- Reutilización del código:
- Las subclases pueden usar atributos y métodos definidos en la superclase.
- Especialización:
- Las subclases pueden agregar atributos y métodos adicionales para ampliar o modificar el comportamiento de la superclase.
- Relación jerárquica:
- Java no permite herencia múltiple directa (una clase no puede extender más de una clase).
Ejemplo de jerarquía:
public class Animal { public void hacerSonido() { System.out.println("El animal hace un sonido."); } } public class Gato extends Animal { @Override public void hacerSonido() { System.out.println("El gato maúlla."); } }
3. Uso de super
La palabra clave super
se utiliza para:
Llamar al constructor de la superclase:
public class Animal { public Animal(String nombre) { System.out.println("Animal: " + nombre); } } public class Perro extends Animal { public Perro(String nombre) { super(nombre); // Llama al constructor de la superclase System.out.println("Perro: " + nombre); } }
Salida:
Animal: Max Perro: Max
Acceder a métodos o atributos de la superclase:
public class Animal { public void dormir() { System.out.println("El animal está durmiendo."); } } public class Perro extends Animal { public void dormir() { super.dormir(); // Llama al método de la superclase System.out.println("El perro está roncando."); } }
Salida:
El animal está durmiendo. El perro está roncando.
4. Modificadores de acceso y herencia
Modificador | Accesible en subclases del mismo paquete | Accesible en subclases de otros paquetes |
---|---|---|
public | Sí | Sí |
protected | Sí | Sí |
Sin modificador | Sí | No |
private | No | No |
5. Sobreescritura de métodos (@Override)
La sobreescritura permite que una subclase redefina el comportamiento de un método heredado.
Reglas de sobreescritura:
- El método debe tener el mismo nombre, tipo de retorno y parámetros.
- El método no puede tener un modificador más restrictivo.
- Se recomienda usar la anotación
@Override
.
Ejemplo:
public class Animal { public void hacerSonido() { System.out.println("El animal hace un sonido."); } } public class Gato extends Animal { @Override public void hacerSonido() { System.out.println("El gato maúlla."); } } public class Principal { public static void main(String[] args) { Animal miAnimal = new Gato(); miAnimal.hacerSonido(); // Llama al método de la subclase } }
Salida:
El gato maúlla.
6. Clases finales y abstractas
Clases finales (final
):
public final class Animal { // Esta clase no puede tener subclases }
Clases abstractas:
public abstract class Animal { public abstract void hacerSonido(); } public class Perro extends Animal { @Override public void hacerSonido() { System.out.println("El perro ladra."); } }
7. Errores comunes con la herencia
- Acceso restringido a métodos heredados:
- Si un método heredado es
private
, no está disponible en la subclase.
- Si un método heredado es
- Dependencia circular:
- Java no permite que dos clases se extiendan mutuamente.
- Herencia innecesaria:
- Usa herencia solo si existe una clara relación «es un».
Resumen
- La herencia permite reutilizar código y crear jerarquías de clases.
- Usa
super
para acceder a constructores y métodos de la superclase. - La sobreescritura (
@Override
) redefine comportamientos en las subclases. - Entiende las diferencias entre clases finales y abstractas para aplicarlas correctamente.