Перегрузка и переопределение методов в Java
Изучите основы перегрузки и переопределения методов в Java.
1. Обзор
Перегрузка и переопределение методов являются ключевыми понятиями языка программирования Java, и как таковые они заслуживают углубленного изучения.
В этой статье мы изучим основы этих концепций и посмотрим, в каких ситуациях они могут быть полезны.
2. Перегрузка метода
Перегрузка методов-это мощный механизм, который позволяет нам определять API-интерфейсы связного класса. Чтобы лучше понять, почему перегрузка методов является такой ценной функцией, давайте рассмотрим простой пример.
Предположим, что мы написали наивный служебный класс, который реализует различные методы умножения двух чисел, трех чисел и так далее.
Проще говоря, мы можем реализовать перегрузку метода двумя различными способами:
2.1. Различное количество аргументов
2.2. Аргументы различных типов
Кроме того, правомерно определить класс Multiplier с обоими типами перегрузки методов:
Чтобы понять, почему – давайте рассмотрим следующий пример:
В этом случае код просто не будет компилироваться из – за неоднозначности вызова метода – компилятор не будет знать, какую реализацию multiply() вызывать.
2.3. Тип Продвижения
Проще говоря, один данный тип неявно повышается до другого, когда нет соответствия между типами аргументов, переданных перегруженному методу, и конкретной реализацией метода.
Чтобы более четко понять, как работает продвижение типов, рассмотрим следующие реализации метода multiply() :
Давайте посмотрим быстрый модульный тест, чтобы продемонстрировать продвижение типа:
И наоборот, если мы вызываем метод с соответствующей реализацией, продвижение типа просто не происходит:
Вот краткое описание правил продвижения типов, которые применяются для перегрузки методов:
2.4. Статическая привязка
Возможность связать конкретный вызов метода с телом метода называется связыванием.
В случае перегрузки метода привязка выполняется статически во время компиляции, поэтому она называется статической привязкой.
Компилятор может эффективно установить привязку во время компиляции, просто проверив сигнатуры методов.
3. Переопределение метода
Переопределение методов позволяет нам предоставлять детальные реализации в подклассах для методов, определенных в базовом классе.
Теперь давайте посмотрим, как использовать переопределение метода, создав простое отношение на основе наследования (“is-a”).
А вот надуманный подкласс:
Здесь ясно видно, что если приложение использует экземпляры класса Vehicle , то оно также может работать с экземплярами Car , поскольку обе реализации метода accelerate () имеют одинаковую сигнатуру и один и тот же тип возвращаемого значения.
Давайте напишем несколько модульных тестов для проверки классов Vehicle и Car :
В нашем случае у нас есть доступ к исходному коду для обоих классов, поэтому мы можем ясно видеть, что вызов метода accelerate() на базовом экземпляре Vehicle и вызов accelerate() на экземпляре Car вернет разные значения для одного и того же аргумента.
Таким образом, следующий тест демонстрирует, что переопределенный метод вызывается для экземпляра Car :
3.1. Взаимозаменяемость Типов
Самая большая проблема с переопределением методов заключается в том, что некоторые конкретные реализации методов в производных классах могут не полностью соответствовать LSP и, следовательно, не сохранять заменяемость типов.
Конечно, допустимо сделать переопределенный метод, чтобы принимать аргументы разных типов и возвращать другой тип, но при полном соблюдении этих правил:
3.2. Динамическая привязка
Учитывая, что переопределение метода может быть реализовано только с наследованием, где существует иерархия базового типа и подтипов, компилятор не может определить во время компиляции, какой метод вызывать, поскольку и базовый класс, и подклассы определяют одни и те же методы.
Как следствие, компилятору необходимо проверить тип объекта, чтобы узнать, какой метод следует вызывать.
Поскольку эта проверка происходит во время выполнения, переопределение метода является типичным примером динамической привязки.
4. Заключение
В этом уроке мы узнали, как реализовать перегрузку методов и переопределение методов, а также рассмотрели некоторые типичные ситуации, в которых они полезны.
Вводный курс. Язык программирования Java
25. Перегрузка и переопределение методов
Перегрузка методов (overload)
Чтобы избежать дублирования методов, Java позволяет определять несколько методов с одним и тем же именем. Например, удобно, чтобы методы, которые реализуют похожий алгоритм для различных типов данных, или разного их количества имели одно и то же имя. Например:
int max(int x, int y)
int max(int x, int y, int z)
float max(float x, float y)
float max(float x, float y, float z).
При компиляции программы при обращении к методу max() в зависимости от типа и количества фактических параметров будет вызван требуемый метод.
для max(1, 2) будет вызван метод max(int x, int y),
для max(1.0, 2.0) будет вызван метод max(float x, float y).
Предоставление компилятору возможности выбора среди нескольких методов необходимого называется перегрузкой (overload). В процессе такого выбора используется понятие сигнатуры метода. В Java сигнатура метода состоит из имени метода, типа, числа и последовательности формальных параметров метода.
Имена параметров, тип возвращаемого значения, модификаторы доступа в сигнатуру не входят, например методы
publicl void draw( int x, int y)
public int draw( int color, int bkcolor)
abstract void draw (int a, int b)
draw (int, int)
draw (int, int)
draw (int, int).
Переопределение методов (override)
Переопределение – это изменение реализации уже существующего в суперклассе м етода (override). В новом методе должны быть те же сигнатура и тип возвращаемого результата, что и у метода родительского класса.
Будет выведено:
Класс A
Класс В
Запись @Override называется аннотацией и указывает, что метод базового класса должен быть переопределен. Если в базовом классе не окажется метода с аналогичной сигнатурой, то мы получим предупреждение компилятора о том, что метод переопределить невозможно. Аннотация не влияет на переопределение метода, но служит лишь для контроля успешности переопределения. Аннотацию можно удалить, но этого делать не надо, потому что в случае ошибки вместо переопределения будет выполнена перегрузка метода.
Переопределение методов
1. Что такое переопределение методов?
Если в иерархии классов совпадают имена и сигнатуры типов методов из подкласса и супер класса, то говорят, что метод из подкласса переопределяет метод из супер-класса.
Переопределение методов выполняется только в том случае, если имена и сигнатуры типов обоих методов одинаковы. В противном случае оба методы считаются перегружаемыми.
Когда переопределенный метод вызывается из своего подкласса, он всегда ссылается на свой вариант, определенный в подклассе. А вариант метода, определенный в супер классе, будет скрыт. Из метода someMethod() будет вызван метод того же класса N :
Рассмотрим более конкретный пример, который показывает зачем переопределяются методы.
Результат выполнения кода:
2. Методы подставки
После выхода Java 5 появилась возможность при переопределении методов указывать другой тип возвращаемого значения, в качестве которого можно использовать только типы, находящиеся ниже в иерархии наследования, чем исходный тип. Такие типы еще называются ковариантными.
3. Переопределение и статические методы
Статические методы не могут быть переопределены. Класс наследник может объявлять метод с такой же сигнатурой, что и супер класс, но это не будет переопределением. При вызове переопределенного метода JVM выбирает нужный вариант основываясь на типе объекта. Вызов же статического метода происходит без объекта. Версия вызываемого статического метода всегда определяется на этапе компиляции.
При использовании ссылки для доступа к статическому члену компилятор при выборе метода учитывает тип ссылки, а не тип объекта, ей присвоенного.
Создадим в супер классе и наследнике статические методы с одинаковой сигнатурой:
4. Переопределение методов в классах наследниках
5. Аннотация @Override
Необязательная аннотация @Override используется с методом для указания того, что он переопределен. Если метод переопределен неверно, код не будет компилироваться:
Модификаторы доступа, переопределение методов, реализация абстрактных методов
— Я расскажу тебе про « модификаторы доступа ». Когда-то я уже рассказывал про них, но повторение – мать учения.
Ты можешь управлять доступом (видимостью) методов и переменных твоего класса из других классов. Модификатор доступа отвечает на вопрос «Кто может обращаться к данному методу/переменной?». Каждому методу или переменной можно указывать только один модификатор.
1) Модификатор « public ».
2) Модификатор « private ».
3) «Модификатор « по умолчанию ».
Если переменная или метод не помечены никаким модификатором, то считается, что они помечены «модификатором по умолчанию». Переменные и методы с таким модификатором видны всем классам пакета, в котором они объявлены, и только им. Этот модификатор еще называют « package » или « package private », намекая, что доступ к переменным и методам открыт для всего пакета, в котором находится их класс
4) Модификатор « protected ».
Таблица с пояснением: