Quando você usa a anotação @Override do Java e por quê?


498

Quais são as melhores práticas para usar a @Overrideanotação de Java e por quê?

Parece que seria um exagero marcar todos os métodos substituídos com a @Overrideanotação. Existem certas situações de programação que exigem o uso de @Overridee outras que nunca devem usar o @Override?

Respostas:


515

Use-o sempre que substituir um método por dois benefícios. Faça isso para que você possa tirar proveito da verificação do compilador para certificar-se de que realmente está substituindo um método quando pensa que está. Dessa forma, se você cometer um erro comum de digitar incorretamente o nome de um método ou não corresponder corretamente aos parâmetros, você será avisado de que o método não substitui realmente o que você pensa. Em segundo lugar, torna seu código mais fácil de entender, porque é mais óbvio quando os métodos são substituídos.

Além disso, no Java 1.6, você pode usá-lo para marcar quando um método implementa uma interface para os mesmos benefícios. Eu acho que seria melhor ter uma anotação separada (como @Implements), mas é melhor que nada.


4
Na mesma linha de "mais fácil de entender", os IDEs localizarão a anotação @Override e sinalizarão visualmente o método de substituição no editor.
Bob Cross

47
Alguns IDEs sinalizam um método substituído que também está ausente na anotação @Override.
Jay R.

20
O outro benefício é que, se a classe pai for alterada, o compilador garantirá que as classes filho também foram atualizadas.
2727 David

4
@ Jay R .: Verdade. Por uma questão de fato, por exemplo, o Eclipse pode até adicionar automaticamente o @Override, se estiver ausente.
sleske

32
Caso alguém mais chegue aqui por causa da alteração aparentemente não documentada de 1,5 para 1,6 para @Overrides em métodos provenientes de interfaces, bugs.sun.com/bugdatabase/view_bug.do?bug_id=5008260 parece ser o bug correspondente. (Obrigado por apontar isso, Dave L.!)
Henrik Heimbuerger

110

Eu acho que é mais útil como um lembrete em tempo de compilação que a intenção do método é substituir um método pai. Como um exemplo:

protected boolean displaySensitiveInformation() {
  return false;
}

Você verá frequentemente algo como o método acima que substitui um método na classe base. Este é um detalhe importante da implementação desta classe - não queremos que informações confidenciais sejam exibidas.

Suponha que esse método seja alterado na classe pai para

protected boolean displaySensitiveInformation(Context context) {
  return true;
}

Essa alteração não causará erros ou avisos no tempo de compilação - mas altera completamente o comportamento pretendido da subclasse.

Para responder sua pergunta: você deve usar a anotação @Override se a falta de um método com a mesma assinatura em uma superclasse for indicativa de um bug.


46

Há muitas boas respostas aqui, então deixe-me oferecer outra maneira de ver isso ...

Não há exagero quando você está codificando. Não custa nada digitar @override, mas a economia pode ser imensa se você digitar o nome de um método incorretamente ou se a assinatura estiver ligeiramente errada.

Pense da seguinte maneira: durante o tempo em que você navegou aqui e digitou esta postagem, você praticamente gastou mais tempo do que gastaria digitando @override pelo resto da vida; mas um erro evitado pode economizar horas.

O Java faz todo o possível para garantir que você não cometeu nenhum erro no momento da edição / compilação. Essa é uma maneira praticamente gratuita de resolver toda uma classe de erros que não são evitáveis ​​de nenhuma outra maneira fora dos testes abrangentes.

Você poderia criar um mecanismo melhor em Java para garantir que, quando o usuário pretendesse substituir um método, ele realmente o fizesse?

Outro efeito interessante é que, se você não fornecer a anotação, ele avisará, em tempo de compilação, que você substituiu acidentalmente um método pai - algo que pode ser significativo se você não pretender fazer isso.


3
"Não há exagero quando você está codificando." Eu concordo com isso, e é por isso que acho langs dinâmicos tão errados (embora 100% do meu trabalho remunerado esteja em rubi agora).
Dan Rosenstark 10/01

4
+1: tive, talvez, 10 bugs causados ​​por um erro de substituição - o tempo necessário para encontrar qualquer um deles teria facilmente excedido o tempo para digitar @Override em todos os meus métodos de substituição. Além disso, se o @Override for um pouco oneroso, você provavelmente está usando demais a herança.
Lawrence Dol

7
Uma desvantagem muito real é que você torna o código mais difícil de ler, espalhando-o com caracóis. Talvez isso seja uma falha do meu IDE, mas eu mesmo experimentei isso.
trate seus mods bem

9
@phyzome Se você acha os "Caracóis" pesados, não está usando QUALQUER LUGAR PERTO de comentários suficientes. Eles devem ser apenas uma única linha acima do cabeçalho do método, que deve ser quase tão grande quanto o seu método na maioria dos casos (algumas linhas) para fornecer texto flutuante decente e javadocs. Acho que estou dizendo que o problema não é o Caracol, é o seu hábito de ler. Todos esses parênteses no código estão incomodando você também?
Bill K

4
Sim, há um exagero na codificação: quando você escreve comentários, papagaia o que o código obviamente faz.
Formigas

22

Eu sempre uso a tag. É um sinalizador simples em tempo de compilação para detectar pequenos erros que eu possa cometer.

Vai pegar coisas como em tostring()vez detoString()

As pequenas coisas ajudam em grandes projetos.


18

O uso da @Overrideanotação atua como uma proteção em tempo de compilação contra um erro de programação comum. Irá gerar um erro de compilação se você tiver a anotação em um método que não está substituindo o método da superclasse.

O caso mais comum em que isso é útil é quando você está alterando um método na classe base para ter uma lista de parâmetros diferente. Um método em uma subclasse que substituía o método da superclasse não o fará mais devido à assinatura do método alterado. Às vezes, isso pode causar um comportamento estranho e inesperado, especialmente quando se lida com estruturas complexas de herança. A @Overrideanotação protege contra isso.


Melhor resposta. Curto e grosso. Eu gostaria que você pudesse explicar como funciona a "salvaguarda" .... ninguém explicou isso.
djangofan

É simples de explicar. Se você cometer um erro (alterando a interface, a classe abstrata ou a subclasse, receberá um aviso (como no Eclipse) ou um erro em tempo de compilação informando que seu @Override não está funcionando. A mensagem dependerá do que foi alterado, mas no Eclipse (por exemplo) fica muito claro rapidamente que há um problema: você verá esse pequeno zigue-zague vermelho sublinhado e um cursor sobre o texto incorreto dirá o que está errado. Eu chamo isso de bom valor.
Ichiro Furusato

14

Para tirar proveito da verificação do compilador, você sempre deve usar a anotação Override. Mas não esqueça que o Java Compiler 1.5 não permitirá essa anotação ao substituir métodos de interface. Você pode usá-lo para substituir os métodos de classe (abstratos ou não).

Alguns IDEs, como o Eclipse, mesmo configurados com o Java 1.6 runtime ou superior, mantêm a conformidade com o Java 1.5 e não permitem o uso @override conforme descrito acima. Para evitar esse comportamento, você deve acessar: Propriedades do projeto -> Java Compiler -> Marque "Ativar configurações específicas do projeto" -> Escolha "Nível de conformidade do compilador" = 6.0 ou superior.

Eu gosto de usar essa anotação sempre que substituir um método independentemente, se a base for uma interface ou classe.

Isso ajuda a evitar alguns erros típicos, como quando você pensa que está substituindo um manipulador de eventos e não vê nada acontecendo. Imagine que você deseja adicionar um ouvinte de evento a algum componente da interface do usuário:

someUIComponent.addMouseListener(new MouseAdapter(){
  public void mouseEntered() {
     ...do something...
  }
});

O código acima é compilado e executado, mas se você mover o mouse dentro de algum componente do UIComponent, o código “faça alguma coisa” notará a execução, porque na verdade você não está substituindo o método base mouseEntered(MouseEvent ev). Você acabou de criar um novo método sem parâmetros mouseEntered(). Em vez desse código, se você usou a @Overrideanotação, viu um erro de compilação e não perdeu tempo pensando no motivo pelo qual o manipulador de eventos não estava em execução.


8

Substituir @ na implementação da interface é inconsistente, pois não existe algo como "substituir uma interface" em java.

O @Override na implementação da interface é inútil, pois, na prática, ele não captura bugs que a compilação não pegaria de qualquer maneira. Há apenas um cenário muito buscado em que a substituição nos implementadores realmente faz algo: Se você implementar uma interface e a interface REMOVER os métodos, você será notificado em tempo de compilação que deve remover as implementações não utilizadas. Observe que se a nova versão da interface tiver métodos NEW ou CHANGED, você obviamente receberá um erro de compilação, pois não está implementando o novo material.

A substituição em implementadores de interface nunca deveria ter sido permitida na versão 1.6, e com o eclipse, infelizmente, optando por inserir automaticamente as anotações como comportamento padrão, obtemos muitos arquivos de origem desordenados. Ao ler o código 1.6, você não pode ver na anotação @Override se um método realmente substitui um método na superclasse ou apenas implementa uma interface.

Usar o @Override ao substituir um método em uma superclasse é bom.


2
Existem opiniões variadas sobre esse ponto. Consulte stackoverflow.com/questions/212614/… .
sleske

8

É melhor usá-lo para todos os métodos destinados a substituir, e Java 6+, todos os métodos destinados a implementar uma interface.

Primeiro, ele captura erros de ortografia como " hashcode()" em vez de " hashCode()" em tempo de compilação. Pode ser desconcertante depurar por que o resultado do seu método não parece corresponder ao seu código quando a causa real é que o seu código nunca é chamado.

Além disso, se uma superclasse alterar uma assinatura de método, as substituições da assinatura mais antiga podem ser "órfãs", deixadas para trás como código morto confuso. A @Overrideanotação ajudará você a identificar esses órfãos para que possam ser modificados para corresponder à nova assinatura.


7

Se você se deparar com métodos (não abstratos) com muita frequência, provavelmente desejará dar uma olhada no seu design. É muito útil quando o compilador não detectaria o erro. Por exemplo, tentando substituir initValue () em ThreadLocal, o que eu fiz.

Usar o @Override ao implementar métodos de interface (recurso 1.6+) parece um pouco exagerado para mim. Se você tiver vários métodos, alguns dos quais substituem e outros não, esse design provavelmente ruim de novo (e seu editor provavelmente mostrará qual é qual, se você não souber).


2
Na verdade, também é bom para métodos de interface substituídos. Se eu, por exemplo, remover um método antigo e obsoleto de uma interface, esse método também deverá ser removido de todas as classes de implementação - fácil identificá-las se elas usarem @override.
Dominik Sandjaja 12/08

7

@ Substituir interfaces realmente é útil, porque você receberá avisos se alterar a interface.


7

Outra coisa que faz é tornar mais óbvio ao ler o código que ele está alterando o comportamento da classe pai. Do que pode ajudar na depuração.

Além disso, no livro Effective Java (2ª edição) de Joshua Block, o item 36 fornece mais detalhes sobre os benefícios da anotação.


Sim, é verdade - ponto 36 :)
Chris Kimpton

