Você pode encontrar-se na posição de pensar em finalizar um método estático, considerando o seguinte:
Tendo as seguintes classes:
class A {
static void ts() {
System.out.print("A");
}
}
class B extends A {
static void ts() {
System.out.print("B");
}
}
Agora, a maneira 'correta' de chamar esses métodos seria
A.ts();
B.ts();
o que resultaria, AB
mas você também poderia chamar os métodos nas instâncias:
A a = new A();
a.ts();
B b = new B();
b.ts();
o que resultaria AB
também.
Agora considere o seguinte:
A a = new B();
a.ts();
isso seria impresso A
. Isso pode surpreendê-lo, pois você está realmente tendo um objeto de classe B
. Mas como você está chamando a partir de uma referência do tipo A
, ele chamará A.ts()
. Você pode imprimir B
com o seguinte código:
A a = new B();
((B)a).ts();
Nos dois casos, o objeto que você possui é realmente da classe B
. Mas, dependendo do ponteiro que aponta para o objeto, você chamará o método de A
ou deB
.
Agora, digamos que você é o desenvolvedor da classe A
e deseja permitir a subclassificação. Mas você realmente deseja um método ts()
, sempre que chamado, mesmo de uma subclasse, que é o que você deseja que ele faça e que não seja oculto por uma versão da subclasse. Então você pode fazer isso final
e impedir que ele fique oculto na subclasse. E você pode ter certeza de que o código a seguir chamará o método da sua classe A
:
B b = new B();
b.ts();
Ok, admitidamente, isso é de alguma forma construído, mas pode fazer sentido para alguns casos.
Você não deve chamar métodos estáticos nas instâncias, mas diretamente nas classes - então você não terá esse problema. Também o IntelliJ IDEA, por exemplo, mostrará um aviso, se você chamar um método estático em uma instância e também se você finalizar um método estático.