Да, вы можете вызвать метод 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
.Цитата из руководства :
Так когда же следует использовать статический импорт? Очень экономно! Используйте его только тогда, когда у вас возникнет искушение объявить локальные копии констант или злоупотребить наследованием (Антипаттерн Constant Interface).Другими словами, используйте его, когда вам требуется частый доступ к статическим членам одного или двух классов. Если вы чрезмерно используете функцию статического импорта, она может сделать вашу программу нечитаемой и не поддерживаемой , загрязняя ее пространство имен всеми 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
, верно?
НЕПРАВИЛЬНО!static
метод не может быть переопределен!Это может быть скрыто только подклассом!Фактически, если вы попытаетесь сделать правильную вещь и добавить аннотацию @Override
к task2
, она не будет компилироваться!
From JLS 15.12.4.4 Метод Locate для вызова :
Если режим вызова static
, ссылка на цель не требуется и переопределение не допускается.Метод m класса T - это тот, который должен быть вызван.
Фактически эта проблема рассматривается в Java Puzzlers Головоломка 48: Все, что я получаю, статично.Вывод, приведенный в конце головоломки, таков:
В общем, квалифицируйте static
вызовы методов с именем класса или не квалифицируйте их вообще, если вы вызываете их изв своем собственном классе, но никогда не квалифицируйте их выражением.Также избегайте сокрытия статических методов.Вместе эти рекомендации помогают устранить ложное представление о переопределении с помощью динамической диспетчеризации для статических методов.
Лучше всего следовать всем этим рекомендациям вместе, поэтому:
- Если выВы вызываете метод
static
в своем собственном классе, не квалифицируйтесь - В противном случае, квалифицируйтесь с именем класса
- Если вы делаете это много в одном классе, подумайте
static import
этого конкретного метода - Старайтесь не
static import
всех членов с *
- Никогда не подходите с выражением
- Не скрывайте метод
static
;Вы не можете @Override
это, это только вызовет путаницу
См. также: