Palabra clave super en Java
Referencia la clase padre en Java con super: llama constructores y métodos sobreescritos del padre.
super es el complemento de this para la clase padre. Donde this es "el objeto actual", super es "el objeto actual, visto como su superclase." Solo tiene significado dentro de una clase que extiende otra, y aparece en tres lugares:
super(args)dentro de un constructor — llama a un constructor del padre.super.method(args)dentro de un método de instancia — llama a la versión del padre de un método sobreescrito.super.fielddentro de un método de instancia — lee un campo del padre que la subclase oculta.
El primero es con mucho el más común.
super(...) — llamar a un constructor del padre
Cada constructor de subclase debe comenzar llamando a algún constructor del padre. Si no escribes uno, Java inserta super(); como primera línea — una llamada al constructor sin argumentos del padre:
public class Animal {
String name;
public Animal() { name = "(unnamed)"; } // no-arg
}
public class Cat extends Animal {
public Cat() {
// super(); ← inserted by the compiler
}
}Cuando el padre no tiene constructor sin argumentos, debes llamar a uno explícitamente:
public class Animal {
String name;
public Animal(String name) { this.name = name; } // no no-arg constructor
}
public class Cat extends Animal {
public Cat(String name) {
super(name); // required — there is no Animal()
}
}El error más común en herencia es olvidar esto. Cuando un padre no tiene constructor sin argumentos, el compilador igual intenta insertar super(); en cualquier constructor de subclase que no llame a super(...) explícitamente — y entonces falla con "there is no default constructor available in Animal". La solución es añadir una llamada explícita a super(...) que coincida con un constructor real del padre.
Reglas para super(...):
- Debe ser la primera instrucción en el cuerpo del constructor.
- Un constructor puede encadenar a otro constructor de la misma clase con
this(...)o llamar al padre consuper(...)— no ambos. - Los argumentos deben coincidir con un constructor existente del padre.
¿Por qué la regla de "primera instrucción"?
La JVM debe construir completamente la parte del padre en el objeto antes de que se ejecute cualquier código de la subclase. Eso incluye inicializar los campos final que declara el padre. Permitir que el código de la subclase se ejecute primero significaría leer esos campos antes de que se les hayan asignado sus valores.
super.method(args) — llamar a la versión del padre
Dentro de un método de instancia, super.method(...) llama a la versión del padre de method, incluso si la clase actual lo ha sobreescrito:
public class Animal {
String speak() { return "(some noise)"; }
}
public class Cat extends Animal {
@Override
String speak() {
return super.speak() + " — actually, meow";
// ^^^^^^^^^^^^^ calls Animal.speak(), not Cat.speak()
}
}
new Cat().speak(); // "(some noise) — actually, meow"Sin super., un simple speak() dentro de Cat.speak se llamaría a sí mismo y recurriría infinitamente.
El patrón clásico es extender el comportamiento del padre en lugar de reemplazarlo:
@Override
void onSave() {
super.onSave(); // run parent's save logic first
// then add subclass-specific behavior
}super.method(...) no puede llegar dos niveles hacia arriba — no existe super.super.method() en Java. Si tu clase extiende una clase que extiende otra, puedes llamar al método de tu padre inmediato, no al de tu abuelo.
super.field — acceder a un campo oculto
Si una subclase declara un campo con el mismo nombre que el campo de un padre, el campo de la subclase oculta al del padre:
public class A {
String label = "A's label";
}
public class B extends A {
String label = "B's label";
void show() {
System.out.println(label); // B's label
System.out.println(super.label); // A's label
System.out.println(this.label); // B's label
}
}Esto es casi siempre un mal diseño — tener dos campos con el mismo nombre en un par padre-hijo es confuso — pero el lenguaje te da super.field para desambiguar cuando ocurre. La solución más limpia es renombrar uno de los campos.
Ten en cuenta que los campos no son polimórficos. A diferencia de los métodos sobreescritos, el acceso a campos se decide en tiempo de compilación según el tipo declarado de la referencia. El capítulo de polimorfismo explica por qué.
super y static
super solo existe en contextos de instancia, como this. No puedes escribir super en un método static o inicializador — no hay objeto actual, por lo que tampoco hay vista del padre. Para llamar a un método estático declarado en el padre, califícalo con el nombre de la clase del padre:
public class A { static void hi() { System.out.println("hi"); } }
public class B extends A {
static void demo() {
A.hi(); // ok — call by class name
// super.hi(); // ERROR — super in a static context
}
}Una subclase también puede declarar un método static con el mismo nombre que el método static de un padre — esto se llama ocultamiento de método, no sobreescritura, y sigue las reglas en tiempo de compilación. Se trata brevemente en el capítulo de sobreescritura de métodos.
Cadenas de super
Cada llamada super(...) activa la siguiente capa de la cadena de herencia. Rastreando lo que se ejecuta para una subclase profundamente anidada:
new SiameseCat("Lulu")
→ SiameseCat(String)
→ super("Lulu") — Cat(String)
→ super("Lulu") — Animal(String)
→ super() — Object()
→ Animal body runs
→ Cat body runs
→ SiameseCat body runsLa inicialización siempre procede desde el ancestro más lejano hasta la clase actual. Para cuando se ejecuta el cuerpo de SiameseCat, todos los campos del padre están completamente inicializados.
Un ejemplo práctico
¿Qué sigue?
super es el puente hacia la clase padre, pero la idea más amplia que habilita es el polimorfismo — la capacidad de llamar a un método en una referencia de tipo padre y que se despache a la implementación correcta de la subclase en tiempo de ejecución. Ese es el siguiente capítulo. Continúa con polimorfismo en Java.