Quand utilisez-vous l'annotation @Override de Java et pourquoi?

498

Quelles sont les meilleures pratiques pour utiliser l' @Overrideannotation Java et pourquoi?

Il semble qu'il serait exagéré de marquer chaque méthode remplacée avec l' @Overrideannotation. Y a-t-il certaines situations de programmation qui appellent à utiliser le @Overrideet d'autres qui ne devraient jamais utiliser le @Override?

Alex B
la source

Réponses:

515

Utilisez-le chaque fois que vous remplacez une méthode pour deux avantages. Faites-le afin que vous puissiez profiter de la vérification du compilateur pour vous assurer que vous remplacez réellement une méthode lorsque vous pensez que vous l'êtes. De cette façon, si vous faites une erreur courante de mal orthographier un nom de méthode ou de ne pas faire correspondre correctement les paramètres, vous serez averti que votre méthode ne remplace pas réellement comme vous le pensez. Deuxièmement, cela rend votre code plus facile à comprendre car il est plus évident lorsque les méthodes sont écrasées.

De plus, en Java 1.6, vous pouvez l'utiliser pour marquer lorsqu'une méthode implémente une interface pour les mêmes avantages. Je pense qu'il serait préférable d'avoir une annotation séparée (comme @Implements), mais c'est mieux que rien.

Dave L.
la source
4
Dans le même esprit que «plus facile à comprendre», les IDE repèreront l'annotation @Override et marqueront visuellement la méthode prioritaire dans l'éditeur.
Bob Cross
47
Certains IDE signalent également une méthode substituée qui manque l'annotation @Override.
Jay R.
20
L'autre avantage est que si la classe parent change, le compilateur s'assurera que les classes enfants ont également été mises à jour.
David
4
@Jay R .: Vrai. En fait, par exemple, Eclipse peut même ajouter automatiquement le @Override s'il est manquant.
sleske
32
Au cas où quelqu'un d'autre serait arrivé à cause du changement apparemment non documenté de 1.5 à 1.6 pour @Overrides sur les méthodes provenant des interfaces, bugs.sun.com/bugdatabase/view_bug.do?bug_id=5008260 semble être le bogue correspondant. (Merci de l'avoir signalé, Dave L.!)
Henrik Heimbuerger
110

Je pense que c'est plus utile comme rappel au moment de la compilation que l'intention de la méthode est de remplacer une méthode parent. Par exemple:

protected boolean displaySensitiveInformation() {
  return false;
}

Vous verrez souvent quelque chose comme la méthode ci-dessus qui remplace une méthode dans la classe de base. Il s'agit d'un détail d'implémentation important de cette classe - nous ne voulons pas que des informations sensibles soient affichées.

Supposons que cette méthode soit modifiée dans la classe parent en

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

Cette modification ne provoquera aucune erreur ni aucun avertissement lors de la compilation, mais elle modifie complètement le comportement prévu de la sous-classe.

Pour répondre à votre question: vous devez utiliser l'annotation @Override si l'absence d'une méthode avec la même signature dans une superclasse est révélatrice d'un bug.

Jon
la source
46

Il y a beaucoup de bonnes réponses ici, alors laissez-moi vous proposer une autre façon de voir les choses ...

Il n'y a pas de surpuissance lorsque vous codez. Il ne vous coûte rien de taper @override, mais les économies peuvent être énormes si vous avez mal orthographié un nom de méthode ou obtenu une signature légèrement erronée.

Pensez-y de cette façon: lorsque vous avez navigué ici et tapé ce message, vous avez utilisé plus de temps que vous ne passerez à taper @override pour le reste de votre vie; mais une erreur qu'il empêche peut vous faire économiser des heures.

Java fait tout son possible pour vous assurer que vous n'avez commis aucune erreur au moment de l'édition / de la compilation.C'est un moyen pratiquement gratuit de résoudre une classe entière d'erreurs qui ne peuvent être évitées d'aucune autre manière en dehors des tests complets.

Pourriez-vous trouver un meilleur mécanisme en Java pour vous assurer que lorsque l'utilisateur a l'intention de remplacer une méthode, il l'a effectivement fait?

Un autre effet intéressant est que si vous ne fournissez pas l'annotation, il vous avertira lors de la compilation que vous avez accidentellement outrepassé une méthode parent - ce qui pourrait être significatif si vous n'aviez pas l'intention de le faire.

Bill K
la source
3
"Il n'y a aucune surpuissance lorsque vous codez." Je suis d'accord avec cela, c'est pourquoi je trouve les langages dynamiques si mal (bien que 100% de mon travail rémunéré soit en rubis en ce moment).
Dan Rosenstark
4
+1: J'ai peut-être eu 10 bogues causés par une erreur de substitution - le temps nécessaire pour trouver l'un d'eux aurait facilement dépassé le temps de taper @Override sur chacune de mes méthodes de substitution. En outre, si @Override est un peu lourd, vous utilisez probablement l'héritage de manière excessive.
Lawrence Dol
7
Un inconvénient très réel est que vous rendez le code plus difficile à lire en le salissant d'escargots. C'est peut-être une faute de mon IDE, mais je l'ai vécu moi-même.
traitez bien vos mods du
9
@phyzome Si vous trouvez que les "escargots" sont encombrants, vous n'utilisez PAS assez loin de commentaires. Ils devraient être juste une seule ligne au-dessus de votre en-tête de méthode qui devrait être à peu près aussi grand que votre méthode dans la plupart des cas (quelques lignes) pour fournir un texte de survol décent et des javadocs. Je suppose que je dis que le problème n'est pas les escargots, ce sont vos habitudes de lecture. Toutes ces parenthèses dans le code vous dérangent-elles également?
Bill K
4
Oui, le codage est exagéré: lorsque vous écrivez des commentaires qui ne font que percevoir ce que fait le code.
Fourmis
22

J'utilise toujours la balise. C'est un simple indicateur au moment de la compilation pour détecter les petites erreurs que je pourrais faire.

Il va attraper des choses comme tostring()au lieu detoString()

Les petites choses aident dans les grands projets.

jjnguy
la source
18

L'utilisation de l' @Overrideannotation agit comme une protection à la compilation contre une erreur de programmation courante. Cela générera une erreur de compilation si vous avez l'annotation sur une méthode que vous ne remplacez pas réellement la méthode de superclasse.

Le cas le plus courant où cela est utile est lorsque vous modifiez une méthode dans la classe de base pour avoir une liste de paramètres différente. Une méthode dans une sous-classe qui remplaçait la méthode de super-classe ne le fera plus en raison de la signature de méthode modifiée. Cela peut parfois provoquer un comportement étrange et inattendu, en particulier lorsqu'il s'agit de structures d'héritage complexes. L' @Overrideannotation protège contre cela.

toluju
la source
Meilleure réponse. Court et doux. J'aimerais que vous puissiez expliquer comment fonctionne la "sauvegarde" ... personne ne l'a expliqué.
djangofan
C'est simple à expliquer. Si vous faites une erreur (soit en changeant l'interface, la classe abstraite ou la sous-classe, vous obtiendrez soit un avertissement (comme dans Eclipse) soit une erreur de compilation vous indiquant que votre @Override ne fonctionne pas. L'erreur réelle Le message dépendra de ce qui a été modifié, mais dans Eclipse (par exemple), il est très clair très rapidement qu'il y a un problème: vous verrez ce petit zigzag rouge souligné, et un survol du texte incriminé vous dira ce qui ne va pas. J'appelle ça une bonne valeur.
Ichiro Furusato
14

Pour tirer parti de la vérification du compilateur, vous devez toujours utiliser l'annotation Override. Mais n'oubliez pas que Java Compiler 1.5 n'autorisera pas cette annotation lors du remplacement des méthodes d'interface. Vous pouvez simplement l'utiliser pour remplacer les méthodes de classe (abstraites ou non).

Certains IDE, comme Eclipse, même configurés avec le runtime Java 1.6 ou supérieur, ils maintiennent la conformité avec Java 1.5 et ne permettent pas l'utilisation de @override comme décrit ci-dessus. Pour éviter ce comportement, vous devez aller dans: Propriétés du projet -> Compilateur Java -> Cochez «Activer les paramètres spécifiques au projet» -> Choisissez «Niveau de conformité du compilateur» = 6.0 ou supérieur.

J'aime utiliser cette annotation chaque fois que je remplace une méthode indépendamment, si la base est une interface ou une classe.

Cela vous aide à éviter certaines erreurs typiques, comme lorsque vous pensez que vous remplacez un gestionnaire d'événements et que vous ne voyez rien se produire. Imaginez que vous souhaitez ajouter un écouteur d'événements à un composant de l'interface utilisateur:

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

Le code ci-dessus se compile et s'exécute, mais si vous déplacez la souris à l'intérieur de someUIComponent, le code «faire quelque chose» notera l'exécution, car en réalité vous ne remplacez pas la méthode de base mouseEntered(MouseEvent ev). Vous venez de créer une nouvelle méthode sans paramètre mouseEntered(). Au lieu de ce code, si vous avez utilisé l' @Overrideannotation, vous avez vu une erreur de compilation et vous n'avez pas perdu de temps à vous demander pourquoi votre gestionnaire d'événements ne s'exécutait pas.

Associés Donal
la source
8

@Override sur l' implémentation de l'interface est incohérent car il n'y a rien de tel que "remplacer une interface" en java.

@Override sur la mise en œuvre de l'interface est inutile car en pratique, il ne détecte aucun bogue que la compilation n'attraperait pas de toute façon. Il n'y a qu'un seul scénario farfelu où le remplacement des implémenteurs fait réellement quelque chose: si vous implémentez une interface et les méthodes d'interface SUPPRIME, vous serez averti au moment de la compilation que vous devez supprimer les implémentations inutilisées. Notez que si la nouvelle version de l'interface a des méthodes NOUVELLES ou MODIFIÉES, vous obtiendrez de toute façon une erreur de compilation car vous n'implémentez pas les nouvelles choses.

@Override sur les implémenteurs d'interface n'aurait jamais dû être autorisé en 1.6, et avec l'éclipse choisissant malheureusement d'insérer automatiquement les annotations comme comportement par défaut, nous obtenons beaucoup de fichiers source encombrés. Lors de la lecture du code 1.6, vous ne pouvez pas voir dans l'annotation @Override si une méthode remplace réellement une méthode dans la superclasse ou implémente simplement une interface.

Utiliser @Override pour remplacer une méthode dans une superclasse est très bien.

Rune
la source
2
Les opinions divergent sur ce point. Voir stackoverflow.com/questions/212614/… .
sleske
8

Il est préférable de l'utiliser pour chaque méthode destinée à remplacer, et Java 6+, chaque méthode conçue comme implémentation d'une interface.

Tout d'abord, il capture les fautes d'orthographe comme " hashcode()" au lieu de " hashCode()" au moment de la compilation. Il peut être déconcertant de déboguer pourquoi le résultat de votre méthode ne semble pas correspondre à votre code lorsque la vraie cause est que votre code n'est jamais appelé.

De plus, si une superclasse modifie une signature de méthode, les remplacements de l'ancienne signature peuvent être "orphelins", laissés pour cause de code mort déroutant. L' @Overrideannotation vous aidera à identifier ces orphelins afin qu'ils puissent être modifiés pour correspondre à la nouvelle signature.

erickson
la source
7

Si vous vous retrouvez très souvent devant des méthodes (non abstraites), vous voudrez probablement jeter un œil à votre conception. Il est très utile lorsque le compilateur ne détecterait pas l'erreur autrement. Par exemple, essayer de remplacer initValue () dans ThreadLocal, ce que j'ai fait.

Utiliser @Override lors de l'implémentation de méthodes d'interface (fonctionnalité 1.6+) me semble un peu exagéré. Si vous avez beaucoup de méthodes dont certaines écrasent et d'autres non, c'est probablement une mauvaise conception à nouveau (et votre éditeur montrera probablement laquelle est si vous ne le savez pas).

Tom Hawtin - sellerie
la source
2
En fait, c'est aussi bien pour les méthodes d'interface surchargées. Si, par exemple, je supprime une ancienne méthode obsolète d'une interface, cette méthode devrait également être supprimée de toutes les classes d'implémentation - facile à repérer si elles utilisent @override.
Dominik Sandjaja
7

@Override sur les interfaces est en fait utile, car vous obtiendrez des avertissements si vous modifiez l'interface.

Asgeir S. Nilsen
la source
7

Une autre chose qu'il fait est qu'il rend plus évident lors de la lecture du code qu'il modifie le comportement de la classe parente. Que peut aider au débogage.

De plus, dans le livre de Joshua Block Effective Java (2e édition), l'article 36 donne plus de détails sur les avantages de l'annotation.

Diastrophisme
la source
Oui, en effet - article 36 :)
Chris Kimpton
6

