La réponse courte est: c'est tout à fait possible, mais Java ne le fait pas.
Voici un code qui illustre l' état actuel des choses à Java:
Fichier Base.java
:
package sp.trial;
public class Base {
static void printValue() {
System.out.println(" Called static Base method.");
}
void nonStatPrintValue() {
System.out.println(" Called non-static Base method.");
}
void nonLocalIndirectStatMethod() {
System.out.println(" Non-static calls overridden(?) static:");
System.out.print(" ");
this.printValue();
}
}
Fichier Child.java
:
package sp.trial;
public class Child extends Base {
static void printValue() {
System.out.println(" Called static Child method.");
}
void nonStatPrintValue() {
System.out.println(" Called non-static Child method.");
}
void localIndirectStatMethod() {
System.out.println(" Non-static calls own static:");
System.out.print(" ");
printValue();
}
public static void main(String[] args) {
System.out.println("Object: static type Base; runtime type Child:");
Base base = new Child();
base.printValue();
base.nonStatPrintValue();
System.out.println("Object: static type Child; runtime type Child:");
Child child = new Child();
child.printValue();
child.nonStatPrintValue();
System.out.println("Class: Child static call:");
Child.printValue();
System.out.println("Class: Base static call:");
Base.printValue();
System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
child.localIndirectStatMethod();
System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
child.nonLocalIndirectStatMethod();
}
}
Si vous exécutez ceci (je l'ai fait sur un Mac, depuis Eclipse, en utilisant Java 1.6), vous obtenez:
Object: static type Base; runtime type Child.
Called static Base method.
Called non-static Child method.
Object: static type Child; runtime type Child.
Called static Child method.
Called non-static Child method.
Class: Child static call.
Called static Child method.
Class: Base static call.
Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
Non-static calls own static.
Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
Non-static calls overridden(?) static.
Called static Base method.
Ici, les seuls cas qui pourraient être une surprise (et sur lesquels porte la question) semblent être le premier cas:
"Le type d'exécution n'est pas utilisé pour déterminer quelles méthodes statiques sont appelées, même lorsqu'il est appelé avec une instance d'objet ( obj.staticMethod()
)."
et le dernier cas:
"Lors de l'appel d'une méthode statique à partir d'une méthode objet d'une classe, la méthode statique choisie est celle accessible depuis la classe elle-même et non depuis la classe définissant le type d'exécution de l'objet."
Appel avec une instance d'objet
L'appel statique est résolu au moment de la compilation, tandis qu'un appel de méthode non statique est résolu au moment de l'exécution. Notez que bien que les méthodes statiques soient héritées (du parent), elles ne sont pas remplacées (par l'enfant). Cela pourrait être une surprise si vous vous attendiez à autre chose.
Appel depuis une méthode objet
Les appels de méthode objet sont résolus à l'aide du type d'exécution, mais les appels de méthode statique ( classe ) sont résolus à l'aide du type de compilation (déclaré).
Changer les règles
Pour modifier ces règles, de sorte que le dernier appel dans l'exemple appelé Child.printValue()
, les appels statiques doivent être fournis avec un type au moment de l'exécution, plutôt que le compilateur résolvant l'appel au moment de la compilation avec la classe déclarée de l'objet (ou le contexte). Les appels statiques pourraient alors utiliser la hiérarchie de type (dynamique) pour résoudre l'appel, tout comme les appels de méthode objet le font aujourd'hui.
Cela serait facilement réalisable (si nous changions Java: -O), et ce n'est pas du tout déraisonnable, cependant, cela a quelques considérations intéressantes.
La considération principale est que nous devons décider quels appels de méthodes statiques devraient faire cela.
À l'heure actuelle, Java a cette "bizarrerie" dans le langage où les obj.staticMethod()
appels sont remplacés par des ObjectClass.staticMethod()
appels (normalement avec un avertissement). [ Remarque: ObjectClass
est le type de compilation obj
.] Ce sont de bons candidats pour remplacer de cette manière, en prenant le type d'exécution de obj
.
Si nous le faisions, cela rendrait les corps de méthodes plus difficiles à lire: les appels statiques dans une classe parente pourraient potentiellement être "réacheminés" dynamiquement . Pour éviter cela, nous devrions appeler la méthode statique avec un nom de classe - et cela rend les appels résolus de manière plus évidente avec la hiérarchie de type à la compilation (comme maintenant).
Les autres façons d'invoquer une méthode statique sont plus délicates: this.staticMethod()
devraient signifier la même chose que obj.staticMethod()
, en prenant le type d'exécution de this
. Cependant, cela peut provoquer des maux de tête avec les programmes existants, qui appellent des méthodes statiques (apparemment locales) sans décoration (ce qui est sans doute équivalent à this.method()
).
Qu'en est-il des appels sans fioritures staticMethod()
? Je suggère qu'ils fassent de même qu'aujourd'hui et utilisent le contexte de classe local pour décider quoi faire. Sinon, une grande confusion s'ensuivrait. Bien sûr, cela signifie que method()
cela signifierait this.method()
si method
c'était une méthode non statique et ThisClass.method()
si method
c'était une méthode statique. Ceci est une autre source de confusion.
Autres considérations
Si nous changions ce comportement (et rendions des appels statiques potentiellement non locaux dynamiques), nous voudrions probablement revoir la signification de final
, private
et en protected
tant que qualificatifs sur les static
méthodes d'une classe. Nous devrons alors tous nous habituer au fait que les méthodes private static
et public final
ne sont pas remplacées et peuvent donc être résolues en toute sécurité au moment de la compilation et sont "sûres" à lire comme références locales.