- 23. Java – Переопределение (overriding)
- Содержание
- Пример 1
- Пример 2
- Правила переопределения метода
- Использование ключевого слова super
- Пример
- Зачем использовать аннотацию @Override
- Как использовать аннотацию @Override
- Функция 1: маркировка переопределённых методов
- Функция 2: защита от переопределения не того метода
- Заключение
- Все о переопределении в Java
- Переопределение методов Java
- Что такое переопределение в Java
- Зачем и где именно писать @Override?
23. Java – Переопределение (overriding)
В предыдущей главе мы рассказали про суперклассы и подклассы. Если класс наследует метод из своего суперкласса, тогда есть шанс переопределить взятый метод, если он не помечен final.
Так что такое в Java overriding или override – это переопределение.
Преимущество в Java переопределения заключается в том, что оно позволяет определять (описывать) поведение, характерное для типа подкласса, значит подкласс может реализовать метод родительского класса на основе его требования.
В объектно-ориентированных терминах, переопределение значит перезапись функционала существующего метода.
Содержание
Пример 1
После запуска программы будет выдан такой результат:
В вышеприведённом примере вы можете заметить, что b хоть и является типом Animal, оно запускает метод move в классе Dog. Причина тому: во время компиляции проходит проверка ссылочного типа. Однако, во время выполнения, JVM определяет тип объекта и запускает метод, который принадлежит этому конкретному объекту.
Следовательно, по примеру выше, программа запустится правильно, так как класс Animal имеет метод move. Затем, во время выполнения, он запускает метод, принадлежащий этому объекту.
Рассмотрите следующий пример:
Пример 2
После запуска программы будет выдан такой результат:
Программа выдаст ошибку во время компиляции, так как ссылочный тип b у Animal не имеет метода под именем bark.
Правила переопределения метода
- Список аргументов должен быть точно таким же, как и для переопределённого метода.
- Возвращаемый тип должен быть таким же или подтипом возвращаемого типа, объявленного в исходном переопределенном методе в суперклассе.
- Уровень доступа не может быть более ограниченным, чем уровень доступа переопределённого метода. Например, если метод суперкласса объявлен public, то переопределяемый метод в подклассе не может быть private или protected.
- Методы экземпляров могут быть переопределены только если они наследованы подклассом.
- Методы, которые объявлены как final, не могут быть переопределены.
- Статические методы, которые объявлены как static, не могут быть переопределены, но могут быть повторно объявлены.
- Если метод нельзя наследовать, то его нельзя переопределить.
- Подкласс внутри того же пакета, что и суперкласс экземпляра, может переопределять любой метод суперкласса, который не объявлен как private или final.
- Подкласс в другом пакете может переопределять только не final методы, объявленные как public или protected.
- Переопределяемый метод может выдавать любые непроверенные исключения вне зависимости от того, переопределяет ли переопределённый метод какие-либо непроверенные исключения или нет. Однако, переопределяемый метод не должен генерировать проверенные исключения, которые являются новыми или более широкими, чем те, которые объявлены переопределённым методом. Переопределенный метод может генерировать более узкие или меньшие исключения, чем переопределенный метод.
- Конструкторы нельзя переопределить.
Использование ключевого слова super
Вызывая версию суперкласса переопределённого метода, используется ключевое слово super.
Пример
После запуска программы будет выдан такой результат:
Источник
Зачем использовать аннотацию @Override
Аннотация @Override появилась в Java 5. С помощью этой аннотации маркируются методы, которые переопределяются в наследниках.
Как использовать аннотацию @Override
Рассмотрим стандартный интерфейс AutoCloseable:
Как вы видите, в этом интерфейсе определён один метод close.
Теперь создадим собственный класс Resource и укажем, что он реализует интерфейс AutoCloseable:
Теперь для того, чтобы код компилировался, нам потребуется определить метод close. Если вы сгенерируете заглушку метода средствами вашей IDE, методу автоматически будет установлена аннотация @Override:
Функция 1: маркировка переопределённых методов
Как вы видите, аннотация означает, что метод close был переопределён . Это даёт дополнительную подсказку программисту о том, что метод был объявлен в каком-то предке данного класса.
Функция 2: защита от переопределения не того метода
Вторая, не менее важная функция аннотации @Override это защита от переопределения не того метода по ошибке программиста.
В том же классе Resource переименуем метод close() на close2():
Ваша IDE подсветит строку с аннотацией @Override, сигнализируя вам о том, что метода close2() нет в предках класса Resource. Таким образом, компилятор предупреждает нас о потенциальной ошибке, которая могла произойти по вине программиста.
Заключение
Аннотация @Override одновременно обозначает переопределяемые (реализуемые) методы в потомках и предотвращает потенциальные ошибки, которые могли быть при определении метода с другой сигнатурой.
Источник
Все о переопределении в Java
У нас на этой неделе практически юбилей — стартует пятая группа «Разработчик Java», а это значит, что мы снова делимся всякими полезностями.
Если вы хотите убедиться, что вы переопределяете правильным образом, взгляните на это руководство, которое описывает различные средства, имеющиеся в вашем распоряжении, и некоторые подводные камни, которых следует остерегаться.
Дочерний класс может переопределить методы экземпляра своего родительского класса. Это называется переопределением метода. Сигнатура (тип возврата, тип параметров, количество параметров и порядок параметров) должна быть такой же, какой была определена в родительском классе. Переопределение метода выполняется для достижения полиморфизма во время выполнения программы.
Что такое полиморфизм?
Полиморфизм позволяет вам определить один интерфейс и иметь для него несколько реализаций. Это один из основных принципов объектно-ориентированного программирования. Слово «полиморфизм» буквально означает «состояние наличия многих форм» или «способность принимать разные формы». При применении к объектно-ориентированным языкам программирования, таким как Java, он описывает способность языка обрабатывать объекты разных типов и классов через единый, однородный интерфейс.
Что такое полиморфизм времени выполнения (или отправка динамического метода?)
Переопределенный метод вызывается в соответствии с объектом, которому принадлежит метод, а не по типу ссылки.
В чём польза полиморфизма времени выполнения?
Статический или динамический полиморфизм?
Private, final и static методы используют статические привязки и связаны компилятором, в то время как виртуальные методы связываются во время выполнения на основе обрабатываемого объекта.
Используйте аннотацию Override, чтобы компилятор мог проверить, что вы действительно переопределяете метод, когда вы на это рассчитываете. Таким образом, если вы совершаете распространенную ошибку, например, опечатку в имени метода или неправильно задаете параметры, вы будете предупреждены о том, что ваш метод фактически не переопределяет в то время, как вы уверены в обратном. Во-вторых, это улучшает читаемость кода, делая переопределение более очевидным.
Кроме того, начиная с Java 1.6 вы можете воспользоваться Override с теми же целями, чтобы отметить, когда метод реализует интерфейс.
Правила динамического полиморфизма
Изменение сигнатуры метода
Если мы используем переопределение, то метод переопределения должен иметь ту же сигнатуру, что и переопределенный метод. Вы можете соответствующим образом изменить сигнатуру метода в своем дочернем классе, то есть количество аргументов, тип и порядок аргументов и тип возвращаемого значения. Но это называется перегрузкой.
Тип возврата метода
Типы возвращаемых данных могут варьироваться в зависимости от методов, которые переопределяют друг друга, если типы возврата являются ссылочными типами. Java поддерживает ковариантные возвращения — специализацию типа возврата к подтипу. Объявление метода d1 с типом возврата R1 заменит возвращаемое значение метода d2 с возвращаемым типом R2 тогда и только тогда, когда выполняются следующие условия:
- Если R1 void, то R2 является void.
- Если R1 является примитивным типом, то R2 идентичен R1.
- Если R1 является ссылочным типом, то: R1 является либо подтипом R2, либо R1 может быть преобразован в подтип R2 путем unchecked преобразования или
- R1 = | R2 |
Ковариантный тип возврата
Возвращение коварианта означает, что при переопределении метода возвращаемый тип переопределяющего метода разрешен как подтип возвращаемого типа переопределенного метода.
Чтобы прояснить это с помощью примера, общим случаем является Object.clone (), который объявляется для возврата типа объекта. Вы можете переопределить это в своем классе следующим образом:
Переопределение статического метода (или) Связывание метода
Связывание статических переменных
Final и private методы
Переопределение уровней доступа
Переопределение с super()
Переопределение с абстракцией
Переопределение с исключениями
Переопределение из внутренних приватных классов
Переопределение и перегрузка
Переопределение методов экземпляра против статических методов
Переопределение методов экземпляра против статических переменных
Конструктор с super()
Переопределение другого и того же пакетов
Правила ребенок-родитель: последствия переопределения
Методы экземпляра предпочтительнее default методов интерфейса.
Программы, содержащие комментарии для иллюстрации использования и последствий при переопределении, могут иметь некоторые CE и RE.
Как всегда будем рады видеть ваши комментарии или вопросы.
Источник
Переопределение методов Java
Привет! Это статья про переопределение (override) методов в Java. Она тесно связана с пониманием принципов ООП, классов и механизма наследования. Если Вы плохо разбираетесь в этих темах, сначала почитайте:
Что такое переопределение в Java
Итак, Вы уже знакомы с понятиями классов и методов в Java. Наверняка Вам даже известно, что одни классы могут наследовать другие.
И вот в этот момент — момент наследования — может возникнуть проблема. Чтобы проиллюстрировать, представим, что у нас есть класс Animal. Этот класс имеет несколько методов — в том числе и метод voice() («голос»):
Давайте теперь представим, что мы создаем класс Cat, который наследует Animal:
Но сейчас если мы создадим кошку и запустим метод voice() , мы получим «This is my voice!». Например, если запустим это:
Как мы знаем, кошка не говорит «This is my voice!» 🙂 Кошка мяукает, собака лает, и т.д.
Таким образом, мы хотели бы, чтобы при вызове метода voice() наша кошка говорила «Мяу». Конечно, мы можем создать новый метод — например, catVoice(), — но это было бы не очень эффективно. Что, если мы хотим изменить 3, 5 или 10 методов? И что, метод родителя будет лежать у нас мертвым грузом?
Нет, нам совершенно не обязательно идти этим путем. Гораздо лучше, если мы просто будем иметь «свой вариант» нужного метода. Мы можем сделать так, чтобы нам не надо было менять название или параметры метода, но он вызвал нужный нам результат. Для этого мы просто должны переопределить метод родителя.
Пример
Как нам переопределить метод voice()? Все очень просто:
- Во-первых, мы заново прописываем метод voice() в нашем классе Cat
- Во-вторых, мы должны дать Java понять, что мы не ошиблись и не назвали метод названием, которое уже есть, из-за невнимательности. Чтобы сказать, что мы знаем, что делаем и действительно хотим переопределить(по англ. «override«) метод, нужно над методом написать @Override .
Источник
Зачем и где именно писать @Override?
На самом деле аннотация @Override указывает, что далее мы собираемся переопределять метод базового класса.
Аннотация служит лишь для контроля успешности действия при сборке проекта.
Из этого я вообще ничего не понял, зачем и где именно его писать. Чужой код разбирал, удалил @Override в чужом коде, без него тоже все работает, но все таки это нужно для чего то
- Вопрос задан более трёх лет назад
- 6459 просмотров
Это аннотация пишется над методами, которые переопределяются из супер класса.
Это что-то вроде страховки, гарантирующая что 100% переопределен метод.
Компилятор, когда встретит данную аннотацию, проверит, чтоб сигнатуры методов в супер классе и в под классе совпадали, т.е. вы переопределили метод, и в полиморфизме будит вызываться переопределенный метод.
Если вдруг вы ошиблись в сигнатуре метода (например пропустили букву в название), то компилятор выдаст ошибку
Показателен пример с переопределением Object.equals(Object) — люди часто ошибаются с сигнатурой: class MyClass < public boolean equals(MyClass o) < /* blah-blah */ >>. В итоге определили новый метод, а не переопределили родительский. Причём ошибка может не сразу обнаружиться.
Ладно equals() можно запомнить очень быстро. Базовый метод, как-никак. Часто на слуху. Но в нетривиальных случаях можно неплохо подпортить себе нервы, пытаясь отдебажить проблему, которую можно было переложить на компилятор аннотацией @Override.
Источник