Volver a Java Básico

Introducción

La herencia te permite crear jerarquías de clases donde las clases hijas heredan atributos y métodos de una clase padre. La abstracción te ayuda a definir estructuras reutilizables.

Clases Abstractas

Una clase abstracta no puede ser instanciada directamente. Sirve como plantilla para otras clases.

// Clase abstracta base public abstract class Animal { protected String nombre; public Animal(String nombre) { this.nombre = nombre; } public void saludar() { System.out.println("Hola, soy un animal llamado " + nombre); } // Método abstracto (obligatorio de implementar) public abstract void hacerSonido(); } // Clase concreta que hereda public class Perro extends Animal { public Perro(String nombre) { super(nombre); } @Override public void hacerSonido() { System.out.println("¡Guau!"); } } // Otra clase concreta public class Gato extends Animal { public Gato(String nombre) { super(nombre); } @Override public void hacerSonido() { System.out.println("¡Miau!"); } } // Uso en código Animal perro = new Perro("Rex"); perro.saludar(); // Hola, soy un animal llamado Rex perro.hacerSonido(); // ¡Guau! Animal gato = new Gato("Michi"); gato.saludar(); // Hola, soy un animal llamado Michi gato.hacerSonido(); // ¡Miau!

Polimorfismo

El polimorfismo te permite tratar objetos de diferentes tipos de manera uniforme a través de su clase base:

List<Animal> animales = List.of( new Perro("Toby"), new Gato("Luna") ); for (Animal animal : animales) { animal.saludar(); animal.hacerSonido(); }

Buenas Prácticas

  • Usa herencia cuando existe una relación clara "es-un"
  • Mantén las jerarquías de herencia simples (evita jerarquías profundas)
  • Usa clases abstractas para definir comportamiento común
  • Sobrescribe métodos apropiadamente con @Override
  • Prefiere composición sobre herencia cuando sea apropiado

Malas Prácticas Comunes

  • Crear jerarquías de herencia profundas (más de 3-4 niveles)
  • Usar herencia solo para reutilizar código sin relación lógica
  • No usar la anotación @Override
  • Hacer todo abstracto innecesariamente

Ejemplo Práctico

En un juego, podrías tener diferentes tipos de personajes que comparten comportamiento común:

public abstract class Personaje { protected int vida; protected int nivel; public abstract void atacar(); public void recibirDanio(int danio) { vida -= danio; } } public class Guerrero extends Personaje { @Override public void atacar() { System.out.println("¡Guerrero ataca con espada!"); } } public class Mago extends Personaje { @Override public void atacar() { System.out.println("¡Mago lanza un hechizo!"); } }

Conclusión

La herencia y la abstracción son herramientas poderosas para crear estructuras de código reutilizables y organizadas. Usadas correctamente, te ayudan a modelar relaciones del mundo real y evitar duplicación de código.

En el próximo capítulo, aprenderemos sobre interfaces y cómo se diferencian de las clases abstractas.