Краткий ответ: это вполне возможно, но 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.
Здесь, только дела, которые могут быть неожиданностью (и о чем вопрос), представляются как first дело:
"Тип времени выполнения не используется для определения того, какие статические методы вызываются, даже если они вызваны с экземпляром объекта (obj.staticMethod()
)."
и последний кейс:
"При вызове статического метода из метода объекта класса выбран статический метод, доступный из самого класса, а не из класса, определяющего тип времени выполнения объекта . "
Вызов с экземпляром объекта
Статический вызов разрешается во время компиляции, тогда как вызов нестатического метода разрешается во время выполнения. Обратите внимание, что хотя статические методы наследуются (от родителя), они не переопределяются (дочерними). Это может быть сюрпризом, если вы ожидаете иначе.
Вызов изнутри метода объекта
Объектные вызовы методов разрешаются с использованием типа времени выполнения, но статические ( class ) вызовы методов разрешаются с использованием типа времени компиляции (объявленного).
Изменение правил
Чтобы изменить эти правила, чтобы последний вызов в примере с именем 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
не переопределяются и поэтому могут быть безопасно разрешены во время компиляции и «безопасны» для чтения как локальные ссылки.