Kiedy używasz adnotacji @Override w Javie i dlaczego?

498

Jakie są najlepsze praktyki korzystania z @Overrideadnotacji Java i dlaczego?

Wygląda na to, że oznaczanie każdej zastąpionej metody @Overrideadnotacją byłoby przesadą . Czy istnieją pewne sytuacje programowania, które wymagają użycia @Overridei innych, które nigdy nie powinny używać @Override?

Alex B.
źródło

Odpowiedzi:

515

Użyj go za każdym razem, gdy przesłonisz metodę, aby uzyskać dwie korzyści. Zrób to, abyś mógł skorzystać z sprawdzania kompilatora, aby upewnić się, że faktycznie zastępujesz metodę, gdy uważasz, że tak. W ten sposób, jeśli popełnisz częsty błąd polegający na błędnej pisowni nazwy metody lub niepoprawnym dopasowaniu parametrów, zostaniesz ostrzeżony, że metoda nie zastępuje tak, jak myślisz. Po drugie, ułatwia zrozumienie kodu, ponieważ jest bardziej oczywiste, gdy metody są zastępowane.

Ponadto w Javie 1.6 można go używać do oznaczania, kiedy metoda implementuje interfejs dla tych samych korzyści. Myślę, że lepiej byłoby mieć osobną adnotację (jak @Implements), ale lepiej niż nic.

Dave L.
źródło
4
W tym samym wierszu, co „łatwiejsze do zrozumienia”, IDE zauważą adnotację @Override i wizualnie oflagują metodę nadpisywania w edytorze.
Bob Cross
47
Niektóre IDE oflagują przesłoniętą metodę, w której również brakuje adnotacji @Override.
Jay R.
20
Inną korzyścią jest to, że jeśli klasa nadrzędna ulegnie zmianie, kompilator upewni się, że klasy podrzędne również zostały zaktualizowane.
David
4
@Jay R .: Prawda. W rzeczywistości np. Eclipse może nawet automatycznie dodać @Override, jeśli go brakuje.
sleske,
32
W przypadku, gdy ktoś tu dotarł z powodu pozornie nieudokumentowanej zmiany z 1.5 na 1.6 dla @Overrides w metodach pochodzących z interfejsów, błąds.sun.com/bugdatabase/view_bug.do?bug_id=5008260 wydaje się być odpowiednim błędem. (Dzięki za zwrócenie uwagi, Dave L.!)
Henrik Heimbuerger
110

Myślę, że jest to najbardziej przydatne jako przypomnienie w czasie kompilacji, że celem metody jest zastąpienie metody nadrzędnej. Jako przykład:

protected boolean displaySensitiveInformation() {
  return false;
}

Często można zobaczyć coś takiego jak powyższa metoda, która zastępuje metodę w klasie bazowej. Jest to ważny szczegół implementacyjny tej klasy - nie chcemy, aby wrażliwe informacje były wyświetlane.

Załóżmy, że ta metoda została zmieniona w klasie nadrzędnej na

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

Ta zmiana nie spowoduje żadnych błędów lub ostrzeżeń podczas kompilacji - ale całkowicie zmienia zamierzone zachowanie podklasy.

Aby odpowiedzieć na twoje pytanie: powinieneś użyć adnotacji @Override, jeśli brak metody o tej samej sygnaturze w nadklasie wskazuje na błąd.

jon
źródło
46

Jest tu wiele dobrych odpowiedzi, więc pozwólcie, że zaoferuję inny sposób spojrzenia na to ...

Podczas kodowania nie ma nadmiaru. Wpisanie @ override nie kosztuje nic, ale oszczędności mogą być ogromne, jeśli źle wpisałeś nazwę metody lub nieco popełniłeś błąd.

Pomyśl o tym w ten sposób: w czasie, gdy nawigowałeś tutaj i pisałeś ten post, prawie przeznaczyłeś więcej czasu niż na pisanie @override przez resztę życia; ale jeden błąd, który zapobiega, może zaoszczędzić wiele godzin.

Java robi wszystko, aby upewnić się, że nie popełniłeś żadnych błędów w czasie edycji / kompilacji, jest to praktycznie darmowy sposób na rozwiązanie całej klasy błędów, których nie można zapobiec w żaden inny sposób poza kompleksowymi testami.

Czy mógłbyś wymyślić lepszy mechanizm w Javie, aby upewnić się, że kiedy użytkownik zamierzał zastąpić metodę, faktycznie to zrobił?

