Quando usi l'annotazione @Override di Java e perché?


498

Quali sono le migliori pratiche per l'utilizzo @Overridedell'annotazione Java e perché?

Sembra che sarebbe eccessivo contrassegnare ogni singolo metodo ignorato con l' @Overrideannotazione. Ci sono alcune situazioni di programmazione che richiedono l'utilizzo di @Overridee altre che non dovrebbero mai usare @Override?

Risposte:


515

Usalo ogni volta che sostituisci un metodo per due vantaggi. Fallo in modo che tu possa trarre vantaggio dal controllo del compilatore per assicurarti di sostituire un metodo quando pensi di esserlo. In questo modo, se si commette un errore comune nel digitare erroneamente il nome di un metodo o nel non corrispondere correttamente ai parametri, si verrà avvertiti che il metodo non ha la precedenza su come si pensa. In secondo luogo, semplifica la comprensione del codice perché è più ovvio quando i metodi vengono sovrascritti.

Inoltre, in Java 1.6 è possibile utilizzarlo per contrassegnare quando un metodo implementa un'interfaccia per gli stessi vantaggi. Penso che sarebbe meglio avere un'annotazione separata (come @Implements), ma è meglio di niente.


4
Sulla stessa linea di "più facile da capire", gli IDE individueranno l'annotazione @Override e contrassegneranno visivamente il metodo prevalente nell'editor.
Bob Cross,

47
Alcuni IDE contrassegneranno un metodo ignorato in cui manca anche l'annotazione @Override.
Jay R.

20
L'altro vantaggio è che se la classe genitore cambia, il compilatore si assicurerà che anche le classi figlie siano state aggiornate.
David,

4
@Jay R .: True. È un dato di fatto, ad esempio Eclipse può anche aggiungere automaticamente @Override se manca.
sleske,

32
Nel caso in cui qualcun altro fosse arrivato qui a causa della modifica apparentemente non documentata da 1.5 a 1.6 per @Overrides sui metodi provenienti dalle interfacce, bugs.sun.com/bugdatabase/view_bug.do?bug_id=5008260 sembra essere il bug corrispondente. (Grazie per averlo segnalato, Dave L.!)
Henrik Heimbuerger,

110

Penso che sia più utile come promemoria in fase di compilazione che l'intenzione del metodo è quella di sovrascrivere un metodo genitore. Come esempio:

protected boolean displaySensitiveInformation() {
  return false;
}

Vedrai spesso qualcosa come il metodo sopra che sovrascrive un metodo nella classe base. Questo è un dettaglio di implementazione importante di questa classe: non vogliamo che vengano visualizzate informazioni sensibili.

Supponiamo che questo metodo sia cambiato nella classe genitore in

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

Questa modifica non causerà errori o avvisi in fase di compilazione, ma modifica completamente il comportamento previsto della sottoclasse.

Per rispondere alla tua domanda: dovresti usare l'annotazione @Override se la mancanza di un metodo con la stessa firma in una superclasse è indicativa di un bug.


46

Ci sono molte buone risposte qui, quindi lasciami offrire un altro modo di guardarlo ...

Non vi è alcun eccesso durante la codifica. Digitare @override non ti costa nulla, ma i risparmi possono essere enormi se hai sbagliato l'ortografia del nome di un metodo o hai sbagliato leggermente la firma.

Pensaci in questo modo: nel tempo in cui hai navigato qui e digitato questo post, hai praticamente usato più tempo di quanto trascorrerai digitando @override per il resto della tua vita; ma un errore che impedisce può farti risparmiare ore.

Java fa tutto il possibile per assicurarsi di non aver commesso errori in fase di modifica / compilazione, questo è un modo virtualmente gratuito per risolvere un'intera classe di errori che non sono prevenibili in altro modo al di fuori dei test completi.

Potresti trovare un meccanismo migliore in Java per garantire che quando l'utente intendeva sovrascrivere un metodo, lo facesse davvero?