Cela n'a aucun sens d'utiliser @Override lors de l'implémentation d'une méthode d'interface. Il n'y a aucun avantage à l'utiliser dans ce cas - le compilateur détectera déjà votre erreur, donc c'est juste un encombrement inutile.

Steve R.
la source
6
L'utilisation @Overridesur une interface vous obligera à remarquer lorsqu'une méthode de l'interface est supprimée.
Alex B
@Alex: Supprimer des méthodes dans une interface est un changement de rupture, comme les ajouter. Une fois qu'une interface est publiée, elle est effectivement verrouillée, sauf si vous avez un contrôle complet sur tout le code qui l'utilise.
Lawrence Dol
6

Chaque fois qu'une méthode remplace une autre méthode ou qu'une méthode implémente une signature dans une interface.

L' @Overrideannotation vous assure que vous avez en fait remplacé quelque chose. Sans l'annotation, vous risquez une faute d'orthographe ou une différence dans les types et le nombre de paramètres.

Greg Mattes
la source
1
Vous ne pouvez l'utiliser que pour marquer l'implémentation de l'interface dans Java 1.6
Dave L.
5

Je l'utilise à chaque fois. C'est plus d'informations que je peux utiliser pour comprendre rapidement ce qui se passe lorsque je revisite le code dans un an et j'ai oublié ce que je pensais la première fois.

