Qual é o objective da “aula final” em Java?

Eu estou lendo um livro sobre Java e ele diz que você pode declarar toda a class como final . Eu não consigo pensar em nada onde eu usaria isso.

Eu sou apenas novo para programação e estou querendo saber se os programadores realmente usam isso em seus programas . Se o fizerem, quando o usarão para que eu possa entender melhor e saber quando usá-lo.

Se Java é orientado a objects, e você declara uma class final , isso não impede a idéia de class ter as características de objects?

Se o fizerem, quando o usarão para que eu possa entender melhor e saber quando usá-lo.

Uma aula final é simplesmente uma class que não pode ser estendida .

(Isso não significa que todas as referências a objects da class agiriam como se fossem declaradas como final .)

Quando é útil declarar uma class como final é coberto nas respostas desta questão:

  • Boas razões para proibir a inheritance em Java?

Se Java é orientado a objects, e você declara uma class final , isso não impede a idéia de class ter as características de objects?

Em certo sentido sim.

Ao marcar uma class como final, você desativa um recurso poderoso e flexível do idioma para essa parte do código. Algumas classs, no entanto, não devem (e em certos casos não podem ) ser projetadas para levar em conta a subclass de uma maneira boa. Nesses casos, faz sentido marcar a class como final, mesmo que limite a OOP. (Lembre-se, no entanto, que uma aula final ainda pode estender outra class não final.)


Artigo relacionado: Java: Quando criar uma class final

Em Java, os itens com o modificador final não podem ser alterados!

Isso inclui classs finais, variables ​​finais e methods finais:

  • Uma aula final não pode ser estendida por nenhuma outra class
  • Uma variável final não pode ser transferida para outro valor
  • Um método final não pode ser substituído

Um cenário em que final é importante, quando você deseja evitar a inheritance de uma class, por motivos de segurança. Isso permite que você verifique se o código que está sendo executado não pode ser substituído por alguém.

Outro cenário é para otimização: parece que lembro que o compilador Java incorpora algumas chamadas de function das classs finais. Portanto, se você chamar ax() e a for declarado final , saberemos em tempo de compilation qual será o código e poderá inline na function de chamada. Eu não tenho idéia se isso é realmente feito, mas com final é uma possibilidade.

O melhor exemplo é

class final pública String

que é uma class imutável e não pode ser estendida. Claro, há mais do que apenas tornar a aula final imutável.

Se você imaginar a hierarquia de classs como uma tree (como é em Java), as classs abstratas só podem ser ramificações e as classs finais são aquelas que só podem ser folhas. As classs que se enquadram em nenhuma dessas categorias podem ser ramificações e folhas.

Não há violação dos princípios OO aqui, o final está simplesmente fornecendo uma boa simetria.

Na prática, você quer usar final se quiser que seus objects sejam imutáveis ​​ou se você está escrevendo uma API, para indicar aos usuários da API que a class não é destinada apenas à extensão.

Leitura relevante: The Open-Closed Principle, de Bob Martin.

Citação chave:

Entidades de Software (Classes, Módulos, Funções, etc.) devem estar abertas para Extensão, mas fechadas para Modificação.

A palavra-chave final é o meio de impor isso em Java, seja ela usada em methods ou em classs.

A palavra-chave final si significa que algo é final e não deve ser modificado de forma alguma. Se uma class for marcada como final , ela não poderá ser estendida ou subclassificada. Mas a questão é por que marcamos uma final class? OMI existem vários motivos:

  1. Padronização: Algumas classs executam funções padrão e não devem ser modificadas, por exemplo, classs executando várias funções relacionadas a manipulações de strings ou funções matemáticas, etc.
  2. Motivos de segurança : Às vezes, escrevemos classs que executam várias funções relacionadas a autenticação e senha, e não queremos que elas sejam alteradas por mais ninguém.

Ouvi dizer que marcar class final melhora a eficiência, mas francamente não consegui encontrar esse argumento para ter muito peso.

Se Java é orientado a objects, e você declara uma class final, isso não impede a idéia de class ter as características de objects?

Talvez sim, mas às vezes esse é o propósito pretendido. Às vezes fazemos isso para obter maiores benefícios de segurança, etc., sacrificando a capacidade dessa class de ser estendida. Mas uma aula final ainda pode estender uma aula se for necessário.