Kolejnym ciekawym efektem jest to, że jeśli nie dostarczysz adnotacji, w czasie kompilacji ostrzeże Cię, że przypadkowo zastąpiłeś metodę nadrzędną - coś, co może być znaczące, jeśli nie zamierzasz tego robić.

Bill K.
źródło
3
„Podczas kodowania nie ma nadmiaru”. Zgadzam się z tym, dlatego uważam, że dynamiczne języki są tak błędne (chociaż 100% mojej płatnej pracy jest teraz w rubinach).
Dan Rosenstark,
4
+1: Być może miałem 10 błędów spowodowanych błędem w przesłonięciu - czas potrzebny na znalezienie jednego z nich z łatwością przekroczyłby czas na napisanie @Override dla każdej z moich zastępujących metod. Poza tym, jeśli @Override jest uciążliwe, prawdopodobnie nadmiernie korzystasz z dziedziczenia.
Lawrence Dol
7
Jednym bardzo poważnym minusem jest to, że utrudniasz czytanie kodu, zaśmiecając go ślimakami. Być może jest to wina mojego IDE, ale sam tego doświadczyłem.
traktuj swoje mody dobrze
9
@ phyzome Jeśli uważasz, że „Ślimaki” są uciążliwe, nie używasz NIGDY W POBLIŻU wystarczającej liczby komentarzy. Powinny być one po prostu pojedynczą linią nad nagłówkiem metody, która powinna być w większości przypadków tak duża jak metoda w większości przypadków (kilka linii), aby zapewnić przyzwoity tekst zawisu i javadocs. Myślę, że mówię, że problemem nie są Ślimaki, to twoje nawyki czytania. Czy przeszkadzają ci też wszystkie nawiasy w kodzie?
Bill K
4
Tak, kodowanie jest przesadne: kiedy piszesz komentarze, które tylko papugują to, co oczywiście robi kod.
Mrówki
22

Zawsze używam tagu. Jest to prosta flaga czasu kompilacji do wychwytywania drobnych błędów, które mogę popełnić.

Będzie łapał rzeczy takie jak tostring()zamiasttoString()

Małe rzeczy pomagają w dużych projektach.

jjnguy
źródło
18

Korzystanie z @Overrideadnotacji działa jako zabezpieczenie podczas kompilacji przed powszechnym błędem programistycznym. Zgłasza błąd kompilacji, jeśli masz adnotację do metody, której tak naprawdę nie przesłaniasz metody nadklasy.

Najczęstszym przypadkiem, gdy jest to przydatne, jest zmiana metody w klasie bazowej na inną listę parametrów. Metoda w podklasie, która została użyta do zastąpienia metody nadklasy, nie będzie już tego robić ze względu na zmienioną sygnaturę metody. Może to czasem powodować dziwne i nieoczekiwane zachowanie, szczególnie w przypadku złożonych struktur dziedziczenia. Do @Overridezabezpieczenia adnotacji przed tym.