Hank Gay
la source
5

La meilleure pratique est de toujours l'utiliser (ou de le faire remplir par l'IDE pour vous)

@Override est utile pour détecter les changements dans les classes parentes qui n'ont pas été signalés dans la hiérarchie. Sans elle, vous pouvez changer une signature de méthode et oublier de modifier ses remplacements, avec @Override, le compilateur l'attrapera pour vous.

Ce genre de filet de sécurité est toujours bon à avoir.


la source
1
Donc, si vous changez la méthode parent et que vous n'utilisez pas @Override dans la méthode de la classe enfant, la compilation dira-t-elle quelque chose ou restera-t-elle silencieuse? L'utilisation de "Override" vous donnera-t-elle plus d'informations, et si oui, quoi?
djangofan
5

Je l'utilise partout. Concernant l'effort de marquage des méthodes, je laisse Eclipse le faire pour moi donc, ce n'est pas un effort supplémentaire.

Je suis religieux au sujet du refactoring continu .... donc, je vais utiliser chaque petite chose pour que ça se passe plus facilement.

willCode4Beer
la source
5
  • Utilisé uniquement sur les déclarations de méthode.
  • Indique que la déclaration de méthode annotée remplace une déclaration de supertype.

S'il est utilisé de manière cohérente, il vous protège contre une grande classe de bugs néfastes.

Utilisez l'annotation @Override pour éviter ces bogues: (Repérez le bogue dans le code suivant :)

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());
    }
}

source: Java efficace

I have
la source
Je ne sais pas quelles sont les règles de priorité des opérateurs en Java, mais votre méthode d'égalité crie BUUUUUUUUUUUG! J'écrirais (b.first == first) && (b.second == second), même s'il &&avait une priorité plus faible que ==.
pyon
Saviez-vous que votre lien affiche un message «vous devez vous abonner» couvrant la partie utile de cette page?
Adriano Varoli Piazza
@Adriano: Désolé mec !! Suis impuissant !! Quand j'ai écrit la «réponse», elle était disponible. Pas de soucis ... achetez le livre. Ça vaut le coup !!
jai
5
La méthode equals ne remplace pas: l'original Object::equalsest boolean equals(Object), tandis que le substitué equalsest boolean equals(Bigram), qui a une signature de méthode différente, qui ne remplace pas. L'ajout de @Override à equalsdétectera cette erreur.
Ming-Tang
3

Soyez prudent lorsque vous utilisez Override, car vous ne pouvez pas faire de rétro-ingénierie dans starUML par la suite; faire le uml en premier.

Horatiu Jeflea
la source
2

