Abstracción¶
La abstracción es un proceso de ocultar los detalles de implementación y mostrar solo la funcionalidad al usuario.
De otra manera, muestra solo las cosas esenciales para el usuario y oculta los detalles internos.
Una clase abstracta es una clase que no se puede instanciar pero que puede ser el padre de otras clases. Esto es útil, por ejemplo, cuando tenemos un concepto abstracto o amplio como Vehículo o Animal pero en realidad los objetos reales serían tipos específicos como Coche, Avión, Perro, etc.
Aunque no se puede instanciar, una clase abstracta define métodos y variables que heredan las clases hijas.
Cómo crear una clase abstracta¶
Para crear una clase abstracta en IntelliJ, haremos lo siguiente:
- Botón derecho en el paquete de nuestra aplicación → New ---> Java class y añadimos la palabra reservada
abstract:
public abstract class Animal {
}
Métodos abstractos¶
Las clases abstractas pueden opcionalmente contener métodos abstractos. También pueden contener métodos no abstractos, que serán heredados por los hijos.
Un método abstracto no tiene cuerpo. (No tiene código). Solo se escribe la signatura del método con la palabra reservada abstract.
Vamos a crear una clase abstracta Animal:
public abstract class Animal {
// Campo (variable de instancia)
protected String nombre;
// Constructor
public Animal(String nombre) {
this.nombre = nombre;
}
// Métodos abstractos (deben ser implementados por las subclases)
public abstract void alimentar();
public abstract void mover();
// Método concreto (ya implementado en la clase base)
public String getNombre() {
return nombre;
}
// Método Concreto
public void descansar() {
System.out.println(nombre + " está tomando una siesta ligera.");
}
}
Si ahora creamos una clase hija que herede de Animal obtendremos un error:

Es necesario implementar los métodos abstractos para la clase derivada. la clase puede implementar sus propios métodos.
public class Dog extends Animal {
// Constructor que llama al constructor de la clase base (Animal)
public Dog(String nombre) {
super(nombre);
}
// Implementación obligatoria del método abstracto
@Override
public void alimentar() {
System.out.println("El perro " + getNombre() + " está comiendo.");
}
// Implementación obligatoria del método abstracto
@Override
public void mover() {
System.out.println("Se está moviendo ruidosamente");
}
//método propio de Dog
public void darLaPata(){
System.out.println("Ofrece la pata amablemente");
}
}
public class Gato extends Animal {
// Constructor: Llama al constructor de la clase base Animal
public Gato(String nombre) {
super(nombre); // Llama a public Animal(String nombre)
}
// 1. Implementación del método abstracto alimentar()
@Override
public void alimentar() {
System.out.println("El gato " + getNombre() + " está bebiendo leche y come pescado.");
}
// 2. Implementación del método abstracto mover()
@Override
public void mover() {
System.out.println("Se está moviendo silenciosamente.");
}
// 3. Método específico de la subclase Gato
public void maullar() {
System.out.println(getNombre() + " dice: ¡Miau! Miau!");
}
}
public class Main {
public static void main(String[] args) {
// --- Gato ---
Gato misifu = new Gato("Misifu");
System.out.println("--- Llamando a Gato ---");
// Se llama al método sobreescrito de la subclase Gato
misifu.alimentar();
misifu.mover();
//método propio
misifu.maullar();
//llamada a método común implementado en Animal
misifu.descansar();
// --- Perro ---
Dog max = new Dog("Max");
System.out.println("\n--- Llamando a Perro ---");
// Se llama al método sobreescrito de la subclase Dog
max.alimentar();
max.mover();
//método propio
max.darLaPata();
//llamada a método común implementado en Animal
max.descansar();
}
}
Clases hijas abstractas¶
Un hijo abstracto de un padre abstracto no tiene que definir métodos no abstractos para los métodos abstractas que hereda. Esto significa que puede haber varios pasos entre una clase base abstracta y una clase secundaria que no es completamente abstracta.
Por ejemplo una subespecie Ave puede ser abstracta con nuevos métodos abstractos
public abstract class Ave extends Animal {
private
// Constructor
public Ave(String nombre) {
super(nombre);
}
// Nuevo método abstracto específico de la subclase Ave
public abstract void volar();
}
public class Ganso extends Ave{
public Ganso(String nombre) {
super(nombre);
}
//Implementa todos los métodos abstractos heredados
@Override
public void volar() {
System.out.println("Vuela lento pero mucha distancia");
}
@Override
public void alimentar() {
System.out.println("Come insectos en la laguna");
}
@Override
public void mover() {
System.out.println("Se desplaza elegantemente por el agua y cómicamente por tierra");
}
}
Resumen de característica de las clase abstractas¶
| Característica | Descripción | Ejemplo (Animal / Gato) |
|---|---|---|
| Declaración | Se usa la palabra clave abstract delante de class. |
public abstract class Animal { ... } |
| Instanciación | No se pueden crear objetos directamente de esta clase. | No puedes hacer Animal a = new Animal("Pepe");. |
| Métodos Abstractos | No tienen cuerpo (solo firma). Obligan a las subclases a implementarlos. | public abstract void alimentar(); (En Animal) |
| Métodos Concretos | Tienen cuerpo y lógica. Son heredados y compartidos por las subclases. | public void descansar() { ... } (En Animal) |
| Herencia | Una subclase concreta debe implementar todos los métodos abstractos del padre. | class Gato extends Animal { @Override public void alimentar() {...} } |
| Constructores | Pueden tener constructores, pero solo son llamados por la subclase usando super(). |
El constructor de Gato llama a super(nombre); del constructor de Animal. |