TutorJava Nivel Básico: tutorial completo Java 21

Las interfaces y clases abstractas son los mecanismos de Java para definir contratos y abstracciones. Con las mejoras introducidas hasta Java 21, las interfaces son mucho más potentes que en las primeras versiones del lenguaje.

Clases abstractas

Una clase abstracta no se puede instanciar directamente. Define el esqueleto de una familia de clases, proporcionando implementación parcial que las subclases concretan:

public abstract class Figura {
    protected String color;

    public Figura(String color) {
        this.color = color;
    }

    // Método abstracto: cada figura implementa el suyo
    public abstract double calcularArea();

    // Método concreto: compartido por todas las figuras
    public void describir() {
        System.out.printf("Figura %s con área %.2f%n", color, calcularArea());
    }
}

public class Circulo extends Figura {
    private double radio;

    public Circulo(String color, double radio) {
        super(color);
        this.radio = radio;
    }

    @Override
    public double calcularArea() {
        return Math.PI * radio * radio;
    }
}

public class Rectangulo extends Figura {
    private double ancho, alto;

    public Rectangulo(String color, double ancho, double alto) {
        super(color);
        this.ancho = ancho;
        this.alto = alto;
    }

    @Override
    public double calcularArea() {
        return ancho * alto;
    }
}

Interfaces

Una interfaz define un contrato: un conjunto de métodos que las clases que la implementan deben proporcionar. A diferencia de la herencia (una sola clase padre), una clase puede implementar múltiples interfaces:

public interface Serializable {
    byte[] serializar();
}

public interface Comparable {
    int compareTo(T otro);
}

public class Producto implements Comparable, Serializable {
    private String nombre;
    private double precio;

    public Producto(String nombre, double precio) {
        this.nombre = nombre;
        this.precio = precio;
    }

    @Override
    public int compareTo(Producto otro) {
        return Double.compare(this.precio, otro.precio);
    }

    @Override
    public byte[] serializar() {
        return nombre.getBytes();
    }
}

Métodos default en interfaces (Java 8+)

Desde Java 8, las interfaces pueden tener métodos con implementación por defecto (default). Esto permite añadir métodos a interfaces existentes sin romper las implementaciones:

public interface Coleccion {
    void agregar(T elemento);
    int tamanyo();

    default boolean estaVacia() {
        return tamanyo() == 0;
    }

    default void mostrar() {
        System.out.println("Colección con " + tamanyo() + " elementos");
    }
}

Interfaces funcionales (Java 8+)

Una interfaz con un único método abstracto se llama interfaz funcional. Java las marca con @FunctionalInterface. Son la base de las lambdas:

@FunctionalInterface
public interface Transformador {
    R transformar(T entrada);
}

// Uso con lambda
Transformador longitud = s -> s.length();
System.out.println(longitud.transformar("Hola")); // 4

// O con referencia a método
Transformador mayusculas = String::toUpperCase;
System.out.println(mayusculas.transformar("hola")); // HOLA

Cuándo usar interfaz vs. clase abstracta

Criterio

Interfaz

Clase abstracta

Herencia múltiple

Sí (una clase puede implementar muchas)

No (solo una clase padre)

Estado (atributos)

Solo constantes (static final)

Sí, atributos de instancia

Constructor

No

Uso típico

Contrato de capacidad («puede hacer X»)

Familia de clases con código compartido

Regla práctica en Java moderno: prefiere interfaces. Úsalas para definir contratos. Reserva las clases abstractas para cuando realmente necesites compartir estado o lógica de inicialización entre las subclases.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP