Die kurze Antwort lautet: Es ist durchaus möglich, aber Java tut es nicht.
Hier ist ein Code, der den aktuellen Stand der Dinge in Java veranschaulicht :
Datei 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();
}
}
Datei 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();
}
}
Wenn Sie dies ausführen (ich habe es auf einem Mac von Eclipse mit Java 1.6 ausgeführt), erhalten Sie:
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.
Hier scheinen die einzigen Fälle, die eine Überraschung sein könnten (und um die es in der Frage geht), der erste Fall zu sein:
"Der Laufzeittyp wird nicht verwendet, um zu bestimmen, welche statischen Methoden aufgerufen werden, selbst wenn sie mit einer Objektinstanz ( obj.staticMethod()
) aufgerufen werden ."
und der letzte Fall:
"Wenn Sie eine statische Methode aus einer Objektmethode einer Klasse aufrufen, wird die statische Methode ausgewählt, auf die von der Klasse selbst zugegriffen werden kann, und nicht von der Klasse, die den Laufzeittyp des Objekts definiert."
Aufruf mit einer Objektinstanz
Der statische Aufruf wird zur Kompilierungszeit aufgelöst, während ein nicht statischer Methodenaufruf zur Laufzeit aufgelöst wird. Beachten Sie, dass statische Methoden zwar vom Elternteil geerbt werden, aber nicht vom Kind überschrieben werden. Dies könnte eine Überraschung sein, wenn Sie etwas anderes erwartet haben.
Aufruf aus einer Objektmethode heraus
Objektmethodenaufrufe werden unter Verwendung des Laufzeittyps aufgelöst, statische ( Klassen- ) Methodenaufrufe werden jedoch unter Verwendung des Typs zur Kompilierungszeit (deklariert) aufgelöst.
Regeln ändern
Um diese Regeln so zu ändern, dass beim letzten Aufruf im aufgerufenen Beispiel Child.printValue()
statische Aufrufe zur Laufzeit mit einem Typ versehen werden müssen, anstatt dass der Compiler den Aufruf zur Kompilierungszeit mit der deklarierten Klasse des Objekts (oder) auflöst Kontext). Statische Aufrufe könnten dann die (dynamische) Typhierarchie verwenden, um den Aufruf aufzulösen, so wie es Objektmethodenaufrufe heute tun.
Dies wäre leicht machbar (wenn wir Java: -O ändern würden) und ist keineswegs unvernünftig, hat jedoch einige interessante Überlegungen.
Die Hauptüberlegung ist, dass wir entscheiden müssen, welche statischen Methodenaufrufe dies tun sollen.
Im Moment hat Java diese "Eigenart" in der Sprache, in der obj.staticMethod()
Anrufe durch ObjectClass.staticMethod()
Anrufe ersetzt werden (normalerweise mit einer Warnung). [ Hinweis: ObjectClass
ist der Typ zur Kompilierungszeit von obj
.] Dies wären gute Kandidaten, um auf diese Weise den Laufzeittyp von zu überschreiben obj
.
Wenn wir dies tun würden, wäre das Lesen von Methodenkörpern schwieriger: Statische Aufrufe in einer übergeordneten Klasse könnten möglicherweise dynamisch "umgeleitet" werden. Um dies zu vermeiden, müssten wir die statische Methode mit einem Klassennamen aufrufen - und dies macht die Aufrufe mit der Hierarchie des Typs zur Kompilierungszeit (wie jetzt) offensichtlicher aufgelöst.
Die anderen Möglichkeiten zum Aufrufen einer statischen Methode sind schwieriger: Sie this.staticMethod()
sollten dasselbe bedeuten wie obj.staticMethod()
die Verwendung des Laufzeit-Typs von this
. Dies kann jedoch zu Kopfschmerzen bei vorhandenen Programmen führen, die (anscheinend lokale) statische Methoden ohne Dekoration aufrufen (was wohl gleichbedeutend ist mit this.method()
).
Was ist also mit schmucklosen Anrufen staticMethod()
? Ich schlage vor, dass sie dasselbe tun wie heute und den lokalen Klassenkontext verwenden, um zu entscheiden, was zu tun ist. Andernfalls würde große Verwirrung entstehen. Natürlich bedeutet dies , dass method()
würde bedeuten , this.method()
wenn method
eine nicht-statische Methode war, und ThisClass.method()
wenn method
eine statische Methode war. Dies ist eine weitere Quelle der Verwirrung.
Andere Überlegungen
Wenn wir dieses Verhalten geändert (und machte einen statischen Aufruf potenziell dynamisch nicht-lokal), würden wir wahrscheinlich wollen die Bedeutung zu überdenken final
, private
und protected
als Qualifier auf static
Methoden einer Klasse. Wir müssten uns dann alle daran gewöhnen, dass private static
und public final
Methoden nicht überschrieben werden und daher zur Kompilierungszeit sicher aufgelöst werden können und als lokale Referenzen "sicher" zu lesen sind.