CodeGym /Cursos /JAVA 25 SELF /Uso de super: llama...

Uso de super: llamada al constructor y a los métodos de la clase base

JAVA 25 SELF
Nivel 17 , Lección 2
Disponible

1. Uso de super para llamar a métodos de la clase base

Cuando creas una subclase, a veces surge la necesidad de acceder a campos o métodos de la clase base, especialmente si los has sobrescrito o los has «ensombrecido» (ocultado) en la subclase. Para ello, en Java existe la palabra clave especial — super.

Si lo pensamos con una analogía, super es como «¡mamá, ayúdame!», cuando en la subclase quieres referirte explícitamente a lo que está definido en el padre.

Imagina que tienes una clase Animal con un método eat(), que simplemente imprime "El animal come". Y en la clase Cat quieres que el gato primero haga algo propio (por ejemplo, maullar) y luego igualmente ejecute el estándar «el animal come». Ahí es donde viene bien super.eat().

Cuando en la subclase sobrescribes un método, pero aun así quieres invocar dentro de él la implementación de ese método de la clase base, utiliza super.nombreDelMetodo().

Ejemplo: ampliamos el comportamiento

class Animal {
    void eat() {
        System.out.println("El animal come");
    }
}

class Cat extends Animal {
    @Override
    void eat() {
        System.out.println("El gato huele la comida...");
        super.eat(); // llamamos al método eat() de Animal
        System.out.println("El gato ronronea satisfecho");
    }
}

¿Cómo funciona?

  • Cuando se llama a eat() en un objeto de tipo Cat, primero se ejecuta el código de Cat.eat(), es decir, su propio método.
  • Dentro de este método invocamos explícitamente super.eat(), es decir, la implementación de la clase padre Animal.
  • Esto permite añadir comportamiento adicional sin olvidar el del «padre».

Práctica: úsalo en una aplicación

Supongamos que en nuestra aplicación de aprendizaje hay una clase base Animal y las subclases Dog y Cat. Queremos que al alimentar a un animal se ejecuten tanto las acciones comunes (por ejemplo, aumentar la saciedad) como las específicas de cada animal.

class Animal {
    int satiety = 0;

    void eat() {
        satiety += 10;
        System.out.println("El animal come. Saciedad: " + satiety);
    }
}

class Dog extends Animal {
    @Override
    void eat() {
        System.out.println("El perro mueve la cola antes de comer");
        super.eat();
    }
}

Ahora, si llamas a dog.eat(), verás ambos mensajes y satiety aumentará correctamente.

2. Uso de super para acceder a los campos de la clase base

Si en la subclase declaras un campo con el mismo nombre que en la clase padre, este «ensombrece» el campo del padre. A veces necesitas acceder al campo original de la clase base — para ello sirve super.nombreDelCampo.

Ejemplo: ensombrecimiento de un campo

class Animal {
    String name = "Animal";
}

class Cat extends Animal {
    String name = "Gato";

    void printNames() {
        System.out.println("Nombre desde Cat: " + name);
        System.out.println("Nombre desde Animal: " + super.name);
    }
}

La llamada new Cat().printNames(); mostrará:

Nombre desde Cat: Gato
Nombre desde Animal: Animal

En la práctica real no se recomienda «ensombrecer» campos salvo necesidad extrema, pero conviene conocer esta posibilidad.

3. Llamada al constructor de la clase base mediante super(...)

¿Cómo se crean los objetos en una jerarquía?

Cuando creas un objeto de una subclase, primero se invoca el constructor de la clase base y solo después el de la subclase. Esto es necesario para que todos los campos se inicialicen correctamente, pues la subclase «hereda» parte del estado del padre.

Llamada explícita al constructor de la clase base

Si la clase base tiene un constructor sin parámetros, todo es sencillo: Java lo llamará automáticamente antes de ejecutar el constructor de la subclase. Pero si el padre no tiene constructor sin parámetros, estás obligado a invocar explícitamente el constructor adecuado mediante super(...).

Ejemplo:

class Animal {
    String name;

    Animal(String name) {
        this.name = name;
        System.out.println("Se ha creado un animal: " + name);
    }
}

class Cat extends Animal {
    Cat(String name) {
        super(name); // ¡obligatorio! No hay constructor Animal() sin parámetros
        System.out.println("Se ha creado un gato: " + name);
    }
}