toluju
źródło
Najlepsza odpowiedź. Krótkie i słodkie. Chciałbym, żebyś mógł wyjaśnić, jak działa „zabezpieczenie”… nikt tego nie wyjaśnił.
djangofan
Łatwo to wyjaśnić. Jeśli popełnisz błąd (zmieniając interfejs, klasę abstrakcyjną lub podklasę, otrzymasz ostrzeżenie (na przykład w środowisku Eclipse) lub błąd kompilacji informujący, że @Override nie działa. Rzeczywisty błąd wiadomość będzie zależała od tego, co zostało zmienione, ale w Eclipse (na przykład) bardzo szybko widać, że jest problem: zobaczysz to małe czerwone zygzak podkreślone, a najechanie kursorem na obrażający tekst powie ci, co jest nie tak. Nazywam to dobrą wartością
Ichiro Furusato,
14

Aby skorzystać z sprawdzania kompilatora, należy zawsze używać adnotacji Zastąp. Ale nie zapominaj, że Java Compiler 1.5 nie zezwoli na tę adnotację podczas przesłonięcia metod interfejsu. Możesz po prostu użyć go do zastąpienia metod klasowych (abstrakcyjnych lub nie).

Niektóre środowiska IDE, takie jak Eclipse, nawet skonfigurowane ze środowiskiem wykonawczym Java 1.6 lub nowszym, zachowują zgodność z Java 1.5 i nie pozwalają na użycie @override, jak opisano powyżej. Aby tego uniknąć, należy przejść do: Właściwości projektu -> Kompilator Java -> Zaznacz „Włącz ustawienia specyficzne dla projektu” -> Wybierz „Poziom zgodności kompilatora” = 6.0 lub wyższy.

Lubię używać tej adnotacji za każdym razem, gdy nadpisuję metodę niezależnie, jeśli baza jest interfejsem lub klasą.

Pomaga to uniknąć typowych błędów, na przykład gdy myślisz, że przesłoniłeś moduł obsługi zdarzeń, a potem nic się nie dzieje. Wyobraź sobie, że chcesz dodać detektor zdarzeń do niektórych składników interfejsu użytkownika:

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

Powyższy kod kompiluje się i uruchamia, ale jeśli poruszysz myszą wewnątrz jakiegoś komponentu UIC, kod „zrób coś” zapisze polecenie uruchomienia, ponieważ tak naprawdę nie zastępujesz metody podstawowej mouseEntered(MouseEvent ev). Właśnie tworzysz nową metodę bez parametrów mouseEntered(). Zamiast tego kodu, jeśli użyłeś @Overrideadnotacji, zobaczyłeś błąd kompilacji i nie marnowałeś czasu na zastanawianie się, dlaczego program obsługi zdarzeń nie działa.

Donal Fellows
źródło
8

@Override w sprawie implementacji interfejsu jest niespójny, ponieważ nie ma czegoś takiego jak „przesłanianie interfejsu” w java.

@Override w sprawie implementacji interfejsu jest bezużyteczny, ponieważ w praktyce nie wyłapuje błędów, których kompilacja i tak nie wychwyciłaby. Jest tylko jeden, dalekosiężny scenariusz, w którym przesłonięcie implementatorów faktycznie coś robi: Jeśli zaimplementujesz interfejs, a interfejs USUWA metody, zostaniesz powiadomiony w czasie kompilacji, że powinieneś usunąć nieużywane implementacje. Zauważ, że jeśli nowa wersja interfejsu ma NOWE lub ZMIENIONE metody, oczywiście i tak dostaniesz błąd kompilacji, ponieważ nie wdrażasz nowych rzeczy.

@Override na implementatorach interfejsów nigdy nie powinno być dozwolone w wersji 1.6, a ponieważ zaćmienie ze smutkiem decyduje się na automatyczne wstawianie adnotacji jako zachowanie domyślne, otrzymujemy wiele zaśmieconych plików źródłowych. Podczas czytania kodu 1.6 z adnotacji @Override nie można zobaczyć, czy metoda faktycznie przesłania metodę w nadklasie lub po prostu implementuje interfejs.

Użycie @Override podczas faktycznego nadpisywania metody w nadklasie jest w porządku.

Runa
źródło
2
Istnieją różne opinie na ten temat. Zobacz stackoverflow.com/questions/212614/… .
sleske,
8

Najlepiej jest używać go do każdej metody przewidzianej jako zastąpienie, a Java 6+, każda metoda przeznaczona jako implementacja interfejsu.

Po pierwsze, wychwytuje błędy pisowni, takie jak „ hashcode()” zamiast „ hashCode()” podczas kompilacji. Debugowanie, dlaczego wynik metody wydaje się nie pasować do kodu, może być kłopotliwe, gdy prawdziwą przyczyną jest to, że kod nigdy nie jest wywoływany.

Ponadto, jeśli superklasa zmienia podpis metody, przesłania starszego podpisu można „osierocić”, pozostawiając jako mylący martwy kod. @OverrideAdnotacja pomoże Ci zidentyfikować te sieroty tak, że mogą one być modyfikowane, aby dopasować nowy podpis.

erickson
źródło
7

Jeśli często zastępujesz (nieabstrakcyjne) metody, prawdopodobnie zechcesz rzucić okiem na swój projekt. Jest to bardzo przydatne, gdy kompilator nie wychwyciłby błędu. Na przykład próba zastąpienia initValue () w ThreadLocal, co zrobiłem.

Używanie @Override podczas implementowania metod interfejsu (funkcja 1.6+) wydaje mi się nieco przesadne. Jeśli masz mnóstwo metod, z których niektóre zastępują, a niektóre nie, prawdopodobnie ten zły projekt ponownie (a twój edytor prawdopodobnie pokaże, który z nich, jeśli nie wiesz).

Tom Hawtin - tackline
źródło
2
W rzeczywistości jest to również przydatne w przypadku przesłoniętych metod interfejsu. Jeśli np. Usunę starą, przestarzałą metodę z interfejsu, metoda ta powinna zostać również usunięta ze wszystkich klas implementujących - łatwo je wykryć, jeśli używają @override.
Dominik Sandjaja,
7

@Override na interfejsach faktycznie są pomocne, ponieważ otrzymasz ostrzeżenia, jeśli zmienisz interfejs.

Asgeir S. Nilsen
źródło
7

Inną rzeczą, jaką robi, jest to, że podczas czytania kodu staje się bardziej oczywiste, że zmienia zachowanie klasy nadrzędnej. Niż może pomóc w debugowaniu.

Również w książce Joshua Blocka Effective Java (wydanie drugie) pozycja 36 podaje więcej szczegółów na temat korzyści z adnotacji.

Diastrofizm
źródło
Tak, rzeczywiście - pozycja 36 :)
Chris Kimpton
6

