Вы можете подумать о том, чтобы сделать статический метод окончательным, учитывая следующее:
Имея следующие классы:
class A {
static void ts() {
System.out.print("A");
}
}
class B extends A {
static void ts() {
System.out.print("B");
}
}
Теперь «правильный» способ вызова этих методов будет
A.ts();
B.ts();
, что приведет к AB
, но вы также можете вызывать методы для экземпляров:
A a = new A();
a.ts();
B b = new B();
b.ts();
, что также приведет к AB
.
Теперь рассмотрим следующее:
A a = new B();
a.ts();
это напечатало бы A
. Это может вас удивить, поскольку у вас есть объект класса B
. Но так как вы вызываете его из ссылки типа A
, он будет вызывать A.ts()
. Вы можете напечатать B
со следующим кодом:
A a = new B();
((B)a).ts();
В обоих случаях у вас есть объект из класса B
. Но в зависимости от указателя, который указывает на объект, вы будете вызывать метод с A
или с B
.
Теперь предположим, что вы разработчик класса A
и хотите разрешить подклассы. Но вам действительно нужен метод ts()
, когда бы он ни вызывался, даже из подкласса, то есть он делает то, что вы хотите, чтобы он не скрывался версией подкласса. Тогда вы можете сделать это final
и предотвратить его скрытие в подклассе. И вы можете быть уверены, что следующий код вызовет метод из вашего класса A
:
B b = new B();
b.ts();
Хорошо, конечно, это как-то сконструировано, но в некоторых случаях это может иметь смысл.
Вы не должны вызывать статические методы для экземпляров, а непосредственно для классов - тогда у вас не возникнет этой проблемы. Также IntelliJ IDEA, например, покажет вам предупреждение, если вы вызываете статический метод для экземпляра, а также если вы делаете статический метод финальным.