Blog

Pourquoi « super » ne peut pas être une « référence à la superclasse » ?

D’après ce que j’entends ou lis autour de moi, il semble que beaucoup de gens se contentent d’accepter cette affirmation : ‘super’ est une référence à la superclasse.

Malheureusement, cette définition ne tient pas une seconde. Si c’était une référence vers quelque chose, je pourrais m’en servir comme valeur dans une affectation ou en argument d’un appel.

Alors qu’est donc ce « super » ?

Personnellement, je l’appelle un « modificateur de recherche de méthode ».
En effet, il donne la possibilité à un objet de s’envoyer un message, comme avec « this », mais en modifiant le niveau où débute la recherche de la méthode dans l’arbre d’héritage.

De quel niveau exactement s’agit-il ?

Ce n’est pas clair pour tout le monde. On se contente généralement d’un vague « dans la superclasse ».
Oui, mais la superclasse de quoi ? de l’objet ? celui qui invoque la méthode ?

Pour comprendre, regardons un exemple

Deux classes A et B héritent l’une de l’autre :

public class A {
  public char m() { 
    return 'a'; 
  }
  public char thisM() { 
    return m(); 
  }
}

public class B extends A {
  @Override
  public char m() { 
    return 'b'; 
  }
  public char superM() { 
    return super.m(); 
  }
}

Effectuons quelques tests :

A a = new A();
a.m();       // -> 'a'  (l’envoi de message marche bien !)
a.thisM();   // -> 'a'  (l’envoi à « this » marche bien !)
B b = new B();
b.m();       // -> 'b'  (la redéfinition marche bien)
b.thisM();   // -> 'b'  (l’héritage marche bien)
b.superM();  // -> 'a'  (le « super » modifie la recherche de méthode vers la superclasse)

Ajoutons une sous-classe C héritant de B :

public class C extends B {
  @Override
  public char m() { 
    return 'c'; 
  }
}
C c = new C();

La question fondamentale est : « Qu’elle est la valeur de c.superM() ? »

‘a’ ou ‘b’ ?

La réponse est ‘a’ !

Eh oui, la recherche de méthode commence bien dans une superclasse, mais pas celle de l’objet receveur. Il s’agit de la superclasse de la classe où est implémentée la méthode utilisant le « super ». En d’autres termes, le « super » est une instruction de code statique, contrairement à son homologue « this » qui référence l’instance courante.

Bien entendu, ce genre de code est à proscrire car le résultat peut être surprenant et générateur de bugs difficiles à comprendre.
« Je redéfini la méthode m() mais j’obtiens toujours ‘a’ » ?!?
(une situation similaire m’avait fait perdre une bonne demi-heure dans un lointain passé où j’aidais à résoudre les problèmes des gens en Smalltalk).

En conclusion, un bon principe est qu’un « super » devrait toujours être appelé sur la même méthode que celle où il se trouve écrit.

public char m() {
  …
  super.m(); 
  …
}
Jean-Francois Lefevre

Written by

The author didnt add any Information to his profile yet

  • bon j’ai mis du temps à comprendre (car pour moi, c.superM() ne pouvait jamais renvoyer ‘b’), mais j’ai quand même compris!

    A la différence du this, le super reste « à son niveau ». Si, dans la méthode B.superM(), tu remplaces « super.m() » par « this.m() », le résultat de c.superM() est bien ‘c’. Et donc le this fait référence à une instance de C, et non de B.

    ouf

  • Bon, j’aurais préféré des chats et des poissons rouges pour l’exemple, mais sinon c’est très instructif !
    Au passage ça enlève de la crédibilité au discours car SuperM c’est le nom qu’on donnait aux supermarchés Monoprix … euh bon je sors !