Коли ви використовуєте примітку Java @Override та чому?


498

Які найкращі практики використання @Overrideанотацій Java та чому?

Здається, було б надмірно позначити кожний перекреслений метод @Overrideанотацією. Чи існують певні ситуації програмування, які вимагають використання @Overrideта інших, які ніколи не повинні використовувати @Override?

Відповіді:


515

Використовуйте його щоразу, коли ви перекриєте метод на дві переваги. Зробіть це так, щоб ви могли скористатися перевіркою компілятора, щоб переконатися, що ви насправді перекривали метод, коли вважаєте, що є. Таким чином, якщо ви зробите звичайну помилку, неправильно написавши ім'я методу або невірно відповідаючи параметрам, вас попередить, що метод насправді не переосмислює, як ви вважаєте, що це робить. По-друге, це полегшує розуміння вашого коду, оскільки більш очевидно, коли методи перезаписуються.

Крім того, в Java 1.6 ви можете використовувати його для позначення, коли метод реалізує інтерфейс для тих же переваг. Я думаю, що було б краще мати окрему анотацію (як @Implements), але це краще, ніж нічого.


4
У той самий рядок, що і "легше зрозуміти", IDE помітить анотацію @Override і візуально позначить в редакторі метод переосмислення.
Боб Крос,

47
Деякі IDE позначать метод перекритого способу, у якому також відсутня примітка @Override.
Джей Р.

20
Інша перевага полягає в тому, що якщо батьківський клас зміниться, компілятор переконається, що дочірні класи також були оновлені.
Девід

4
@Jay R .: Правда. Власне кажучи, наприклад, Eclipse навіть може автоматично додати @Override, якщо він відсутній.
sleske

