Короткий ответ: это вполне возможно, но Java этого не делает.
Вот некоторый код, который иллюстрирует текущее состояние дел в Java:
Файл 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();
}
}
Файл 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();
}
}
Если вы запустите это (я сделал это на Mac, из Eclipse, используя Java 1.6), вы получите:
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.
Здесь единственные случаи, которые могут быть неожиданностью (и о чем идет речь), являются первым случаем:
«Тип времени выполнения не используется для определения того, какие статические методы вызываются, даже когда они вызываются с помощью экземпляра объекта ( obj.staticMethod()
)».
и последний случай:
«При вызове статического метода из метода объекта класса выбран статический метод, доступный из самого класса, а не из класса, определяющего тип времени выполнения объекта».
Вызов с экземпляром объекта
Статический вызов разрешается во время компиляции, тогда как вызов нестатического метода разрешается во время выполнения. Обратите внимание, что хотя статические методы наследуются (от родителя), они не переопределяются (дочерними). Это может быть сюрпризом, если вы ожидаете иначе.
Вызов из метода объекта
Вызовы методов объекта разрешаются с использованием типа времени выполнения, но вызовы статических ( классовых ) методов разрешаются с использованием типа времени объявления (объявленного).
Изменение правил
Чтобы изменить эти правила, чтобы при последнем вызове в вызываемом примере Child.printValue()
статические вызовы должны были быть предоставлены с типом во время выполнения, а не компилятором, разрешающим вызов во время компиляции с объявленным классом объекта (или контекст). Статические вызовы могут затем использовать (динамическую) иерархию типов для разрешения вызова, так же, как вызовы объектных методов делают сегодня.
Это легко выполнимо (если мы изменили Java: -O), и это вовсе не неразумно, однако, у него есть некоторые интересные соображения.
Основное соображение заключается в том, что нам нужно решить, какие статические вызовы методов должны делать это.
На данный момент в Java есть такая «причуда» в языке, при которой obj.staticMethod()
вызовы заменяются ObjectClass.staticMethod()
вызовами (обычно с предупреждением). [ Примечание: ObjectClass
это тип времени компиляции obj
.] Это были бы хорошие кандидаты для переопределения таким способом, принимая тип времени выполнения obj
.
Если бы мы сделали это, это бы затруднило чтение тел методов: статические вызовы в родительском классе потенциально могли бы быть динамически «перенаправлены». Чтобы избежать этого, нам пришлось бы вызывать статический метод с именем класса - и это делает вызовы более очевидно разрешенными с помощью иерархии типов времени компиляции (как сейчас).
Другие способы вызова статического метода более хитры: они this.staticMethod()
должны означать то же самое obj.staticMethod()
, что и тип во время выполнения this
. Однако это может вызвать некоторые проблемы с существующими программами, которые вызывают (очевидно локальные) статические методы без декорации (что, возможно, эквивалентно this.method()
).
Так что насчет неукрашенных звонков staticMethod()
? Я предлагаю сделать то же самое, что и сегодня, и использовать контекст локального класса, чтобы решить, что делать. В противном случае возникнет великое замешательство. Конечно, это означает, что method()
это означало this.method()
бы, если бы method
был нестатический метод, и ThisClass.method()
если бы method
был статический метод. Это еще один источник путаницы.
Другие соображения
Если мы изменили это поведение (и сделали статические вызовы потенциально динамически нелокальным), мы, вероятно , захотите пересмотреть смысл final
, private
а protected
также отборочные на static
методах класса. Тогда нам всем придется привыкнуть к тому факту, что private static
и public final
методы не переопределяются и поэтому могут быть безопасно разрешены во время компиляции и «безопасны» для чтения как локальные ссылки.