Interfaces frente a Clases Abstractas
Contratos y esqueletos de implementación
Interfaces
Una interfaz define un contrato: qué operaciones ofrece un tipo, sin decir cómo las implementa. Desde Java 8
pueden tener default methods (implementación heredable) y
static methods (factorías), pero no pueden tener estado de instancia.
// Interfaz: contrato puro + default methods desde Java 8
public interface Comparable<T> {
int compareTo(T otro); // abstracto: obliga a implementar
}
public interface Serializable {
// sin métodos — solo marca semántica (marker interface)
}
// Java 8: puede tener métodos con implementación
public interface Coleccion<E> {
void agregar(E elemento); // abstracto
int size(); // abstracto
default boolean isEmpty() { // default: implementación opcional
return size() == 0;
}
static <E> Coleccion<E> vacia() { // static factory method
return new ColeccionVacia<>();
}
} Clases abstractas
Una clase abstracta es una clase que no puede instanciarse directamente. Puede combinar métodos abstractos (sin implementar) con métodos concretos, constructores y estado. El patrón Template Method — definir el esqueleto de un algoritmo dejando pasos a las subclases — es el uso más habitual.
// Clase abstracta: esqueleto de implementación con estado compartido
public abstract class ConexionBBDD {
protected final String url;
protected Connection connection; // estado compartido entre subclases
protected ConexionBBDD(String url) {
this.url = url;
}
// Método abstracto: las subclases definen cómo abrir la conexión
protected abstract Connection abrirConexion() throws SQLException;
// Template method: define el algoritmo, delega pasos a subclases
public final void conectar() throws SQLException {
System.out.println("Conectando a " + url);
connection = abrirConexion(); // delegado a la subclase
configurarConexion();
}
protected void configurarConexion() {
// implementación por defecto: no hace nada
// las subclases pueden sobreescribir si necesitan configurar
}
} Diferencias clave
// INTERFACES: qué no pueden hacer (antes de Java 8)
// - No pueden tener estado (campos de instancia)
// - No pueden tener constructores
// - Los campos son implícitamente public static final (constantes)
// INTERFACES: qué pueden desde Java 8
// - Default methods (implementación con 'default')
// - Static methods
// CLASES ABSTRACTAS: qué pueden que las interfaces no
// - Estado (campos de instancia)
// - Constructores
// - Campos con cualquier modificador de acceso
// - Múltiples niveles de herencia
// HERENCIA MÚLTIPLE:
// Una clase puede implementar N interfaces pero extender solo 1 clase abstracta
class MiClase extends ClaseAbstracta implements InterfazA, InterfazB { ... } Cuándo usar cada uno
// Cuándo usar interfaz:
// → Contrato sin implementación que múltiples tipos no relacionados deben cumplir
// → Herencia múltiple de tipo (una clase puede implementar varias)
// → API pública que evolucionará sin romper implementaciones existentes (default methods)
public interface Exportable {
byte[] exportar(Formato formato);
default byte[] exportarCSV() {
return exportar(Formato.CSV);
}
}
// Cuándo usar clase abstracta:
// → Jerarquía de herencia con estado compartido
// → Template Method pattern: algoritmo fijo con pasos variables
// → Cuando las subclases comparten código de implementación sustancial
public abstract class InformeBase {
private final String titulo;
protected InformeBase(String titulo) { this.titulo = titulo; }
public final String generar() {
return encabezado() + cuerpo() + pie();
}
protected String encabezado() { return titulo + "\n"; }
protected abstract String cuerpo();
protected String pie() { return "---\n"; }
}