32
Якщо хтось потрапив сюди через очевидно недокументовану зміну з 1,5 на 1,6 для @Overrides щодо методів, що надходять з інтерфейсів, bugs.sun.com/bugdatabase/view_bug.do?bug_id=5008260 видається відповідною помилкою. (Дякую, що
вказали

110

Я думаю, що це найбільш корисно як нагадування під час компіляції про те, що метою методу є перекриття батьківського методу. Як приклад:

protected boolean displaySensitiveInformation() {
  return false;
}

Ви часто будете бачити щось подібне до вищевказаного методу, який переосмислює метод у базовому класі. Це важлива деталь реалізації цього класу - ми не хочемо відображати конфіденційну інформацію.

Припустимо, цей метод змінюється в батьківському класі на

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

Ця зміна не спричинить за часом компіляції помилок чи попереджень - але повністю змінює призначену поведінку підкласу.

Щоб відповісти на ваше запитання: вам слід використовувати анотацію @Override, якщо відсутність методу з однаковою підписом у суперкласі свідчить про помилку.


46

Тут є багато хороших відповідей, тому дозвольте запропонувати інший спосіб поглянути на це ...

При кодуванні немає надмірної кількості. Вводити @override нічого не коштує, але заощадження можуть бути величезними, якщо ви неправильно написали ім'я методу або отримали підпис трохи неправильно.

Подумайте про це так: За час, коли ви переходили сюди і вводили цю публікацію, ви майже вживаєте більше часу, ніж витратите на друк @override протягом усього свого життя; але одна помилка, яку вона запобігає, може заощадити години.

Java робить все можливе для того, щоб ви не допустили помилок під час редагування / компіляції, це практично безкоштовний спосіб вирішити цілий клас помилок, які неможливо запобігти будь-яким іншим способом за межами комплексного тестування.

Не могли б ви створити кращий механізм на Java, щоб переконатися, що коли користувач мав намір перекрити метод, він насправді це зробив?

Інший ефектний ефект полягає в тому, що якщо ви не надаєте анотацію, вона під час компіляції попередить, що ви випадково переоцінили батьківський метод - те, що може бути важливим, якщо ви цього не мали наміру.


3
"При кодуванні немає надмірного вмісту." Я погоджуюся з цим, тому я вважаю, що динамічні моменти так неправильно (хоча 100% моєї оплачуваної роботи зараз у рубіні).
Дан Розенстарк

4
+1: Можливо, у мене було 10 помилок, викликаних помилкою переосмислення - час, необхідний для пошуку будь-якого з них, легко перевищив би час на введення @Override для кожного з моїх переважаючих методів. Крім того, якщо @Override є деяким обтяжливим, ви, ймовірно, надмірно використовуєте спадщину.
Лоуренс Дол

7
Одним із справжніх недоліків є те, що ви ускладнюєте читати код, засмічуючи його равликами. Можливо, це вина моєї ІДЕ, але я сам це пережив.
ставитесь до своїх модників добре

9
@phyzome Якщо ви вважаєте, що "Равлики" громіздкі, ви не використовуєте БІЛЬШЕ БЛИЗЬКО коментарів. Вони повинні бути лише одним рядком над заголовком методу, який у більшості випадків повинен бути приблизно таким же, як і ваш метод (кілька рядків), щоб забезпечити пристойний наближення тексту та javadocs. Я думаю, я кажу, що проблема не в Равликах, це у ваших звичках до читання. Чи непокоїть вас і всі ці круглі дужки в коді?
Білл К

4
Так, у кодуванні є надмірність: коли ви пишете коментарі, вони просто папугають те, що код, очевидно, робить.
Мурашки

22

Я завжди використовую тег. Це простий прапор часу компіляції, щоб зловити невеликі помилки, які я можу зробити.

Це буде ловити такі речі, як tostring()замістьtoString()

Маленькі речі допомагають у великих проектах.


18

Використання @Overrideпримітки виступає захистом часу компіляції від поширеної помилки програмування. Це призведе до помилки компіляції, якщо у вас є анотація до методу, який ви насправді не перекриває метод надкласу.

Найчастіший випадок, коли це корисно, це коли ви змінюєте метод у базовому класі, щоб мати інший список параметрів. Метод підкласу, який використовувався для заміщення методу надкласу, більше не буде робити це через підпис зміненого методу. Це іноді може спричинити дивну та несподівану поведінку, особливо коли йдеться про складні структури успадкування. В @Overrideанотації гарантії проти цього.


Найкраща відповідь. Короткий і милий. Хотілося б, щоб ви могли пояснити, як працює "захисна програма" .... ніхто цього не пояснив.
djangofan

Це просто пояснити. Якщо ви помилитесь (змінивши інтерфейс, абстрактний клас або підклас, ви отримаєте або попередження (наприклад, у Eclipse), або помилку під час компіляції, яка говорить про те, що ваш @Override не працює. Фактична помилка) повідомлення буде залежати від того, що було змінено, але в Eclipse (наприклад) дуже швидко зрозуміло, що існує проблема: ви побачите, що маленький червоний зигзаг підкреслюється, і наведення курсору на текст, що ображає, підкаже вам, що не так. Я називаю це хорошим
співвідношенням

14

Щоб скористатися перевіркою компілятора, ви завжди повинні використовувати замітку заміни. Але не забувайте, що Java Compiler 1.5 не дозволить отримати цю примітку при перегляді методів інтерфейсу. Ви просто можете використовувати його для зміни способів класу (абстрактних чи ні).

Деякі IDE, як Eclipse, навіть налаштовані під час виконання Java 1.6 або вище, вони підтримують відповідність Java 1.5 і не дозволяють використовувати @override, як описано вище. Щоб уникнути такої поведінки, потрібно перейти до: Властивості проекту -> Java-компілятор -> Поставити прапорець "Увімкнути специфічні параметри проекту" -> Вибрати "Рівень відповідності компілятора" = 6,0 або вище.

Мені подобається використовувати цю примітку щоразу, коли я переосмислюю метод самостійно, якщо базою є інтерфейс чи клас.

Це допомагає вам уникнути типових помилок, як, коли ви думаєте, що ви переосмислите обробник подій, і тоді ви не бачите нічого. Уявіть, що ви хочете додати слухача події до якогось компонента інтерфейсу:

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

Вищенаведений код компілюється та запускається, але якщо ви перемістите мишу всередину деякогоUIComponent, код «зробіть щось» зазначатиме виконання, оскільки насправді ви не переосмислюєте базовий метод mouseEntered(MouseEvent ev). Ви просто створите новий метод без параметрів mouseEntered(). Замість цього коду, якщо ви використовували @Overrideпримітку, ви побачили помилку компіляції, і ви не витрачали часу на роздуми, чому ваш обробник подій не працює.


8

@Override щодо реалізації інтерфейсу є непослідовним, оскільки в Java немає такого поняття, як "переосмислення інтерфейсу".

@Override щодо реалізації інтерфейсу марний, оскільки на практиці він не виявляє помилок, які компіляція все-таки не зачепить. Є лише один, надуманий сценарій, коли переосмислення реалізаторів насправді щось робить: Якщо ви реалізуєте інтерфейс, а інтерфейс ВИДАЛИТИ методи, ви отримаєте сповіщення під час компіляції, що вам слід видалити невикористані реалізації. Зауважте, що якщо нова версія інтерфейсу має НОВІ або ЗМІНЕНІ методи, ви, очевидно, отримаєте помилку компіляції, оскільки ви не реалізуєте нові речі.

@Override на реалізаторах інтерфейсу ніколи не повинен бути дозволений у 1.6, і, із затьмаренням, сумно вирішивши автоматично вставити анотації як поведінку за замовчуванням, ми отримуємо велику кількість захаращених вихідних файлів. Читаючи код 1.6, з анотації @Override не видно, чи метод насправді замінює метод у надкласі чи просто реалізує інтерфейс.

Використовувати @Override при фактичному переосмисленні методу в надкласовій категорії добре.


2
З цього приводу є різні думки. Дивіться stackoverflow.com/questions/212614/… .
sleske

8

Найкраще використовувати його для кожного методу, призначеного як переопределення, і Java 6+, кожного методу, призначеного як реалізація інтерфейсу.

По-перше, він вловлює неправильні написання типу " hashcode()" замість " hashCode()" під час компіляції. Налагодити помилку, чому результат вашого методу не відповідає вашому коду, коли справжньою причиною є те, що ваш код ніколи не викликається.

Крім того, якщо суперклас змінює підпис методу, зміни попереднього підпису можуть бути "осиротілими", залишені як заплутані мертвий код. @OverrideАнотацій допоможе вам визначити ці сироти , так що вони можуть бути змінені , щоб відповідати новій підпису.


7

Якщо ви дуже часто виявляєте переважаючі (не абстрактні) методи, вам, ймовірно, хочеться поглянути на ваш дизайн. Це дуже корисно, коли компілятор інакше не вловить помилку. Наприклад, намагаючись замінити initValue () в ThreadLocal, що я і зробив.

Використання @Override при впровадженні методів інтерфейсу (функція 1.6+) для мене здається трохи надмірною. Якщо у вас є безліч методів, деякі з яких переосмислюють, а деякі ні, - це, ймовірно, поганий дизайн (і ваш редактор, мабуть, покаже, що це, якщо ви не знаєте).


2
Насправді це також приємно для переоцінених методів інтерфейсу. Якщо я, наприклад, видаляю з інтерфейсу старий, застарілий метод, цей метод слід також видалити з усіх класів-реалізаторів - їх легко помітити, якщо вони використовують @override.
Домінік Санджаджа

7

@Override на інтерфейсах насправді корисні, оскільки ви отримаєте попередження, якщо зміните інтерфейс.


7

Інша річ, яку він робить - це робить більш очевидним при читанні коду, що він змінює поведінку батьківського класу. Чим може допомогти в налагодженні.

Також у книзі Джошуа Блока «Ефективна Java» (2-е видання) у пункті 36 детальніше про переваги анотації.


Так, дійсно - пункт 36 :)
Кріс Кімптон

