Когда вы используете аннотацию @Override в Java и почему?


498

Каковы лучшие практики использования @Overrideаннотации Java и почему?

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

Ответы:


515

Используйте его каждый раз, когда вы переопределяете метод для двух преимуществ. Сделайте это так, чтобы вы могли воспользоваться проверкой компилятора, чтобы убедиться, что вы на самом деле переопределяете метод, когда вы так думаете. Таким образом, если вы допустите общую ошибку в неправильном написании имени метода или в неправильном соответствии параметров, вы будете предупреждены, что ваш метод на самом деле не переопределяет, как вы думаете. Во-вторых, это облегчает понимание вашего кода, поскольку становится более очевидным, когда методы перезаписываются.

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


4
В том же ключе, что и «проще для понимания», интегрированные среды разработки заметят аннотацию @Override и визуально пометят переопределяющий метод в редакторе.
Боб Кросс

47
Некоторые IDE помечают переопределенный метод, в котором также отсутствует аннотация @Override.
Джей Р.

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

4
@ Джей Р .: Верно. На самом деле, например, Eclipse может даже автоматически добавлять @Override, если он отсутствует.
Слеське

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
Один очень реальный недостаток заключается в том, что вы затрудняете чтение кода, засоряя его улитками. Возможно, это вина моей IDE, но я сам испытал это.
хорошо относитесь к своим модам

9
@phyzome Если вы находите "Улитки" громоздкими, вы не используете НИКОГДА БЛИЖАЙШЕГО комментария. Они должны быть на одну строку выше заголовка вашего метода, который в большинстве случаев должен быть примерно таким же, как ваш метод (несколько строк), чтобы обеспечить приличный текст при наведении курсора и javadocs. Я полагаю, что проблема не в Улитках, а в ваших привычках к чтению. Тебя беспокоят все эти скобки в коде?
Билл К

4
Да, в кодировании есть излишество: когда вы пишете комментарии, это просто попугай того, что код явно делает.
Муравьи

22

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

Он будет ловить такие вещи, как tostring()вместоtoString()

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


18

Использование @Overrideаннотации действует как гарантия времени компиляции от распространенной ошибки программирования. Он выдаст ошибку компиляции, если у вас есть аннотация к методу, который вы на самом деле не переопределяете для метода суперкласса.

Наиболее распространенный случай, когда это полезно, когда вы меняете метод в базовом классе, чтобы получить другой список параметров. Метод в подклассе, который используется для переопределения метода суперкласса, больше не будет делать это из-за измененной сигнатуры метода. Иногда это может вызывать странное и неожиданное поведение, особенно при работе со сложными структурами наследования. В @Overrideаннотации гарантии против этого.


Лучший ответ. Коротко и сладко. Хотелось бы, чтобы вы объяснили, как работает «мера предосторожности» .... никто не объяснил это.
Джангофан

Это просто объяснить. Если вы сделаете ошибку (либо изменив интерфейс, абстрактный класс или подкласс, вы получите либо предупреждение (например, в Eclipse), либо ошибку времени компиляции, сообщающую, что ваш @Override не работает. Фактическая ошибка сообщение будет зависеть от того, что было изменено, но в Eclipse (например) очень быстро очень ясно, что есть проблема: вы увидите, что небольшое красное зигзагообразное подчеркивание, и наведение на оскорбительный текст скажет вам, что не так. Я называю это Хорошей Ценностью
Ичиро Фурусато

14

Чтобы воспользоваться преимуществами проверки компилятором, вы всегда должны использовать аннотацию Override. Но не забывайте, что 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...
  }
});

Вышеприведенный код компилируется и запускается, но если вы переместите мышь внутри someUIComponent, код «сделать что-то» запустится, потому что на самом деле вы не переопределяете базовый метод mouseEntered(MouseEvent ev). Вы просто создаете новый метод без параметров mouseEntered(). Вместо этого кода, если вы использовали @Overrideаннотацию, вы увидели ошибку компиляции, и вы не тратили время на размышления о том, почему не работает ваш обработчик событий.


8

@Override в реализации интерфейса несовместимо, поскольку в java нет такой вещи, как «переопределение интерфейса».

@ Override on реализации интерфейса бесполезен, так как на практике он не обнаруживает ошибок, которые компиляция не поймет в любом случае. Существует только один, надуманный сценарий, в котором переопределение на реализаторах фактически что-то делает: если вы реализуете интерфейс, а интерфейс УДАЛЯЕТ методы, вы получите уведомление во время компиляции, что вам следует удалить неиспользуемые реализации. Обратите внимание, что если в новой версии интерфейса есть методы NEW или CHANGED, вы, очевидно, все равно получите ошибку компиляции, поскольку вы не реализуете новый материал.

@Override на реализациях интерфейса никогда не должно было быть разрешено в 1.6, и с затмением, к сожалению, выбрав автоматическую вставку аннотаций в качестве поведения по умолчанию, мы получаем много загроможденных исходных файлов. При чтении кода 1.6 вы не можете видеть из аннотации @Override, если метод фактически переопределяет метод в суперклассе или просто реализует интерфейс.

Использование @Override при переопределении метода в суперклассе - это нормально.


2
Есть разные мнения на этот счет. См. Stackoverflow.com/questions/212614/… .
Слеське