Nie ma absolutnie żadnego sensu używanie @Override podczas implementacji metody interfejsu. W takim przypadku nie ma żadnej korzyści - kompilator już złapie twój błąd, więc jest to po prostu niepotrzebny bałagan.

Steve R.
źródło
6
Używanie @Overrideinterfejsu zmusi cię do zauważenia, że ​​metoda interfejsu została usunięta.
Alex B
@Alex: Usuwanie metod w interfejsie jest przełomową zmianą, podobnie jak ich dodawanie. Po opublikowaniu interfejs jest skutecznie blokowany, chyba że masz pełną kontrolę nad całym kodem, który go używa.
Lawrence Dol
6

Ilekroć metoda zastępuje inną metodę lub metoda implementuje podpis w interfejsie.

@OverrideAdnotacja zapewni, że rzeczywiście wymuszenia czegoś. Bez adnotacji ryzykujesz błąd ortograficzny lub różnicę w typach i liczbie parametrów.

Greg Mattes
źródło
1
Możesz go używać tylko do oznaczania implementacji interfejsu w Javie 1.6
Dave L.
5

Używam go za każdym razem. To więcej informacji, których mogę użyć, aby szybko dowiedzieć się, co się dzieje, kiedy ponownie odwiedzam kod za rok i zapomniałem, o czym myślałem za pierwszym razem.

Hank Gay
źródło
5

Najlepiej jest zawsze go używać (lub poprosić o wypełnienie go przez IDE)

Przydatnością @Override jest wykrywanie zmian w klasach nadrzędnych, które nie zostały zgłoszone w hierarchii. Bez niego możesz zmienić sygnaturę metody i zapomnieć o zmianie jej nadpisań, dzięki @Override kompilator złapie ją za ciebie.

Tego rodzaju siatkę bezpieczeństwa zawsze warto mieć.


źródło
1
Jeśli więc zmienisz metodę nadrzędną, a nie użyjesz @Override w metodzie klasy podrzędnej, czy kompilacja powie cokolwiek lub pozostanie cicho? Czy użycie „Zastąpienia” dostarczy Ci więcej informacji, a jeśli tak, to co?
djangofan
5

Używam go wszędzie. Jeśli chodzi o wysiłek dotyczący metod oznaczania, pozwalam Eclipse zrobić to za mnie, więc nie jest to dodatkowy wysiłek.

Jestem religijny w kwestii ciągłego refaktoryzacji ... więc wykorzystam każdą drobiazg, aby wszystko poszło gładko.

willCode4Beer
źródło
5
  • Używany tylko w deklaracjach metod.
  • Wskazuje, że deklaracja metody z komentarzem zastępuje deklarację w nadtypie.

Przy konsekwentnym stosowaniu chroni przed dużą klasą niecnych błędów.

Użyj adnotacji @Override, aby uniknąć tych błędów: (Znajdź błąd w następującym kodzie :)

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

źródło: Skuteczna Java

jai
źródło
Nie wiem, jakie są reguły pierwszeństwa operatorów w Javie, ale twoja metoda równości krzyczy BUUUUUUUUUUUG! Pisałbym (b.first == first) && (b.second == second), nawet gdyby &&miał niższy priorytet niż ==.
pyon
Czy wiesz, że Twój link zawiera komunikat „musisz subskrybować” obejmujący przydatną część tej strony?
Adriano Varoli Piazza
@Adriano: Przepraszam stary !! Jestem bezradny !! Kiedy napisałem „odpowiedź”, była dostępna. Bez obaw .. kup książkę. Warto to mieć !!
jai
5
Równości sposób nie zastępują: Oryginał Object::equalsjest boolean equals(Object), gdy przesłonięte equalsjest boolean equals(Bigram), który ma inną metodę podpis, który nie zastępuje. Dodanie @Override do equalsspowoduje wykrycie tego błędu.
Ming-Tang,
3

Zachowaj ostrożność podczas korzystania z funkcji Zastąp, ponieważ później nie można wykonać inżynierii wstecznej w starUML; zrób uml pierwszy.

Horatiu Jeflea
źródło
2