6

Não faz absolutamente sentido usar o @Override ao implementar um método de interface. Não há vantagem em usá-lo nesse caso - o compilador já detectou seu erro, portanto é apenas uma confusão desnecessária.


6
O uso @Overrideem uma interface forçará você a notar quando um método na interface é removido.
Alex B

@ Alex: A remoção de métodos em uma interface é uma mudança radical, como adicioná-los. Depois que uma interface é publicada, ela é efetivamente bloqueada, a menos que você tenha controle total sobre todo o código que a utiliza.
Lawrence Dol

6

Sempre que um método substitui outro, ou um método implementa uma assinatura em uma interface.

A @Overrideanotação garante que você de fato substituiu algo. Sem a anotação, você corre o risco de erros de ortografia ou diferença nos tipos e números de parâmetros.


1
Você só pode usá-lo para marcar a implementação da interface no Java 1.6
Dave L.

5

Eu uso sempre. São mais informações que posso usar para descobrir rapidamente o que está acontecendo quando revisito o código em um ano e esqueci o que estava pensando na primeira vez.


5

O melhor é sempre usá-lo (ou fazer com que o IDE os preencha)

A utilidade @Override é detectar alterações nas classes pai que não foram relatadas na hierarquia. Sem ele, você pode alterar uma assinatura de método e esquecer de alterar suas substituições. Com @Override, o compilador irá capturá-lo para você.

É sempre bom ter esse tipo de rede de segurança.


1
Portanto, se você alterar o método pai e não usar @Override no método da classe filho, a compilação dirá alguma coisa ou permanecerá em silêncio? O uso de "Substituir" fornecerá mais informações e, em caso afirmativo, o que?
djangofan

5

Eu uso em todos os lugares. No tópico do esforço para marcar métodos, deixei o Eclipse fazer isso por mim, para que não seja um esforço adicional.

Sou religioso em relação à refatoração contínua ... então, usarei tudo para torná-la mais suave.


5
  • Usado apenas em declarações de método.
  • Indica que a declaração do método anotado substitui uma declaração no supertipo.

Se usado de forma consistente, ele protege você de uma grande classe de erros nefastos.

Use a anotação @Override para evitar esses erros: (Encontre o erro no código a seguir :)

public class Bigram {
    private final char first;
    private final char second;
    public Bigram(char first, char second) {
        this.first  = first;
        this.second = second;
    }
    public boolean equals(Bigram b) {
        return b.first == first && b.second == second;
    }
    public int hashCode() {
        return 31 * first + second;
    }

