Ответ 2
Да, вы можете вызвать метод static
без упоминания имени класса. Там import static
(см. JLS 7.5.4 для точного механизма), но даже без него, если имя может быть разрешено (см. JLS 15.12.1 для точного механизма) без полной квалификации класса, он будет работать.
Следующий код компилирует и печатает "Hello world!"
, как ожидалось.
import static java.lang.System.out;
public class Test {
static String greeting() {
return "Hello world!";
}
public static void main(String[] args) {
out.println(greeting());
}
}
out
в инструкции println
фактически является полем доступа к static
класса java.lang.System
, а не static
, но тем не менее он имеет доступ к элементу static
. greeting()
- это вызов метода static
, и имя класса можно опустить, поскольку его ссылка может быть разрешена без полной квалификации имени.
Теперь позвольте спросить, хорошая ли это идея. Если вы не вызываете метод static
из своего класса, не рекомендуется вообще опускать имя класса!!!
Сначала сфокусируйтесь на static import
. Цитата из guide:
Итак, когда вы должны использовать статический импорт? Очень экономно! Используйте его только тогда, когда в противном случае у вас возникнет соблазн объявить локальные копии констант или злоупотреблять наследованием (Constant Interface Antipattern). Другими словами, используйте его, когда вам требуется частый доступ к статическим членам из одного или двух классов. Если вы злоупотребляете функцией статического импорта, это может сделать вашу программу нечитаемой и недостижимой, загрязняя ее пространство имен всеми членами static
, которые вы импортируете. Читатели вашего кода (включая вас, через несколько месяцев после того, как вы его написали) не будут знать, из какого класса приходит статический член. Импорт всех статических элементов из класса может быть особенно вреден для удобочитаемости; если вам нужен только один или два члена, импортируйте их отдельно. При правильном использовании статический импорт может сделать вашу программу более читаемой, удалив шаблон повторения имен классов.
В следующем примере дело усиливается:
class Base {
void task1() {
System.out.println("Base.task1");
}
static void task2() {
System.out.println("Base.task2");
}
}
class Child extends Base {
void task1() {
System.out.println("Child.task1");
}
static void task2() {
System.out.println("Child.task2");
}
}
//....
Base sweetChildOMine = new Child();
sweetChildOMine.task1(); // prints "Child.task1"
sweetChildOMine.task2(); // prints "Base.task2"
Какой сюрприз! Вы думаете, что, поскольку sweetChildOMine
имеет ссылку на экземпляр Child
, sweetChildOMine.task2()
должен печатать "Child.task2"
, потому что он переопределяется классом Child
, правильно?
НЕПРАВИЛЬНО! A static
метод нельзя переопределить! Он может быть скрыт только подклассом! На самом деле, если вы попытались сделать правильную вещь и добавили аннотацию @Override
к task2
, она не скомпилировалась бы!
От JLS 15.12.4.4 Найдите способ для вызова:
Если режим вызова static
, целевая ссылка не требуется, и переопределение недопустимо. Метод m класса T является вызываемым.
На самом деле эта проблема рассматривается в Java Puzzlers Пазл 48: все, что я получаю, статично. Вывод, приведенный в конце головоломки, таков:
В целом, квалифицируйте static
вызовы методов с именем класса или не квалифицируйте их вообще, если вы вызываете их из своего класса, но никогда не квалифицируете их выражением. Также избегайте скрывать статические методы. Вместе эти рекомендации помогают устранить вводящий в заблуждение вид переопределения с динамической отправкой для статических методов.
Лучше всего следовать всем этим рекомендациям, поэтому:
- Если вы вызываете метод
static
в своем классе, не квалифицируйте
- В противном случае, с именем класса
- Если вы делаете это много в одном классе, рассмотрите
static import
этого конкретного метода
- Попробуйте
static import
всех членов с *
- Никогда не квалифицируйте с помощью выражения
- Не скрывайте метод
static
; вы не можете @Override
его, это вызовет только путаницу
См. также: