Вы можете подумать о том, чтобы сделать статический метод final, учитывая следующее:
Имея следующие классы:
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. Но в зависимости от указателя, указывающего на объект, вы будете вызывать метод from Aили from B.
Теперь предположим, что вы разработчик класса Aи хотите разрешить подклассы. Но вам действительно нужен метод ts(), когда бы он ни вызывался, даже из подкласса, который делал бы то, что вы хотите, а не был бы скрыт версией подкласса. Тогда вы можете сделать это finalи предотвратить его скрытие в подклассе. И вы можете быть уверены, что следующий код вызовет метод из вашего класса A:
B b = new B();
b.ts();
Хорошо, по общему признанию, это каким-то образом сконструировано, но в некоторых случаях это может иметь смысл.
Вы должны вызывать статические методы не в экземплярах, а непосредственно в классах - тогда у вас не будет этой проблемы. Также IntelliJ IDEA, например, покажет вам предупреждение, если вы вызовете статический метод в экземпляре, а также если вы сделаете статический метод final.