    public static void main(String[] args) {
        Set<Bigram> s = new HashSet<Bigram>();
        for (int i = 0; i < 10; i++)
            for (char ch = 'a'; ch <= 'z'; ch++)
                s.add(new Bigram(ch, ch));
        System.out.println(s.size());
    }
}

fonte: Java eficaz


Não sei quais são as regras de precedência do operador em Java, mas seu método equals está gritando BUUUUUUUUUUUG! Eu escreveria (b.first == first) && (b.second == second), mesmo que &&tivesse precedência menor do que ==.
pyon

Você sabia que o seu link mostra uma mensagem 'você deve se inscrever' cobrindo a parte útil dessa página?
Adriano Varoli Piazza

@ Adriano: Desculpe cara !! Estou desamparado !! Quando escrevi a 'resposta', ela estava disponível. Não se preocupe ... compre o livro. Vale a pena tê-lo !!
jai

5
O método equals não substitui: o original Object::equalsé boolean equals(Object), enquanto o substituído equalsé boolean equals(Bigram), que possui uma assinatura de método diferente, que não substitui. Adicionando @Override ao equalsirá detectar esse erro.
Ming-Tang

3

Tenha cuidado ao usar Override, porque você não pode fazer a engenharia reversa no starUML posteriormente; faça o uml primeiro.


2

Parece que a sabedoria aqui está mudando. Hoje instalei o IntelliJ IDEA 9 e notei que sua " inspeção @Override ausente " agora captura não apenas métodos abstratos implementados, mas também métodos de interface implementados. Na base de código do meu empregador e nos meus próprios projetos, há muito tempo tenho o hábito de usar o @Override apenas para os métodos abstratos implementados anteriormente. No entanto, repensando o hábito, fica claro o mérito de usar as anotações nos dois casos. Apesar de ser mais detalhado, ele protege contra o frágil problema da classe base (não tão grave quanto os exemplos relacionados ao C ++) em que o nome do método da interface muda, tornando o método de implementação em potencial em uma classe derivada.

Obviamente, esse cenário é principalmente hipérbole; a classe derivada não seria mais compilada, agora sem uma implementação do método de interface renomeado, e hoje provavelmente se usaria uma operação de refatoração de Rename Method para endereçar toda a base de código em massa.

Como a inspeção da IDEA não é configurável para ignorar os métodos de interface implementados, hoje vou mudar meu hábito e os critérios de revisão de código da minha equipe.


2

A anotação @Override é usada para ajudar a verificar se o desenvolvedor deve substituir o método correto na classe ou na interface pai. Quando o nome dos métodos do super é alterado, o compilador pode notificar esse caso, que é apenas para manter a consistência com o super e a subclasse.

BTW, se não anunciarmos a anotação @Override na subclasse, mas substituirmos alguns métodos da super, a função poderá funcionar como a do @Override. Mas esse método não pode notificar o desenvolvedor quando o método do super foi alterado. Porque ele não conhecia o objetivo do desenvolvedor - substituir o método de super ou definir um novo método?

Portanto, quando queremos substituir esse método para usar o polimorfismo, é melhor adicionar @Override acima do método.


1

Eu o uso o máximo possível para identificar quando um método está sendo substituído. Se você observar a linguagem de programação Scala, eles também terão uma palavra-chave de substituição. Eu acho isso útil.


0

Ele permite que você (bem, o compilador) seja capturado quando você usa a ortografia errada em um nome de método que você está substituindo.


0

A anotação de substituição é usada para tirar proveito do compilador, para verificar se você está realmente substituindo um método da classe pai. É usado para notificar se você cometer algum erro, como erro de digitar incorretamente o nome de um método, erro de não corresponder corretamente aos parâmetros


0

Eu acho que é melhor codificar o @override sempre que permitido. ajuda na codificação. no entanto, para ser observado, no ecipse Helios, sdk 5 ou 6, a anotação @override para métodos de interface implementados é permitida. quanto ao Galileo, 5 ou 6, a anotação @override não é permitida.


0

As anotações fornecem metadados sobre o código ao compilador e a anotação @Override é usada em caso de herança quando estamos substituindo qualquer método da classe base. Apenas informa ao compilador que você está substituindo o método. Ele pode evitar erros comuns de alguns tipos, como não seguir a assinatura apropriada do método ou escrever incorretamente o nome do método etc. Portanto, é uma boa prática usar a anotação @Override.


0

Para mim, o @Override garante que eu tenha a assinatura do método correta. Se eu inserir a anotação e o método não estiver escrito corretamente, o compilador se queixará de que algo está errado.


0

Simples - quando você deseja substituir um método presente em sua superclasse, use a @Overrideanotação para fazer uma substituição correta. O compilador avisará se você não o substituir corretamente.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.