Un altro effetto ordinato è che se non fornisci l'annotazione ti avviserà in fase di compilazione che hai accidentalmente scavalcato un metodo genitore - qualcosa che potrebbe essere significativo se non avessi intenzione di farlo.


3
"Non c'è overkill durante la programmazione." Sono d'accordo con questo, motivo per cui trovo che i lang dinamici siano così sbagliati (anche se il 100% del mio lavoro retribuito è in ruby ​​in questo momento).
Dan Rosenstark,

4
+1: ho avuto, forse, 10 bug causati da un errore durante l'override - il tempo necessario per trovarne uno avrebbe facilmente superato il tempo di digitare @Override su ciascuno dei miei metodi di override. Inoltre, se @Override è un po 'oneroso, probabilmente stai sfruttando eccessivamente l'ereditarietà.
Lawrence Dol,

7
Uno svantaggio molto reale è che si rende il codice più difficile da leggere sporcandolo di lumache. Forse questo è un difetto del mio IDE, ma l'ho provato anche io.
Tratta bene le tue mod il

9
@phyzome Se ritieni che le "Lumache" siano ingombranti, non stai usando OVUNQUE VICINO a commenti sufficienti. Dovrebbero essere solo una riga sopra l'intestazione del metodo che dovrebbe essere grande quanto il tuo metodo nella maggior parte dei casi (alcune righe) per fornire testo e javadocs decenti. Immagino che sto dicendo che il problema non sono le lumache, sono le tue abitudini di lettura. Anche tutte quelle parentesi nel codice ti danno fastidio?
Bill K,

4
Sì, la codifica è eccessiva: quando scrivi commenti che pappagalli semplicemente ciò che il codice fa ovviamente.
Formiche

22

Uso sempre il tag. È un semplice flag di compilazione per rilevare piccoli errori che potrei fare.

Catturerà cose come tostring()invece ditoString()

Le piccole cose aiutano nei grandi progetti.


18

L'uso @Overridedell'annotazione funge da protezione in fase di compilazione da un errore di programmazione comune. Verrà generato un errore di compilazione se si dispone dell'annotazione su un metodo che non si sta effettivamente ignorando il metodo superclasse.

Il caso più comune in cui ciò è utile è quando si modifica un metodo nella classe base per avere un elenco di parametri diverso. Un metodo in una sottoclasse utilizzato per sovrascrivere il metodo superclasse non lo farà più a causa della firma del metodo modificata. Questo a volte può causare comportamenti strani e inaspettati, specialmente quando si tratta di strutture ereditarie complesse. L' @Overrideannotazione salvaguarda da ciò.


Migliore risposta. Breve e dolce Vorrei che tu potessi spiegare come funziona la "salvaguardia" .... nessuno ha spiegato questo.
Djangofan,