Wydaje się, że mądrość tutaj się zmienia. Dzisiaj zainstalowałem IntelliJ IDEA 9 i zauważyłem, że jego „ brakująca kontrola @Override ” teraz wychwytuje nie tylko zaimplementowane metody abstrakcyjne, ale także zaimplementowane metody interfejsu. W bazie kodu mojego pracodawcy i we własnych projektach od dawna miałem zwyczaj używać @Override tylko dla wcześniejszych metod abstrakcyjnych. Jednakże, przemyślenie nawyku, zalety korzystania z adnotacji w obu przypadkach stają się jasne. Mimo że jest bardziej szczegółowy, chroni przed delikatnym problemem klasy bazowej (nie tak poważnym jak przykłady związane z C ++), w którym zmienia się nazwa metody interfejsu, osierocając potencjalną metodę implementacji w klasie pochodnej.

Oczywiście ten scenariusz to głównie hiperbola; klasa pochodna nie będzie się już kompilować, teraz brakuje jej implementacji metody interfejsu o zmienionej nazwie, a dziś prawdopodobnie można by użyć operacji refaktoryzacji Rename Method w celu masowego rozwiązania całej bazy kodu.

Biorąc pod uwagę, że inspekcji IDEA nie można skonfigurować w celu zignorowania zaimplementowanych metod interfejsu, dzisiaj zmienię zarówno mój nawyk, jak i kryteria przeglądu kodu mojego zespołu.

seh
źródło
2

Adnotacja @Override służy do sprawdzenia, czy programista ma przesłonić poprawną metodę w klasie nadrzędnej lub interfejsie. Gdy zmienia się nazwa metod super, kompilator może powiadomić o tym przypadku, co służy wyłącznie zachowaniu spójności z superklasą i podklasą.

BTW, jeśli nie podamy adnotacji @Override w podklasie, ale zastąpimy niektóre metody super, wtedy funkcja może działać tak jak ta z @Override. Ale ta metoda nie może powiadomić dewelopera o zmianie metody super. Ponieważ nie znał celu programisty - zastąpić metodę super lub zdefiniować nową metodę?

Więc jeśli chcemy zastąpić tę metodę, aby skorzystać z polimorfizmu, lepiej dodać @Override powyżej metody.

lzlstyle
źródło
1

Używam go tak często, jak to możliwe, aby zidentyfikować, kiedy metoda jest zastępowana. Jeśli spojrzysz na język programowania Scala, mają również słowo kluczowe zastępujące. Uważam to za przydatne.

Berlin Brown
źródło
0

Pozwala to (cóż, kompilatorowi) na wychwycenie, gdy użyłeś niewłaściwej pisowni w zastępowanej nazwie metody.

JeeBee
źródło
0

Adnotacja zastępowania służy do korzystania z kompilatora w celu sprawdzenia, czy faktycznie przesłaniasz metodę z klasy nadrzędnej. Służy do powiadamiania, jeśli popełnisz jakiś błąd, np. Błąd w pisowni nazwy metody, błąd niewłaściwego dopasowania parametrów

Siva
źródło
0

myślę, że najlepiej zakodować @ override, ilekroć jest to dozwolone. pomaga w kodowaniu. należy jednak zauważyć, że w przypadku ecipse Helios, sdk 5 lub 6, dozwolona jest adnotacja @override dla zaimplementowanych metod interfejsu. podobnie jak w przypadku Galileo, 5 lub 6, adnotacja @ override jest niedozwolona.

lwpro2
źródło
0

Adnotacje dostarczają kompilatorowi metadane dotyczące kodu, a adnotacja @Override jest używana w przypadku dziedziczenia, gdy zastępujemy dowolną metodę klasy podstawowej. Po prostu informuje kompilator, że zastępujesz metodę. Pozwala to uniknąć niektórych typowych błędów, które możemy popełnić, takich jak nieprzestrzeganie poprawnego podpisu metody lub literówka w nazwie metody itp. Dlatego dobrą praktyką jest stosowanie adnotacji @Override.

gprathour
źródło
0

Dla mnie @Override zapewnia, że ​​mam poprawny podpis metody. Jeśli wstawię adnotację, a metoda nie jest poprawnie napisana, kompilator narzeka, informując mnie, że coś jest nie tak.

Dołek
źródło
0

Prosty - jeśli chcesz zastąpić metodę obecną w swojej nadklasie, użyj @Overrideadnotacji, aby dokonać prawidłowego zastąpienia. Kompilator ostrzeże Cię, jeśli nie zastąpisz go poprawnie.

Sree
źródło