8

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

Во-первых, он отлавливает орфографические ошибки типа " hashcode()" вместо " hashCode()" во время компиляции. Может быть затруднительно отлаживать, почему результат вашего метода не соответствует вашему коду, тогда как настоящая причина в том, что ваш код никогда не вызывается.

Кроме того, если суперкласс изменяет сигнатуру метода, переопределения старой сигнатуры могут быть «осиротевшими», оставляя за собой запутанный мертвый код. @OverrideАннотаций поможет вам определить эти сироты , так что они могут быть изменены , чтобы соответствовать новой подписи.


7

Если вы обнаружите, что слишком часто переопределяете (неабстрактные) методы, вы, вероятно, захотите взглянуть на свой дизайн. Это очень полезно, когда компилятор не мог бы поймать ошибку. Например, попытка переопределить initValue () в ThreadLocal, что я и сделал.

Использование @Override при реализации методов интерфейса (функция 1.6+) кажется мне немного излишним. Если у вас есть множество методов, некоторые из которых переопределяют, а некоторые нет, это, вероятно, снова плохой дизайн (и ваш редактор, вероятно, покажет, какой именно, если вы не знаете).


2
На самом деле, это также хорошо для переопределенных методов интерфейса. Например, если я удаляю старый устаревший метод из интерфейса, этот метод должен быть также удален из всех реализующих классов - их легко обнаружить, если они используют @override.
Доминик Санджажа

7

@ Переопределение интерфейсов на самом деле полезно, потому что вы получите предупреждения, если вы измените интерфейс.


7

Еще одна вещь, которую он делает, это делает более очевидным при чтении кода, что он меняет поведение родительского класса. Чем может помочь в отладке.

Кроме того, в книге Джошуа Блока «Эффективная Java» (2-е издание) пункт 36 дает более подробную информацию о преимуществах аннотации.


Да, действительно - пункт 36 :)
Крис Кимптон

6

Нет смысла использовать @Override при реализации метода интерфейса. В этом случае нет смысла использовать его - компилятор уже поймает вашу ошибку, так что это просто ненужный беспорядок.


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

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

6

Всякий раз, когда метод переопределяет другой метод, или метод реализует подпись в интерфейсе.

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


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

5

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


5

Лучше всего всегда использовать его (или попросить IDE заполнить их за вас)

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

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


1
Итак, если вы измените родительский метод и не используете @Override в методе дочернего класса, компиляция скажет что-нибудь или будет молчать? Будет ли использование «Override» дать вам больше информации, и если да, то что?
Джангофан

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, но ваш метод equals кричит BUUUUUUUUUUUUG! Я написал бы (b.first == first) && (b.second == second), даже если бы &&имел более низкий приоритет, чем ==.
Пион

Знаете ли вы, что ваша ссылка показывает сообщение «Вы должны подписаться», охватывающее полезную часть этой страницы?
Адриано Вароли Пьяцца

@Adriano: Извини, чувак !! Я беспомощен! Когда я написал «ответ», он был доступен. Не беспокойся .. купи книгу. Это стоит того!
джай

5
Равно метод не отменяет: Оригинал Object::equalsнаходится boolean equals(Object), в то время как переопределяется equalsесть boolean equals(Bigram), который имеет другой метод подписи, который не переопределяет. Добавление @Override к equalsобнаружит эту ошибку.
Мин-Тан

3

Будьте осторожны, когда используете Override, потому что вы не можете впоследствии выполнить обратный инжиниринг в starUML; сделать УМЛ первым.


2

Кажется, что мудрость здесь меняется. Сегодня я установил IntelliJ IDEA 9 и заметил, что его « отсутствующая проверка @Override » теперь ловит не только реализованные абстрактные методы, но и реализованные методы интерфейса. В кодовой базе моего работодателя и в моих собственных проектах у меня давно была привычка использовать @Override только для ранее реализованных абстрактных методов. Однако, переосмысливая привычку, становится очевидной ценность использования аннотаций в обоих случаях. Несмотря на то, что он более многословен, он защищает от хрупкой проблемы базового класса (не такой серьезной, как примеры, связанные с C ++), когда имя метода интерфейса изменяется, теряя потенциальный реализующий метод в производном классе.

Конечно, этот сценарий в основном гиперболический; производный класс больше не будет компилироваться, теперь в нем отсутствует реализация переименованного метода интерфейса, и сегодня, скорее всего, будет использоваться операция рефакторинга Rename Method для массового обращения ко всей базе кода.

Учитывая, что проверка IDEA не настраивается так, чтобы игнорировать реализованные методы интерфейса, сегодня я изменю свою привычку и критерии проверки кода моей команды.


2

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

Кстати, если мы не объявили аннотацию @Override в подклассе, но мы переопределяем некоторые методы супер, то функция может работать как эта с @Override. Но этот метод не может уведомить разработчика, когда метод супер был изменен. Потому что он не знал цели разработчика - переопределить метод super или определить новый метод?

Поэтому, когда мы хотим переопределить этот метод для использования Полиморфизма, нам лучше добавить @Override над методом.


1

Я использую его как можно больше, чтобы определить, когда метод переопределяется. Если вы посмотрите на язык программирования Scala, у них также есть ключевое слово override. Я считаю это полезным.


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.