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();
…
}