A palavra-chave "final" em Java

A palavra-chave "final" em Java

1. Visão geral

Embora a herança nos permita reutilizar o código existente, às vezes precisamosset limitations on extensibility por vários motivos; a palavra-chavefinal nos permite fazer exatamente isso.

Neste tutorial, vamos dar uma olhada no que a palavra-chavefinal significa para classes, métodos e variáveis.

2. Final aulas

Classes marked as final can’t be extended. Se olharmos o código das principais bibliotecas Java, encontraremos muitas classesfinal lá. Um exemplo é a classeString.

Considere a situação se pudermos estender a classeString, sobrescrever qualquer um de seus métodos e substituir todas as instânciasString pelas instâncias de nossa subclasseString específica.

O resultado das operações sobre objetosString se tornará imprevisível. E dado que a classeString é usada em todos os lugares, é inaceitável. É por isso que a classeString está marcada comofinal.

Qualquer tentativa de herdar de uma classefinal causará um erro do compilador. Para demonstrar isso, vamos criar a classefinalCat:

public final class Cat {

    private int weight;

    // standard getter and setter
}

E vamos tentar estendê-lo:

public class BlackCat extends Cat {
}

Veremos o erro do compilador:

The type BlackCat cannot subclass the final class Cat

Observe quethe final keyword in a class declaration doesn’t mean that the objects of this class are immutable. Podemos alterar os campos do objetoCat livremente:

Cat cat = new Cat();
cat.setWeight(1);

assertEquals(1, cat.getWeight());

Nós simplesmente não podemos estender isso.

Se seguirmos estritamente as regras de bom design, devemos criar e documentar uma classe cuidadosamente ou declará-lafinal por razões de segurança. No entanto, devemos ter cuidado ao criar classesfinal.

Observe que criar uma classefinal significa que nenhum outro programador pode melhorá-la. Imagine que estamos usando uma classe e não temos o código-fonte para ela e há um problema com um método.

Se a classe forfinal,, não podemos estendê-la para substituir o método e corrigir o problema. Em outras palavras, perdemos a extensibilidade, um dos benefícios da programação orientada a objetos.

3. MétodosFinal

Methods marked as final cannot be overridden. Quando projetamos uma classe e sentimos que um método não deve ser sobrescrito, podemos tornar esse métodofinal. Também podemos encontrar muitos métodosfinal nas bibliotecas principais do Java.

Às vezes, não precisamos proibir totalmente uma extensão de classe, mas apenas impedir a substituição de alguns métodos. Um bom exemplo disso é a classeThread. É legal estendê-lo e, assim, criar uma classe de encadeamento personalizada. Mas seus métodosisAlive() sãofinal.

Este método verifica se um encadeamento está ativo. É impossível substituir o métodoisAlive() corretamente por muitos motivos. Um deles é que esse método é nativo. O código nativo é implementado em outra linguagem de programação e geralmente é específico para o sistema operacional e hardware em que está sendo executado.

Vamos criar uma classeDog e fazer seu métodosound()final:

public class Dog {
    public final void sound() {
        // ...
    }
}

Agora vamos estender a classeDog e tentar substituir seu métodosound():

public class BlackDog extends Dog {
    public void sound() {
    }
}

Veremos o erro do compilador:

- overrides
com.example.finalkeyword.Dog.sound
- Cannot override the final method from Dog
sound() method is final and can’t be overridden

Se alguns métodos de nossa classe são chamados por outros métodos, devemos considerar fazer os métodos chamadosfinal. Caso contrário, substituí-los pode afetar o trabalho dos chamadores e causar resultados surpreendentes.

Se nosso construtor chamar outros métodos, devemos geralmente declarar esses métodosfinal pelo motivo acima.

Qual é a diferença entre fazer todos os métodos da classefinal e marcar a própria classefinal? No primeiro caso, podemos estender a classe e adicionar novos métodos a ela.

No segundo caso, não podemos fazer isso.

4. Final Variáveis

Variables marked as final can’t be reassigned. Depois que uma variávelfinal é inicializada, ela não pode ser alterada.

4.1. Final Variáveis ​​primitivas

Vamos declarar uma variávelfinal primitivai, e atribuir 1 a ela.

E vamos tentar atribuir um valor 2 a ele:

public void whenFinalVariableAssign_thenOnlyOnce() {
    final int i = 1;
    //...
    i=2;
}

O compilador diz:

The final local variable i may already have been assigned

4.2. Final Variáveis ​​de Referência

Se tivermos uma variável de referênciafinal, também não podemos reatribuí-la. Masthis doesn’t mean that the object it refers to is immutable. Nós podemos alterar as propriedades deste objeto livremente.

Para demonstrar isso, vamos declarar a variável de referênciafinalcat e inicializá-la:

final Cat cat = new Cat();

Se tentarmos reatribuir, veremos um erro do compilador:

The final local variable cat cannot be assigned. It must be blank and not using a compound assignment

Mas podemos alterar as propriedades da instânciaCat:

cat.setWeight(5);

assertEquals(5, cat.getWeight());

4.3. CamposFinal

Final fields can be either constants or write-once fields. Para distingui-los, devemos fazer uma pergunta - incluiríamos este campo se fôssemos serializar o objeto? Se não, não faz parte do objeto, mas uma constante.

Observe que, de acordo com as convenções de nomenclatura, as constantes da classe devem estar em maiúsculas, com os componentes separados por caracteres de sublinhado (“_”):

static final int MAX_WIDTH = 999;

Observe queany final field must be initialized before the constructor completes.

Para camposstatic final, isso significa que podemos inicializá-los:

  • mediante declaração, como mostrado no exemplo acima

  • no bloco inicializador estático

Por exemplo, camposfinal, isso significa que podemos inicializá-los:

  • mediante declaração

  • no bloco inicializador da instância

  • no construtor

Caso contrário, o compilador nos dará um erro.

4.4. Final Argumentos

A palavra-chavefinal também é válida para colocar antes dos argumentos do método. A final argument can’t be changed inside a method:

public void methodWithFinalArguments(final int x) {
    x=1;
}

A atribuição acima causa o erro do compilador:

The final local variable x cannot be assigned. It must be blank and not using a compound assignment

5. Conclusão

Neste artigo, aprendemos o que a palavra-chavefinal significa para classes, métodos e variáveis. Embora não possamos usar a palavra-chavefinal com frequência em nosso código interno, pode ser uma boa solução de design.

Como sempre, o código completo para este artigo pode ser encontrado emGitHub project.