La llamada new Cat("Murka") imprimirá:

Se ha creado un animal: Murka
Se ha creado un gato: Murka

Importante: La llamada al constructor del padre mediante super(...) debe ser la primera línea del constructor de la subclase. Si intentas escribir algo antes de esa llamada, el compilador se quejará y te lo recordará.

¿Y si no lo llamas explícitamente?
Si el padre solo tiene constructores con parámetros y no lo has llamado explícitamente mediante super(...), el compilador dará el error: "constructor Animal in class Animal cannot be applied to given types".

4. Detalles útiles

¿Cuándo usar super?

Para ampliar, no para sustituir, el comportamiento.
A veces no quieres reemplazar por completo el comportamiento de un método, sino solo «ampliarlo». Por ejemplo, añadir algo antes o después de la lógica del padre. En esos casos usa super.nombreDelMetodo() dentro del método sobrescrito.

Para inicializar campos heredados.
Si el padre tiene campos obligatorios para su inicialización (por ejemplo, el nombre del animal), llama al constructor del padre con los parámetros necesarios mediante super(...).

Para acceder a campos/métodos ocultos.
Si por alguna razón has «ensombrecido» un campo o método del padre y aun así necesitas acceder a él, usa super.nombreDelCampo o super.nombreDelMetodo().

Limitaciones y particularidades del uso de super

  • La llamada al constructor del padre mediante super(...) solo puede hacerse dentro de un constructor y únicamente como primera línea.
  • No se puede invocar el constructor del padre fuera del constructor de la subclase.
  • Si no llamas a super(...) explícitamente, Java intentará invocar el constructor sin parámetros del padre (si existe).
  • La palabra clave super no puede usarse en métodos estáticos — solo en métodos no estáticos (de instancia) y en constructores.
  • Si un método o campo del padre es private, super no ayuda: no hay acceso a los miembros privados.

5. Ejemplos para afianzar

Ejemplo 1. Ampliamos un método con super

class Animal {
    void makeSound() {
        System.out.println("El animal emite un sonido");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        super.makeSound(); // primero hacemos la acción estándar
        System.out.println("El perro ladra: ¡Guau, guau!");
    }
}

Ejemplo 2. Llamada al constructor de la clase base

class Vehicle {
    String brand;

    Vehicle(String brand) {
        this.brand = brand;
        System.out.println("Vehículo: " + brand);
    }
}

class Car extends Vehicle {
    int year;

    Car(String brand, int year) {
        super(brand); // llamamos al constructor del padre
        this.year = year;
        System.out.println("Coche " + brand + ", año: " + year);
    }
}
Car car = new Car("Toyota", 2023);
// Salida:
// Vehículo: Toyota
// Coche Toyota, año: 2023

Ejemplo 3. Error clásico: olvidaste llamar a super(...)

class Animal {
    String name;

    Animal(String name) {
        this.name = name;
    }
}

class Cat extends Animal {
    Cat() {
        // super(); // ¡Error! No hay constructor Animal() sin parámetros
        // Hay que llamar explícitamente a super(name)
        super("Gato sin nombre");
    }
}

6. Errores típicos al trabajar con super

Error n.º 1: llamar a super(...) no como primera línea del constructor.
Java exige estrictamente que la llamada al constructor del padre mediante super(...) sea la primera línea del constructor de la subclase. Si intentas hacer algo antes de esa llamada (por ejemplo, imprimir un mensaje), el compilador dará un error.

Error n.º 2: no hay un constructor adecuado en el padre.
Si la clase base no tiene un constructor sin parámetros y no has llamado a otro constructor mediante super(...), el compilador no podrá generar la llamada por defecto y lo notificará con un error.

Error n.º 3: intentar acceder a miembros privados del padre mediante super.
La palabra clave super no da acceso mágico a campos o métodos privados del padre. Si algo está declarado como private, permanece inaccesible para la subclase.

Error n.º 4: ensombrecer campos y métodos sin entenderlo.
Si has declarado en la subclase un campo o método con el mismo nombre que en el padre y te olvidas de ello, pueden aparecer resultados inesperados. Recuerda siempre que, en ese caso, el acceso al miembro del padre —solo a través de super.

Error n.º 5: usar super en un método estático.
No se puede usar super en métodos estáticos, porque no pertenecen a un objeto concreto.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION