W3docs

Le mot-clé super en Java

Référencez la classe parente en Java avec super — appel des constructeurs parents et des méthodes redéfinies.

super est le pendant de this pour la classe parente. Là où this désigne "l'objet courant", super désigne "l'objet courant, vu comme son superclasse." Il n'a de sens qu'à l'intérieur d'une classe qui étend une autre, et il apparaît dans trois situations :

  1. super(args) dans un constructeur — appeler un constructeur parent.
  2. super.method(args) dans une méthode d'instance — appeler la version parente d'une méthode redéfinie.
  3. super.field dans une méthode d'instance — lire un champ parent masqué par la sous-classe.

La première est de loin la plus courante.

super(...) — appel d'un constructeur parent

Chaque constructeur de sous-classe doit commencer par appeler un constructeur parent. Si vous n'en écrivez pas, Java insère super(); en première ligne — un appel au constructeur sans argument du parent :

public class Animal {
  String name;
  public Animal() { name = "(unnamed)"; }     // no-arg
}

public class Cat extends Animal {
  public Cat() {
    // super();  ← inserted by the compiler
  }
}

Lorsque le parent ne possède pas de constructeur sans argument, vous devez en appeler un explicitement :

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()
  }
}
Avertissement

L'erreur la plus fréquente liée à l'héritage est d'oublier cela. Lorsqu'un parent n'a pas de constructeur sans argument, le compilateur essaie quand même d'insérer super(); dans tout constructeur de sous-classe qui n'appelle pas super(...) explicitement — et échoue avec "there is no default constructor available in Animal". La correction consiste à ajouter un appel super(...) explicite qui correspond à un vrai constructeur parent.

Règles pour super(...) :

  • Il doit être la première instruction du corps du constructeur.
  • Un constructeur peut soit se chaîner à un autre constructeur de la même classe avec this(...) soit appeler le parent avec super(...) — pas les deux.
  • Les arguments doivent correspondre à un constructeur parent existant.

Pourquoi la règle "première instruction" ?

La JVM doit entièrement construire la partie parente de l'objet avant l'exécution de tout code de sous-classe. Cela inclut l'initialisation des champs final déclarés par le parent. Autoriser l'exécution du code de la sous-classe en premier signifierait lire ces champs avant qu'ils aient reçu leurs valeurs.

super.method(args) — appeler la version parente

Dans une méthode d'instance, super.method(...) appelle la version parente de method, même si la classe courante l'a redéfinie :

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"

Sans super., un simple speak() dans Cat.speak s'appellerait lui-même et recurserait indéfiniment.

Le schéma classique consiste à étendre le comportement du parent plutôt qu'à le remplacer :

@Override
void onSave() {
  super.onSave();      // run parent's save logic first
  // then add subclass-specific behavior
}

super.method(...) ne peut pas remonter deux niveaux — il n'existe pas de super.super.method() en Java. Si votre classe étend une classe qui en étend une autre, vous pouvez appeler la méthode de votre parent immédiat, mais pas celle de votre grand-parent.

super.field — accéder à un champ masqué

Si une sous-classe déclare un champ portant le même nom qu'un champ du parent, le champ de la sous-classe masque celui du parent :

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
  }
}

C'est presque toujours une mauvaise conception — avoir deux champs avec le même nom dans une paire parent-enfant est source de confusion — mais le langage vous offre super.field pour lever l'ambiguïté quand cela se produit. La solution plus propre est de renommer l'un des champs.

Notez que les champs ne sont pas polymorphes. Contrairement aux méthodes redéfinies, l'accès aux champs est déterminé à la compilation en fonction du type déclaré de la référence. Le chapitre sur le polymorphisme explique pourquoi.

super et static

super n'existe que dans les contextes d'instance, comme this. Vous ne pouvez pas utiliser super dans une méthode ou un initialiseur static — il n'y a pas d'objet courant, donc pas de vue parente non plus. Pour appeler une méthode statique déclarée sur le parent, qualifiez-la avec le nom de la classe parente :

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
  }
}

Une sous-classe peut également déclarer une méthode static portant le même nom qu'une méthode static du parent — c'est ce qu'on appelle le masquage de méthode, et non la redéfinition, et cela suit les règles de compilation. Ce point est abordé brièvement dans le chapitre sur la redéfinition de méthode.

Chaînes de super

Chaque appel super(...) active la couche suivante de la chaîne d'héritage. Le traçage de ce qui s'exécute pour une sous-classe profondément imbriquée :

new SiameseCat("Lulu")
  → SiameseCat(String)
      → super("Lulu")        — Cat(String)
          → super("Lulu")    — Animal(String)
              → super()      — Object()
              → Animal body runs
          → Cat body runs
      → SiameseCat body runs

L'initialisation progresse toujours de l'ancêtre le plus éloigné jusqu'à la classe courante. Au moment où le corps de SiameseCat s'exécute, tous les champs parents sont entièrement initialisés.

Exemple concret

java— editable, runs on the server

Prochaine étape

super est le pont vers la classe parente, mais la grande idée qu'il permet est le polymorphisme — la capacité d'appeler une méthode sur une référence de type parent et de la voir dispatcher vers la bonne implémentation de sous-classe à l'exécution. C'est le prochain chapitre. Continuer vers le polymorphisme Java.

Pratique

Pratique
Dans un constructeur, quand le compilateur insère-t-il implicitement super() ?
Dans un constructeur, quand le compilateur insère-t-il implicitement super() ?
Was this page helpful?