È semplice da spiegare. Se commetti un errore (modificando l'interfaccia, la classe astratta o la sottoclasse, riceverai un avviso (come in Eclipse) o un errore di compilazione che ti informa che @Override non funziona. il messaggio dipenderà da ciò che è stato modificato, ma in Eclipse (ad esempio) è molto chiaro molto rapidamente che c'è un problema: vedrai quel piccolo zigzag rosso sottolineato e un passaggio del mouse sopra il testo offensivo ti dirà cosa c'è che non va. Lo chiamo buon valore
Ichiro Furusato,

14

Per trarre vantaggio dal controllo del compilatore, è necessario utilizzare sempre l'annullamento dell'annotazione. Ma non dimenticare che Java Compiler 1.5 non consentirà questa annotazione quando si sovrascrivono i metodi di interfaccia. Puoi semplicemente usarlo per sovrascrivere i metodi di classe (astratti o meno).

Alcuni IDE, come Eclipse, anche configurati con runtime Java 1.6 o versione successiva, mantengono la conformità con Java 1.5 e non consentono l'uso @override come descritto sopra. Per evitare questo comportamento, è necessario andare su: Proprietà progetto -> Compilatore Java -> Seleziona “Abilita impostazioni specifiche del progetto” -> Scegli “Livello di conformità del compilatore” = 6.0 o superiore.

Mi piace usare questa annotazione ogni volta che sovrascrivo un metodo in modo indipendente, se la base è un'interfaccia o una classe.

Questo ti aiuta a evitare alcuni errori tipici, come quando pensi di sovrascrivere un gestore di eventi e quindi non vedi nulla. Immagina di voler aggiungere un listener di eventi ad alcuni componenti dell'interfaccia utente:

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

Il codice sopra viene compilato ed eseguito, ma se si sposta il mouse all'interno di un componente USB, il codice "fai qualcosa" noterà l'esecuzione, perché in realtà non si sta sovrascrivendo il metodo di base mouseEntered(MouseEvent ev). Devi solo creare un nuovo metodo senza parametri mouseEntered(). Invece di quel codice, se hai usato l' @Overrideannotazione hai visto un errore di compilazione e non hai perso tempo a pensare al motivo per cui il gestore di eventi non era in esecuzione.


8

@Override sull'implementazione dell'interfaccia è incoerente poiché non esiste qualcosa come "l'override di un'interfaccia" in java.

@Override sull'implementazione dell'interfaccia è inutile poiché in pratica non rileva alcun bug che la compilazione non catturerebbe comunque. Esiste solo uno scenario di gran lunga inverosimile in cui l'override sugli implementatori fa effettivamente qualcosa: se si implementa un'interfaccia e l'interfaccia RIMUOVE i metodi, si riceverà una notifica in fase di compilazione che è necessario rimuovere le implementazioni non utilizzate. Si noti che se la nuova versione dell'interfaccia ha metodi NUOVI o CAMBIATI, ovviamente si otterrà comunque un errore di compilazione poiché non si stanno implementando le nuove cose.

@Override sugli implementatori di interfaccia non avrebbe mai dovuto essere permesso in 1.6, e con l'eclissi che purtroppo sceglie di inserire automaticamente le annotazioni come comportamento predefinito, otteniamo molti file sorgente ingombra. Quando si legge il codice 1.6, dall'annotazione @Override non è possibile vedere se un metodo sovrascrive effettivamente un metodo nella superclasse o implementa semplicemente un'interfaccia.

L'uso di @Override quando si esegue l'override di un metodo in una superclasse va bene.


2
Esistono opinioni diverse su questo punto. Vedi stackoverflow.com/questions/212614/… .
sleske,

8

È meglio usarlo per ogni metodo inteso come override e Java 6+, ogni metodo inteso come implementazione di un'interfaccia.

Innanzitutto, rileva errori di ortografia come " hashcode()" anziché " hashCode()" al momento della compilazione. Può essere sconcertante eseguire il debug del motivo per cui il risultato del metodo non sembra corrispondere al codice quando la vera causa è che il codice non viene mai invocato.

Inoltre, se una superclasse modifica una firma del metodo, le sostituzioni della firma precedente possono essere "orfane", lasciate come codice morto confuso. L' @Overrideannotazione ti aiuterà a identificare questi orfani in modo che possano essere modificati per corrispondere alla nuova firma.


7

Se ti trovi a scavalcare metodi (non astratti) molto spesso, probabilmente vorrai dare un'occhiata al tuo design. È molto utile quando altrimenti il ​​compilatore non rileva l'errore. Ad esempio, cercando di sovrascrivere initValue () in ThreadLocal, cosa che ho fatto.

L'uso di @Override durante l'implementazione dei metodi di interfaccia (funzionalità 1.6+) mi sembra un po 'eccessivo. Se hai un sacco di metodi, alcuni dei quali hanno la precedenza e altri no, probabilmente quella cattiva progettazione di nuovo (e il tuo editor probabilmente mostrerà quale è se non lo sai).


2
In realtà, è anche bello per i metodi di interfaccia overriden. Se per esempio rimuovo un vecchio metodo deprecato da un'interfaccia, quel metodo dovrebbe essere rimosso anche da tutte le classi di implementazione - facile individuarli se usano @override.
Dominik Sandjaja,

7

@Override sulle interfacce in realtà sono utili, perché riceverai avvisi se cambi l'interfaccia.


7

Un'altra cosa che fa è che rende più ovvio durante la lettura del codice che sta cambiando il comportamento della classe genitore. Che può aiutare nel debug.

Inoltre, nel libro di Joshua Block Effective Java (2a edizione), l'articolo 36 fornisce maggiori dettagli sui vantaggi dell'annotazione.


Sì, davvero - voce 36 :)
Chris Kimpton,

