Sobrecarga y sobreescritura

Resolución en tiempo de compilación frente a ejecución

Sobrecarga (overloading)

Definir varios métodos con el mismo nombre pero distintos tipos o número de parámetros. El compilador decide cuál invocar en tiempo de compilación basándose en el tipo estático de los argumentos. No interviene la JVM.

// Sobrecarga (overloading): mismo nombre, distintos parámetros — se resuelve en COMPILACIÓN
public class Calculadora {
    public int sumar(int a, int b) { return a + b; }
    public double sumar(double a, double b) { return a + b; }
    public int sumar(int a, int b, int c) { return a + b + c; }
    public String sumar(String a, String b) { return a + b; } // concatenación
}

Calculadora c = new Calculadora();
c.sumar(1, 2);       // → int sumar(int, int)     — decidido por el compilador
c.sumar(1.0, 2.0);   // → double sumar(double, double)
c.sumar("a", "b");   // → String sumar(String, String)

Sobreescritura (overriding)

Redefinir en una subclase un método de la superclase con la misma firma. La JVM decide en tiempo de ejecución qué implementación invocar según el tipo real del objeto (dynamic dispatch o virtual dispatch). Es el mecanismo que hace funcionar el polimorfismo.

// Sobreescritura (overriding): misma firma, nueva implementación — se resuelve en EJECUCIÓN
public class Animal {
    public String sonido() { return "..."; }
}

public class Gato extends Animal {
    @Override                                // anotación recomendada: el compilador verifica
    public String sonido() { return "miau"; }
}

public class Perro extends Animal {
    @Override
    public String sonido() { return "guau"; }
}

// El tipo estático es Animal, pero la JVM invoca el método del tipo real
Animal a1 = new Gato();
Animal a2 = new Perro();
a1.sonido(); // "miau" — dynamic dispatch
a2.sonido(); // "guau"

La trampa: sobrecarga no es polimórfica

El error más común es asumir que la sobrecarga se resuelve por el tipo real del objeto (como la sobreescritura). No es así: la sobrecarga usa el tipo estático declarado en la variable, no el tipo real en tiempo de ejecución.

// Trampa clásica: sobrecarga + polimorfismo
public class EjemploContraintuitivo {
    public static void imprimir(Object o)  { System.out.println("Object"); }
    public static void imprimir(String s)  { System.out.println("String"); }
}

Object obj = "hola"; // tipo estático: Object; tipo real: String
EjemploContraintuitivo.imprimir(obj); // → "Object" (la sobrecarga se resuelve en compilación)

// Compara con sobreescritura:
Animal a = new Gato();
a.sonido(); // → "miau" (la sobreescritura se resuelve en ejecución)

Reglas de sobreescritura válida

// Reglas de sobreescritura válida:
// 1. La firma (nombre + tipos de parámetros) debe ser idéntica
// 2. El tipo de retorno puede ser covariante (subtipo del original)
// 3. El modificador de acceso no puede ser más restrictivo
// 4. No puede declarar checked exceptions nuevas (solo las del padre o sus subtipos)

public class Base {
    public Animal crearAnimal() { return new Animal("base"); }
    protected void metodo() throws IOException { }
}

public class Derivada extends Base {
    @Override
    public Perro crearAnimal() { return new Perro("derivada"); } // OK: Perro es subtipo de Animal

    @Override
    public void metodo() throws FileNotFoundException { } // OK: FileNotFoundException extends IOException
}

Impedir sobreescritura: final

// final: impide sobreescritura
public class Segura {
    public final void operacionCritica() {
        // nadie puede sobreescribir esto
    }
}

// Una clase final no puede extenderse (String, Integer son final)
public final class Inmutable {
    private final String valor;
    public Inmutable(String v) { this.valor = v; }
    public String getValor() { return valor; }
}
Resumen: sobrecarga = mismo nombre, distintos parámetros, resuelto en compilación. Sobreescritura = misma firma, nueva implementación en subclase, resuelto en ejecución. Usa @Override siempre — si la firma no coincide exactamente, el compilador avisa en lugar de crear silenciosamente una sobrecarga accidental.

Siguiente apartado → Default methods en interfaces

Índice de la sección

Índice del curso