6

Немає сенсу використовувати @Override при реалізації методу інтерфейсу. Немає переваги використовувати його в такому випадку - компілятор вже вловить вашу помилку, тому це просто непотрібне захаращення.


6
Використання @Overrideінтерфейсу змусить вас помітити, коли метод в інтерфейсі видалено.
Алекс Б

@Alex: Видалення методів в інтерфейсі - це суттєва зміна, як-от додавання їх. Після опублікування інтерфейсу він фактично блокується, якщо ви не маєте повного контролю над усім кодом, який використовує його.
Лоуренс Дол

6

Кожен раз, коли метод перекриває інший метод, або метод реалізує підпис в інтерфейсі.

@OverrideАнотацію запевняє вас , що ви зробили насправді що - то перепризначення. Без примітки ви ризикуєте помилковим написанням або різницею типів та кількості параметрів.


1
Ви можете використовувати його лише для позначення реалізації інтерфейсу в Java 1.6
Дейв Л.

5

Я використовую його щоразу. Це більше інформації, яку я можу використати, щоб швидко зрозуміти, що відбувається, коли я переглянув код через рік, і я забув, про що думав перший раз.


5

Найкращий мотив - завжди використовувати його (або дозволити IDE заповнити їх для вас)

Корисність @Override полягає у виявленні змін у батьківських класах, про які не було повідомлено за ієрархією. Без нього ви можете змінити підпис методу і забути змінити його зміни, якщо @Override, компілятор знайде його за вас.

Таку мережу безпеки завжди добре мати.


1
Отже, якщо ви зміните батьківський метод, а ви не використовуєте @Override в методі дочірнього класу, компіляція скаже щось або промовчить? Чи дасть вам використання «Перевизначити» більше інформації, і якщо так, то що?
djangofan

5

Я використовую його всюди. Щодо теми зусиль для маркування методів, я дозволяю Eclipse зробити це для мене так, це не додаткові зусилля.

Я релігійний щодо безперервного рефакторингу .... тому я буду використовувати кожну дрібницю, щоб зробити це більш гладко.


5
  • Використовується лише в деклараціях методів.
  • Вказує на те, що анотоване оголошення оголошення перекриває декларацію в супертипі.

Якщо використовувати його послідовно, він захищає вас від великого класу недобрих помилок.

Використовуйте примітку @Override, щоб уникнути цих помилок: (Знайдіть помилку в наступному коді :)

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

джерело: Ефективна Java