6

Non ha assolutamente senso usare @Override quando si implementa un metodo di interfaccia. Non c'è alcun vantaggio nell'usarlo in quel caso: il compilatore colpirà già il tuo errore, quindi è solo un ingombro inutile.


6
L'uso @Overridesu un'interfaccia ti costringerà a notare quando viene rimosso un metodo nell'interfaccia.
Alex B,

@Alex: la rimozione dei metodi in un'interfaccia è una modifica rivoluzionaria, come l'aggiunta di loro. Una volta che un'interfaccia viene pubblicata, viene effettivamente bloccata a meno che tu non abbia il controllo completo su tutto il codice che la utilizza.
Lawrence Dol,

6

Ogni volta che un metodo sovrascrive un altro metodo o un metodo implementa una firma in un'interfaccia.

L' @Overrideannotazione ti assicura che hai effettivamente ignorato qualcosa. Senza l'annotazione si rischia un errore di ortografia o una differenza nei tipi di parametri e nel numero.


1
Puoi usarlo solo per contrassegnare l'implementazione dell'interfaccia in Java 1.6
Dave L.,

5

Lo uso ogni volta. Sono più informazioni che posso usare per capire rapidamente cosa succede quando rivisito il codice in un anno e ho dimenticato cosa stavo pensando la prima volta.


5

