Ao declarar propriedades, métodos e classes em Java, a palavra -chave pode ser usada para modificá -la. A variável final é uma constante e só pode ser atribuída uma vez; O método final não pode ser reescrito por uma subclasse; A classe final não pode ser herdada.
1. Membros finais
A declaração de um campo final ajuda o otimizador a tomar melhores decisões de otimização, porque se o compilador souber que o valor do campo não mudará, poderá cache com segurança o valor no registro. O campo final também fornece um nível adicional de segurança, fazendo com que o compilador force o campo a ser somente leitura.
1.1 Sobre a tarefa final do membro
1) Em Java, as variáveis comuns podem ser inicializadas por padrão. Mas as variáveis do tipo final devem ser explicitamente inicializadas.
2) Os membros finais podem e só podem ser inicializados uma vez.
3) O membro final deve ser inicializado na declaração (atribuindo um valor diretamente à variável final quando definida) ou no construtor e não pode ser inicializado em outro lugar.
Exemplo 1 bat.java
classe pública BAT {final duplo Pi = 3,14; // Atribua Final Int I quando definido; // Porque deve ser inicializado no construtor, a lista final <at> não pode ser atribuída aqui; // Porque deve ser inicializado no construtor, o BAT () não pode ser atribuído aqui {i = 100; list = new LinkedList <at> (); } Bat (int ii, list <at> l) {i = ii; lista = L; } public static void main (string [] args) {bat b = new Bat (); B.List.Add (New Bat ()); // bi = 25; // b.list = new ArrayList <at> (); System.out.println ("i =" + bi + "Tipo de lista:" + b.list.getclass ()); b = novo morcego (23, novo Arraylist <at> ()); B.List.Add (New Bat ()); System.out.println ("i =" + bi + "Tipo de lista:" + b.list.getclass ()); }}
resultado:
I = 100 Tipo de lista: classe java.util.LinkedListi = 23 Tipo de lista: classe java.util.arraylist
Existem duas linhas de declarações no método principal que são comentadas. Se você remover o comentário, o programa não poderá compilar. Isso significa que, não importa se é o valor de i ou o tipo de lista, uma vez inicializado, ela não pode ser alterada. No entanto, B pode especificar o valor de i ou o tipo de lista reinicializando.
1.2 Inicialização inválida do campo de referência final
É um pouco problemático usar o campo final corretamente, especialmente para referências de objetos cujos construtores podem lançar exceções. Como o campo final deve ser inicializado apenas uma vez em cada construtor, se o construtor referenciado pelo objeto final poderá lançar uma exceção, o compilador poderá relatar um erro dizendo que o campo não foi inicializado. O compilador é geralmente inteligente o suficiente para descobrir que a inicialização em cada ramo de duas ramificações de código mutex (por exemplo, se ... else blocos) acontece apenas uma vez, mas geralmente não é tão "perdoador" para tentar ... capturar blocos.
O código a seguir geralmente tem problemas.
classe Thingie {public static Thingie getDefaultthingie () {return New Thingie (); }} classe pública Foo {particular de coisa final; public Foo () {Try {Thingie = New Thingie (); } Catch (Exceção e) {Thingie = Thingie.getDefaultthingie (); // Erro: O Final Field Thingie pode já ter sido atribuído}}}
Você pode modificar isso.
classe pública Foo {particular de coisa final; public Foo () {Thingie Tempthingie; tente {tempingie = new Thingie (); } catch (Exceção e) {tempthingie = Thingie.getDefaultthingie (); } Thingie = tempingie; }}
1.3 sobre o uso final do membro
Ao definir uma variável em uma classe, adicione a palavra -chave final antes dela, isso significa que, uma vez que essa variável seja inicializada, ela não pode ser alterada. O significado da imutabilidade aqui é que seu valor é imutável para o tipo básico, e sua referência não pode ser mais alterada para a variável de objeto. No entanto, os próprios objetos podem ser modificados e o Java não fornece uma maneira de tornar constantes quaisquer objetos. Essa limitação também se encaixa nas matrizes, que são objetos.
Exemplo 2
private final int val_one = 9; private estático final int val_two = 99; public static final int val_three = 999;
Como Val_One e Val_tow são tipos primitivos finais com valores de tempo de compilação, ambos podem ser usados como constantes de tempo de compilação e não há diferença significativa. Val_three é uma maneira mais típica de definir constantes: definido como público, pode ser usado fora do pacote; definido como estático para enfatizar apenas uma cópia; definido como final para indicar que é uma constante.
A variável marcada final se torna uma constante, mas essa "constante" só pode ser usada dentro desta classe e não pode ser usada diretamente fora da classe. No entanto, quando usamos a final estática pública para marcar uma constante, essa constante se torna uma constante global (um campo estático e final ocupa apenas um espaço de armazenamento que não pode ser alterado). Além disso, as constantes definidas dessa maneira só podem ser atribuídas valores quando definidos e não podem ser usados em outros lugares.
Exemplo 3
classe Valor {int i; Public Value (int i) {this.i = i; }} classe pública finalData {private estático aleatório rand = new aleatom (); ID de string privado; public finalData (string id) {this.id = id; } private final int i4 = rand.nextInt (20); estático final int i5 = rand.nextint (20); public string tostring () {return id + ":" + "i4:" + i4 + ", i5 =" + i5; } public static void main (string [] args) {finalData fd1 = new FinalData ("fd1"); System.out.println (fd1); System.out.println ("Criando novo FinalData"); FinalData fd2 = novo FinalData ("FD2"); System.out.println (fd1); System.out.println (fd2); }}
resultado
fd1: i4: 6, i5 = 3creating novo finalDatafd1: i4: 6, i5 = 3fd2: i4: 17, i5 = 3
A seção Exemplos mostra a diferença entre definir um valor final como estático (i5) e não estático (i4). Essa diferença só aparecerá quando o valor for inicializado durante o tempo de execução, porque o compilador trata o valor compilado igualmente. (E eles podem desaparecer da otimização.) Você verá essa diferença quando executar o programa. Observe que no FD1 e FD2, o valor de i5 não pode ser alterado criando um segundo objeto FinalData. Isso ocorre porque é estático, que é inicializado no carregamento, nem toda vez que um novo objeto é criado.
Exemplo 4
classe Valor {int i; Public Value (int i) {this.i = i; }} classe pública… {Valor privado v1 = novo valor (11); Valor final privado v2 = novo valor (22); Valor final estático privado v3 = novo valor (33); …} Public static void main (string [] args) {… fd1.v2.i ++; // ok-objeto não é constante! fd1.v1 = novo valor (9); // ok-não FD1.V2 = novo valor (0); // Erro: Não é possível alterar a referência fd1.v3 = novo valor (1); // erro: não é possível alterar a referência…} Variáveis de V1 a V3 ilustram o significado das referências finais. Como você pode ver em main (), não pode pensar que não pode alterar seu valor apenas porque o V2 é final. Como é uma referência, final significa que você não pode apontar V2 para outro novo objeto novamente.
Exemplo 5
classe pública… {private final int [] a = {1,2,3,4,5,6}; …} Public static void main (string [] args) {… for (int i = 0; i <fd1.a.length; i ++) fd1.a [i] ++; // ok-objeto não é constante! fd1.a = novo int [3]; // erro: não é possível alterar a referência…} Tendo o mesmo significado para uma matriz (pode alterar seu valor, mas não pode apontar para um novo objeto), uma matriz é outra referência.
1.4 Resolva as limitações das matrizes finais
Embora as referências da matriz possam ser declaradas finais, os elementos da matriz não podem. Isso significa que nem as classes que expõem campos de matriz final pública ou devolver referências a esses campos por meio de seus métodos são mutáveis.
// não imutável - a matriz dos estados pode ser modificada por um estados perigosos de CallerPublicClass maliciosos // cambalhote {private final string [] estados = new String [] {"Alabama", "Alaska", "Ect"}; public String [] getStates () {retornar estados; }}
Da mesma forma, embora uma referência de objeto possa ser declarada como um campo final, o objeto que ele referências ainda pode ser mutável. Se você deseja criar um objeto invariante usando o campo final, deve evitar referências a matrizes ou objetos mutáveis de "escapar" da sua classe. Para fazer isso sem precisar clonar a matriz repetidamente, uma maneira fácil é converter a matriz em uma lista.
// imutável - Retorna uma lista não modificável em vez da cláusula se protege {private final String [] estados = new String [] {"Alabama", "Alaska", "Ect"}; Lista final privada StataSList = new AbstractList () {public Object get (int n) {Return States [n]; } public int size () {return states.length; }}; public list getStates () {return estissaslist; }}
1.5 sobre o uso de parâmetros finais
Outro uso é definir o parâmetro no método como final. Para variáveis de tipos básicos, isso não possui nenhum significado prático, porque as variáveis dos tipos básicas passam valores ao chamar o método, ou seja, você pode alterar a variável de parâmetro no método sem afetar a instrução de chamada. No entanto, para variáveis de objetos, é muito prático porque as variáveis de objeto são passadas por suas referências ao passar. Dessa maneira, sua modificação de variáveis de objeto no método também afetará as variáveis de objeto na declaração de chamada. Quando você não precisa alterar as variáveis do objeto como parâmetros no método, o uso explicitamente final da declaração impedirá que você modifique e afete involuntariamente o método de chamada.
1.6 sobre variáveis de parâmetros nas classes internas
Além disso, ao usar variáveis de parâmetro no método na classe interna, essa variável de parâmetro deve ser declarada final antes de poder ser usada.
Exemplo 6 Inclass.java
classe pública Inclass {void InnerClass (final String str) {class iclass {iclass () {System.out.println (str); }} ICLass IC = new ICLASS (); } public static void main (string [] args) {incllass inc = new Inclass (); Inc.innerclass ("Hello"); }} 2. Método final
2.1 Uso final do método
1) Para garantir que o comportamento de uma determinada função permaneça inalterado durante o processo de herança e não pode ser substituído, o método final pode ser usado.
2) Todos os métodos privados e estáticos da classe são naturalmente finais.
2.2 palavras -chave finais e privadas
Todos os métodos privados da classe são implicitamente especificados para serem finais. Como o método privado não pode ser usado, ele não pode ser substituído.
"Substituir" aparecerá apenas se um método faz parte da interface da classe base. Ou seja, um objeto deve ser capaz de ser transformado para cima em seu tipo primitivo e chamar o mesmo método. Se um método for privado, não faz parte da interface da classe base. É apenas algum código escondido na classe, mas com o mesmo nome. No entanto, se um método de acesso público, protegido ou de pacotes for gerado da mesma maneira na classe de exportação, o método não produzirá o caso "apenas com o mesmo nome" que ocorre na classe base. Nesse ponto, você não substituiu o método, apenas gerou um novo método. Como o método privado não pode ser tocado e pode ser efetivamente oculto, nada mais precisa ser considerado, exceto a existência da estrutura organizacional da classe a que pertence.
3. Classe final
Quando uma classe é definida como final, a classe não pode ser herdada. E como a classe final proíbe a herança, todos os métodos da classe final são implicitamente especificados como final porque não podem ser substituídos.
Final é usado em classes ou métodos para impedir que os vínculos entre os métodos sejam quebrados. Por exemplo, suponha que a implementação de um método de classe X assume que o método m funcionará de alguma forma. Declarar x ou m como final impedirá que a classe derivada redefinirá M dessa maneira, fazendo com que X funcione anormalmente. Embora possa ser melhor implementar X sem essas correlações internas, isso nem sempre é possível e o uso final pode impedir futuras alterações incompatíveis.
PS: a diferença entre final, finalmente e finalizar