Il semble que la sagesse change ici. Aujourd'hui, j'ai installé IntelliJ IDEA 9 et j'ai remarqué que son " inspection @Override manquante " n'attrape pas seulement les méthodes abstraites implémentées, mais également les méthodes d'interface implémentées. Dans la base de code de mon employeur et dans mes propres projets, j'ai depuis longtemps l'habitude de n'utiliser @Override que pour les méthodes abstraites précédemment implémentées. Cependant, en repensant l'habitude, le mérite d'utiliser les annotations dans les deux cas devient clair. Bien qu'il soit plus détaillé, il protège contre le problème de classe de base fragile (pas aussi grave que les exemples liés à C ++) où le nom de la méthode d'interface change, rendant orpheline la méthode d'implémentation potentielle dans une classe dérivée.

Bien sûr, ce scénario est principalement hyperbole; la classe dérivée ne compilerait plus, manquant maintenant d'une implémentation de la méthode d'interface renommée, et aujourd'hui on utiliserait probablement une opération de refactorisation de la méthode Renommer pour adresser la base de code entière en masse.

Étant donné que l'inspection d'IDEA n'est pas configurable pour ignorer les méthodes d'interface implémentées, aujourd'hui je changerai à la fois mon habitude et les critères de révision du code de mon équipe.

seh
la source
2

L'annotation @Override est utilisée pour aider à vérifier si le développeur doit remplacer la bonne méthode dans la classe ou l'interface parent. Lorsque le nom des méthodes de super change, le compilateur peut notifier ce cas, ce qui est uniquement pour garder la cohérence avec le super et la sous-classe.

BTW, si nous n'avons pas annoncé l'annotation @Override dans la sous-classe, mais nous remplaçons certaines méthodes du super, alors la fonction peut fonctionner comme celle-là avec le @Override. Mais cette méthode ne peut pas informer le développeur lorsque la méthode du super a été modifiée. Parce qu'il ne connaissait pas le but du développeur - remplacer la méthode de super ou définir une nouvelle méthode?

Donc, lorsque nous voulons remplacer cette méthode pour utiliser le polymorphisme, nous avons intérêt à ajouter @Override au-dessus de la méthode.

lzlstyle
la source
1

Je l'utilise autant que possible pour identifier quand une méthode est remplacée. Si vous regardez le langage de programmation Scala, ils ont également un mot-clé de remplacement. Je le trouve utile.

Berlin Brown
la source
0

Cela vous permet (enfin, le compilateur) d'attraper lorsque vous avez utilisé une mauvaise orthographe sur un nom de méthode que vous remplacez.

JeeBee
la source
0

La substitution d'annotation est utilisée pour tirer parti du compilateur, pour vérifier si vous remplacez réellement une méthode de la classe parente. Il est utilisé pour avertir si vous faites une erreur comme une erreur d'orthographe d'un nom de méthode, une erreur de ne pas correspondre correctement aux paramètres

Siva
la source
0

je pense qu'il est préférable de coder le @override chaque fois que cela est autorisé. cela aide au codage. cependant, à noter, pour ecipse Helios, sdk 5 ou 6, l'annotation @override pour les méthodes d'interface implémentées est autorisée. comme pour Galileo, 5 ou 6, l'annotation @override n'est pas autorisée.

lwpro2
la source
0

Les annotations fournissent des métadonnées sur le code au compilateur et l'annotation @Override est utilisée en cas d'héritage lorsque nous remplaçons toute méthode de classe de base. Il indique simplement au compilateur que vous remplacez la méthode. Cela peut éviter certains types d'erreurs courantes que nous pouvons faire comme ne pas suivre la signature appropriée de la méthode ou mal orthographier le nom de la méthode, etc. C'est donc une bonne pratique d'utiliser l'annotation @Override.

gprathour
la source
0

Pour moi, le @Override m'assure que j'ai la signature de la méthode correcte. Si je mets l'annotation et que la méthode n'est pas correctement orthographiée, le compilateur se plaint de me faire savoir que quelque chose ne va pas.

Vallée
la source
0

Simple: lorsque vous souhaitez remplacer une méthode présente dans votre superclasse, utilisez l' @Overrideannotation pour effectuer une substitution correcte. Le compilateur vous avertira si vous ne le remplacez pas correctement.

Sree
la source