Я не знаю, які правила пріоритетності оператора в Java, але ваш метод рівних кричить BUUUUUUUUUUUG! Я б писав (b.first == first) && (b.second == second), навіть якби &&мав нижчий пріоритет ніж ==.
піон

Чи знаєте ви, що у вашому посиланні відображається повідомлення "Ви повинні підписатися", що охоплює корисну частину цієї сторінки?
Адріано Варолі П'яцца

@Adriano: Вибачте чувак !! Я безпорадний !! Коли я написав "відповідь", вона була доступна. Не хвилюйтесь .. купуйте книгу. Варто це мати !!
jai

5
Так само метод не скасовує: Оригінал Object::equalsзнаходиться boolean equals(Object), в той час як переопределяется equalsє boolean equals(Bigram), який має інший метод підпису, яка не перекриває. Додавання @Override до equalsволі виявить цю помилку.
Мінг-Тан

3

Будьте обережні, використовуючи Override, тому що ви не можете зробити реверсивного інженера в starUML згодом; зробіть uml спочатку.


2

Здається, що мудрість тут змінюється. Сьогодні я встановив IntelliJ IDEA 9 і зауважив, що його " відсутність @Override inspection " тепер ловить не просто реалізовані абстрактні методи, а й реалізовані методи інтерфейсу. У кодовій базі мого роботодавця та в моїх власних проектах я давно мав звичку використовувати @Override лише для реалізованих раніше абстрактних методів. Однак, переосмисливши звичку, заслуга використання приміток в обох випадках стає зрозумілою. Незважаючи на те, що він є більш багатослівним, він захищає від крихкої проблеми базового класу (не такої серйозної, як приклади, пов’язані з C ++), де змінюється назва методу інтерфейсу, осировуючи метод можливого впровадження у похідному класі.

Звичайно, цей сценарій є здебільшого гіперболою; похідний клас більше не буде компілюватися, тепер йому не вистачає реалізації методу перейменованого інтерфейсу, і сьогодні, ймовірно, можна використовувати операцію рефакторингу методу перейменування для масової адреси всієї бази коду.

З огляду на те, що перевірка IDEA не налаштована на ігнорування реалізованих методів інтерфейсу, сьогодні я зміню як звичку, так і критерії перевірки коду моєї команди.


2

Анотація @Override використовується для того, щоб допомогти перевірити, чи розробник, що замінить правильний метод у батьківському класі чи інтерфейсі. Коли ім'я методів супер змінюється, компілятор може повідомити про цей випадок, який призначений лише для збереження узгодженості з супер та підкласом.

До речі, якщо ми не оголосили анотацію @Override в підкласі, але ми перекриємо деякі методи супер, то функція може працювати як з @Override. Але цей метод не може повідомити розробника про те, що метод супер був змінений. Тому що він не знав мети розробника - замінити метод супер або визначити новий метод?

Тож, коли ми хочемо замінити цей метод, щоб скористатися Поліморфізмом, нам краще додати @Override вище методу.


1

Я використовую його наскільки це можливо, щоб визначити, коли метод перекрито. Якщо ви подивитесь на мову програмування Scala, вони також мають ключове слово для переосмислення. Я вважаю це корисним.


0

Це дозволяє (добре, компілятор) зловити, коли ви використовували неправильне написання назви методу, який ви переосмислюєте.


0

Замітка заміни використовується для того, щоб скористатися компілятором, щоб перевірити, чи дійсно ви переосмислюєте метод з батьківського класу. Він використовується для сповіщення, якщо ви зробили будь-яку помилку, як помилка неправильного написання назви методу, помилка неправильного відповідності параметрів


0

Я думаю, що найкраще кодувати @override, коли це дозволено. це допомагає для кодування. однак, зауважимо, для Ecipse Helios, або sdk 5, або 6, анотація @override для реалізованих методів інтерфейсу дозволена. що стосується Galileo, 5 або 6, анотація @override заборонена.


0

Анотації надають компілятору метадані про код, а примітка @Override використовується у випадку успадкування, коли ми перекриваємо будь-який метод базового класу. Він просто повідомляє компілятору, що ви переважаєте метод. Це дозволяє уникнути деяких видів поширених помилок, які ми можемо зробити, як, наприклад, не слідування правильному підпису методу або неправильне введення в ім'я методу і т. Д. Тож є хорошою практикою використання анотації @Override.


0

Для мене @Override гарантує правильність підпису методу. Якщо я помістив анотацію і метод неправильно написано, тоді компілятор скаржиться, повідомляючи мені, що щось не так.


0

Простий – коли ви хочете замінити метод, присутній у вашому суперкласі, використовуйте @Overrideпримітку, щоб зробити правильне заміщення. Компілятор попередить вас, якщо ви не перекриєте його правильно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.