La migliore pratica è di usarlo sempre (o far sì che l'IDE li riempia per te)

L'utilità di @Override è quella di rilevare le modifiche nelle classi principali che non sono state riportate nella gerarchia. Senza di esso, puoi cambiare la firma di un metodo e dimenticare di modificarne le sostituzioni, con @Override, il compilatore lo prenderà per te.

Quel tipo di rete di sicurezza è sempre bello avere.


1
Quindi, se cambi il metodo genitore e non usi @Override nel metodo della classe figlio, la compilazione dirà qualcosa o rimarrà in silenzio? L'uso di "Override" ti darà maggiori informazioni e, in caso affermativo, cosa?
Djangofan,

5

Lo uso ovunque. Sul tema dello sforzo per i metodi di marcatura, lascio che Eclipse lo faccia per me, quindi non è uno sforzo aggiuntivo.

Sono religioso riguardo al continuo refactoring .... quindi, userò ogni piccola cosa per farlo andare più agevolmente.


5
  • Utilizzato solo su dichiarazioni di metodi.
  • Indica che la dichiarazione del metodo con annotazioni sovrascrive una dichiarazione in supertipo.

Se usato in modo coerente, ti protegge da una grande classe di bug nefasti.

Usa l'annotazione @Override per evitare questi bug: (Individua il bug nel seguente codice :)

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 efficace


Non so quali siano le regole di precedenza dell'operatore in Java, ma il tuo metodo uguale sta urlando BUUUUUUUUUUUG! Scriverei (b.first == first) && (b.second == second), anche se &&avesse una precedenza inferiore a ==.
pyon,

Sapevi che il tuo link mostra un messaggio 'devi iscriverti' che copre la parte utile di quella pagina?
Adriano Varoli Piazza

@Adriano: scusa amico !! Sono impotente !! Quando ho scritto la "risposta", era disponibile. Nessun problema..acquista il libro. Vale la pena averlo !!
jai,

5
Il metodo equals non sovrascrive: l'originale Object::equalsè boolean equals(Object), mentre lo equalsè sovrascritto boolean equals(Bigram), che ha una diversa firma del metodo, che non sostituisce. L'aggiunta di @Override a equalsrileverà questo errore.
Ming-Tang,

3

Fai attenzione quando usi Override, perché in seguito non puoi fare il reverse engineer in starUML; fare prima l'uml.


2

Sembra che la saggezza qui stia cambiando. Oggi ho installato IntelliJ IDEA 9 e ho notato che il suo " controllo @Override mancante " ora cattura non solo i metodi astratti implementati, ma anche i metodi di interfaccia. Nella base di codice del mio datore di lavoro e nei miei progetti, ho sempre avuto l'abitudine di usare @Override solo per i metodi astratti implementati in precedenza. Tuttavia, ripensando l'abitudine, il merito dell'uso delle annotazioni in entrambi i casi diventa chiaro. Nonostante sia più prolisso, protegge dalla fragile classe base problema della (non grave come gli esempi relativi al C ++) in cui cambia il nome del metodo dell'interfaccia, rendendo orfano il potenziale metodo di implementazione in una classe derivata.

Naturalmente, questo scenario è principalmente iperbole; la classe derivata non si sarebbe più compilata, ora mancava un'implementazione del metodo dell'interfaccia rinominata, e oggi si potrebbe probabilmente utilizzare un'operazione di refactoring del metodo Rename per indirizzare l'intera base di codice in massa.

Dato che l'ispezione IDEA non è configurabile per ignorare i metodi di interfaccia implementati, oggi cambierò sia la mia abitudine sia i criteri di revisione del codice del mio team.


2

L'annotazione @Override viene utilizzata per aiutare a verificare se lo sviluppatore deve sovrascrivere il metodo corretto nella classe o nell'interfaccia padre. Quando il nome dei metodi del super cambia, il compilatore può notificare quel caso, che è solo per mantenere la coerenza con il super e la sottoclasse.

A proposito, se non abbiamo annunciato l'annotazione @Override nella sottoclasse, ma sostituiamo alcuni metodi del super, allora la funzione può funzionare come quella con @Override. Ma questo metodo non può informare lo sviluppatore quando il metodo del super è stato modificato. Perché non conosceva lo scopo dello sviluppatore: ignorare il metodo di Super o definire un nuovo metodo?

Quindi, quando vogliamo sovrascrivere quel metodo per utilizzare il polimorfismo, è meglio aggiungere @Override sopra il metodo.


1

Lo uso il più possibile per identificare quando viene superato un metodo. Se guardi il linguaggio di programmazione Scala, hanno anche una parola chiave override. Lo trovo utile


0

Ti permette (bene, il compilatore) di catturare quando hai usato l'ortografia sbagliata su un nome di metodo che stai scavalcando.


0

L'annullamento dell'annotazione viene utilizzato per sfruttare il compilatore, per verificare se si sta effettivamente sostituendo un metodo dalla classe genitore. Viene utilizzato per avvisare se si commettono errori come errori di ortografia del nome di un metodo, errore di non abbinare correttamente i parametri


0

penso che sia meglio codificare @override ogni volta che è permesso. aiuta per la codifica. tuttavia, va notato che per ecipse Helios, sia sdk 5 che 6, è consentita l'annotazione @override per i metodi di interfaccia implementati. come per Galileo, 5 o 6, l'annotazione @override non è consentita.


0

Le annotazioni forniscono metadati sul codice al compilatore e l'annotazione @Override viene utilizzata in caso di ereditarietà quando sovrascriviamo qualsiasi metodo della classe base. Dice solo al compilatore che stai scavalcando il metodo. Può evitare alcuni tipi di errori comuni che possiamo fare come non seguire la firma corretta del metodo o scrivere in modo errato nel nome del metodo ecc. Quindi è una buona pratica usare l'annotazione @Override.


0

Per me @Override mi assicura che la firma del metodo sia corretta. Se inserisco l'annotazione e il metodo non è scritto correttamente, il compilatore si lamenta facendomi sapere che qualcosa non va.


0

Semplice: quando si desidera sovrascrivere un metodo presente nella propria superclasse, utilizzare l' @Overrideannotazione per effettuare una sostituzione corretta. Il compilatore ti avviserà se non lo sovrascrivi correttamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.