Em uma nota lateral, devemos preferir composição sobre inheritance e final palavra-chave final realmente ajuda a impor esse princípio.

Se a class estiver marcada como final , isso significa que a estrutura da class não pode ser modificada por nada externo. Onde esta é a mais visível é quando você está fazendo inheritance tradicional polimórfica, basicamente class B extends A simplesmente não vai funcionar. É basicamente uma maneira de proteger algumas partes do seu código (até certo ponto) .

Para esclarecer, marcar a class final não marca seus campos como final e, como tal, não protege as propriedades do object, mas sim a estrutura da class real.

Tenha cuidado quando você faz uma aula “final”. Porque se você quer escrever um teste unitário para uma class final, você não pode subclassificar esta class final para usar a técnica de quebra de dependência “Subclass e Override Method” descrita no livro de Michael C. Feathers “Working Effectively with Legacy Code” . Neste livro, Feathers disse: “Sério, é fácil acreditar que selado e final é um erro equivocado, que eles nunca deveriam ter sido adicionados às linguagens de programação. Mas a verdadeira falha está conosco. Quando dependemos diretamente de bibliotecas que estão fora de nosso controle, estamos apenas pedindo problemas “.

PARA ENDEREÇAR O PROBLEMA DA CLASSE FINAL:

Existem duas maneiras de fazer uma aula final. A primeira é usar a palavra-chave final na declaração da class:

 public final class SomeClass { // . . . Class contents } 

A segunda maneira de fazer uma final de class é declarar todos os seus construtores como privados:

 public class SomeClass { public final static SOME_INSTANCE = new SomeClass(5); private SomeClass(final int value) { } 

A marcação final evita o problema se você descobrir que é uma final, para demonstrar essa class de teste. parece público à primeira vista.

 public class Test{ private Test(Class beanClass, Class stopClass, int flags) throws Exception{ // . . . snip . . . } } 

Infelizmente, como o único construtor da class é privado, é impossível estender essa class. No caso da class Test, não há motivo para que a class seja final. A class Test é um bom exemplo de como as classs finais implícitas podem causar problemas.

Então você deve marcá-lo final quando você implicitamente faz um final de class fazendo seu construtor privado.

final class pode evitar quebrar a API pública quando você adicionar novos methods

Suponha que na versão 1 da sua class Base você faça:

 public class Base {} 

e um cliente faz:

 class Derived extends Base { public int method() { return 1; } } 

Então, se na versão 2 você deseja adicionar um method método ao Base :

 class Base { public String method() { return null; } } 

isso quebraria o código do cliente.

Se tivéssemos usado final class Base vez disso, o cliente não seria capaz de herdar e a adição do método não quebraria a API.

Sim, às vezes você pode querer isso, seja por segurança ou velocidade. É feito também em C ++. Pode não ser aquele aplicável para programas, mas mais para estruturas. http://www.glenmccl.com/perfj_025.htm

Uma aula final é uma class que não pode ser estendida. Também methods podem ser declarados como final para indicar que não podem ser substituídos por subclasss.

Impedir que a class seja subclassificada pode ser particularmente útil se você gravar APIs ou bibliotecas e quiser evitar que ela seja estendida para alterar o comportamento base.

Uma vantagem de manter uma aula como final:

A class de strings é mantida final para que ninguém possa sobrescrever seus methods e alterar a funcionalidade. por exemplo, ninguém pode alterar a funcionalidade do método length (). Sempre retornará o comprimento de uma string.

O desenvolvedor dessa class não queria que ninguém alterasse a funcionalidade dessa class, então ele a manteve como final.

Classes finais não podem ser estendidas. Então, se você quer que uma class se comporte de uma determinada maneira e não substitua os methods (com código possivelmente menos eficiente e mais malicioso), você pode declarar toda a class como methods finais ou específicos que você não quer que sejam. mudou.

Como declarar uma class não impede que uma class seja instanciada, isso não significa que ela impedirá que a class tenha as características de um object. É só que você terá que se ater aos methods do jeito que eles são declarados na class.

pense em FINAL como o “Fim da linha” – esse cara não pode mais produzir descendentes. Então, quando você vê dessa forma, existem muitos cenários do mundo real que você vai encontrar e exige que você sinalize um marcador de “fim de linha” para a class. É Domain Driven Design – se o seu domínio exigir que uma determinada ENTITY (class) não possa criar subclasss, marque-a como FINAL.

Devo observar que não há nada que impeça você de herdar uma class “deve ser marcada como final”. Mas isso geralmente é classificado como “abuso de inheritance” e feito porque na maioria das vezes você gostaria de herdar alguma function da class base de sua class.

A melhor abordagem é examinar o domínio e permitir que ele determine suas decisões de design.

Como dito acima, se você quiser ninguém pode alterar a funcionalidade do método, então você pode declará-lo como final.

Exemplo: Caminho do arquivo do servidor de aplicativos para download / upload, dividindo a string com base no deslocamento, tais methods você pode declarar Final para que estas funções do método não sejam alteradas. E se você quiser esses methods finais em uma class separada, defina essa class como Classe final. Então, a class final terá todos os methods finais, onde o método final pode ser declarado e definido na class não final.

A class Android Looper é um bom exemplo prático disso. http://developer.android.com/reference/android/os/Looper.html

A class Looper fornece certas funcionalidades que NÃO devem ser substituídas por nenhuma outra class. Portanto, nenhuma subclass aqui.

A aula final é usada quando você deseja padronizar os methods e garantir que eles não sejam sobrescritos por outra pessoa.
Então, por que algumas classs são declaradas como finais?

  1. Como as classs Final não podem ser estendidas, você pode tratá-las como primitivas e não precisa se preocupar com a mudança dessas classs.
  2. Por motivos de segurança, você não quer que o código escrito por você seja substituído por outra pessoa.

Se você fizer uma aula como final, não poderá estendê-la.

 final class Bike{} class Honda1 extends Bike{ void run(){System.out.println("running safely with 100kmph");} public static void main(String args[]){ Honda1 honda= new Honda(); honda.run(); } } Output:Compile Time Error 

Em breve, uma class, variável ou método declarado como final não pode ser alterado.

O que é mais importante é a minha opinião:

Honestamente, acredito que uma palavra-chave final seja um erro, pois sua existência permite que o usuário defina algo que não é final . Tudo em Java deve ser final por padrão, exceto os methods de interface (por sua definição). Foi uma escolha infeliz deixar todos os methods de instância virtual por padrão (em termos de c # ). A chave é forçar o usuário a pensar primeiro e explicitamente definir vergonhosamente um método como virtual – isso faria com que ele se perguntasse se esse método deveria permitir que outros o substituíssem, se é really uma necessidade ou persuadir ele a redesenhar seu código.

Digamos que você tenha uma class Employee que tenha um método greet . Quando o método de greet é chamado, simplesmente imprime Hello everyone! . Então esse é o comportamento esperado do método greet

 public class Employee { void greet() { System.out.println("Hello everyone!"); } } 

Agora, deixe GrumpyEmployee subclass Employee e substitua o método greet como mostrado abaixo.

 public class GrumpyEmployee extends Employee { @Override void greet() { System.out.println("Get lost!"); } } 

Agora, no código abaixo, dê uma olhada no método sayHello . Ele toma a instância Employee como um parâmetro e chama o método greet esperando que ele diga Hello everyone! Mas o que temos é Get lost! . Essa mudança de comportamento é por causa do Employee grumpyEmployee = new GrumpyEmployee();

 public class TestFinal { static Employee grumpyEmployee = new GrumpyEmployee(); public static void main(String[] args) { TestFinal testFinal = new TestFinal(); testFinal.sayHello(grumpyEmployee); } private void sayHello(Employee employee) { employee.greet(); //Here you would expect a warm greeting, but what you get is "Get lost!" } } 

Essa situação pode ser evitada se a class Employee for final . Imagine a quantidade de caos que um programador atrevido poderia causar se a class String não fosse declarada como final .

Orientação a Objetos não é sobre inheritance, é sobre encapsulamento. E a inheritance quebra o encapsulamento.

Declarar uma aula final faz todo o sentido em muitos casos. Qualquer object que represente um “valor” como uma cor ou uma quantia de dinheiro pode ser final. Eles estão por conta própria.

Se você estiver escrevendo bibliotecas, torne suas aulas finais, a menos que você explicitamente as indente a serem derivadas. Caso contrário, as pessoas podem derivar suas classs e replace methods, quebrando suas suposições / invariantes. Isso pode ter implicações de segurança também.

Joshua Bloch em “Effective Java” recomenda projetar explicitamente para inheritance ou proibi-lo e ele observa que projetar para inheritance não é tão fácil.