- Чем отличается перегрузка от переопределения?
- Кофе-брейк #139. Перегрузка и переопределение в Java. 5 методов Java, о которых вы не знали
- Перегрузка (Overloading)
- Переопределение (Overriding)
- 5 методов Java, о которых вы не знали
- 1. decrementExact
- 2. getAsDouble
- 3. absExact
- 4. endsWith
- 5. divideUnisgned
- Заключение
Чем отличается перегрузка от переопределения?
Полиморфизм – соль ООП. Перегрузка (overload) и переопределение (override) – два инструмента достижения полиморфного поведения в Java.
Перегрузкой реализуется ad-hoc-полиморфизм. Это значит «один и тот же» метод может работать с разными параметрами. С технической точки зрения это просто два разных метода, сигнатуры которых имеют одинаковое название, но разный набор параметров. Важно помнить, что для перегрузки не достаточно различий только модификаторов, возвращаемых типов и списков исключений.
Ad-hoc – не совсем настоящий полиморфизм, так как при нём используется раннее, или статическое связывание (early binding, static dispatch). Это значит, что для выбора конкретного варианта метода используется информация о типе переменной, а не объекта в ней лежащего, и происходит это еще при компиляции.
Если в классе объявлены два перегруженных метода, а аргумент в вызове подходит под оба, случится ошибка компиляции. В примере ниже компилятор не может выбрать между вариантами метода println с параметром char[] и со String , так как null может быть и тем и другим.
Переопределение (override) дает полиморфизм подтипов. Это реализация/подмена метода нефинального родительского класса или интерфейса. С помощью этого механизма достигается поведение, когда экземпляр хранится под типом родителя, но реализация методов используется специфичная для этого конкретного подтипа. Пример:
List list = new LinkedList<>();
list.add(“foo“);
Здесь метод add вызывается общий для всех списков, но добавлен будет именно элемент связного списка.
Выбор конкретного метода происходит в последний момент, в процессе работы программы, в зависимости от типа объекта. Это называется позднее или динамическое связывание методов (late binding, dynamic dispatch).
Переопределение имеет непосредственное отношение к принципу подстановки Лисков (LSP): в хорошем объектно-ориентированном коде для вызывающего кода переопределенный метод не должен быть отличим от оригинального.
Переопределенный метод принято снабжать аннотацией @Override . Ее отсутствие допускается, но компиляция не перегружающего метода с такой аннотацией приведет к ошибке.
При переопределении можно сузить набор выбрасываемых исключений или тип результата, и заменить модификатор доступа на менее строгий.
Статические методы нельзя переопределить, можно только перегрузить.
О внутренностях процесса связывания можно почитать в этой статье.
Кофе-брейк #139. Перегрузка и переопределение в Java. 5 методов Java, о которых вы не знали
Источник: Medium Благодаря этой статье вы узнаете о методах переопределения (Overriding) и перегрузки (Overloading) в языке Java. Из-за того, что оба этих термина часто путают между собой, стоит четко понимать предназначение каждого метода и варианты их применения.
Перегрузка (Overloading)
Использование более одного метода с одним и тем же именем, но с разными параметрами в одном и том же классе или методе между суперклассом и подклассом в Java называется перегрузкой (Overloading). Чтобы этого избежать, используется один метод вместо множества, выполняющих аналогичные действия. Поясним на примере:
public class MethodOverloading < public static void main(String[] args)< MethodOverloading operation = new MethodOverloading(); operation.mod(12,4); operation.mod(12.4,4.2); >void mod(double a, double b) < System.out.println(a % b); >void mod(int a, int b) < System.out.println(a % b); >>
В этом коде метод операции перегружен. Методы с одинаковыми именами принимают параметры разных типов. Выбор режима определяется отдельно для параметров int и double . Когда мы запускаем программу, operation.mod (12,4) запускает void.mod (int a, int b) , а operation.mod (12.4,4.2) запускает void.mod (double a, double b) .
Переопределение (Overriding)
В Java мы можем создать суперкласс и подклассы, которые наследуются от этого класса. Эти подклассы могут переопределять и заменять методы родительского класса, которые они наследуют. Это делается с помощью метода переопределения (Overriding). Лучше понять это можно на примере:
public class MethodOverriding < public static void main(String[] args) < Cat cat = new Cat(); cat.sound(); Bee bee = new Bee(); bee.sound(); >> class Animal < void sound()< System.out.println("Animal sounds"); >> class Cat extends Animal < @Override void sound() < System.out.println("Cat : meow meow"); >> class Bee extends Animal < @Override void sound() < System.out.println("Bee : buzz buzz"); >>
В этом примере кода создается суперкласс с именем Animal и подклассы с именами Cat и Bee , унаследованные от этого суперкласса. Метод sound в суперклассе переопределен. Примечание: Разделение перегруженных методов происходит на этапе компиляции. Разделение переопределенных методов происходит на этапе выполнения.
5 методов Java, о которых вы не знали
Источник: Javarevisited Экосистема разработки на языке Java имеет много доступных инструментов, которые программисты могут импортировать и использовать в своих программах. В их число входят встроенные классы и методы. Они заметно упрощают работу программисту, позволяют лучше понимать и писать код. О них следует знать каждому разработчику. Тут приведены 5 методов Java, которые встречаются достаточно редко, но могут оказаться очень полезными в работе.
1. decrementExact
decrementExact() — это базовая функция Java из класса Math , которая уменьшает/вычитает заданный аргумент (число) на единицу и возвращает результат. Эта функция противоположна функции incrementExact() . Например, если заданный аргумент равен 11, то результатом будет 10. Если уменьшение аргумента приводит к переполнению его типа данных, создается исключение. Поэтому важно соблюдать осторожность при использовании этой функции, особенно для больших чисел. Обычно для этой функции используются целые числа. Синтаксис:
System.out.println(Math.decrementExact(11)); // Output: 10
2. getAsDouble
getAsDouble() является методом, принадлежащим классу OptionalDouble . Объект OptionalDouble — это тот объект, который потенциально может содержать двойное число. Методы в классе можно использовать для работы с двойным значением, присутствующим в объекте, или указать, что двойное значение вообще не содержится. getAsDouble() является одним из таких методов, и он возвращает двойное значение, если оно присутствует. В противном случае появляется исключение NoSuchElementException . Синтаксис:
OptionalDoubleObject.getAsDouble();
OptionalDouble num = OptionalDouble.of(15.0); System.out.println(num.getAsDouble()); // Output: 15.0
3. absExact
Метод absExact() аналогичен функции abs() в классе Math . Он возвращает абсолютное значение числа, которое является положительным значением числа независимо от его знака. Разница лишь в том, что он делает это только в том случае, если он точно представлен как его тип данных ( int или long ). Если результат возвращаемого значения превышает исходный тип данных, появляется исключение ArithmeticException . Синтаксис:
System.out.println(Math.absExact(-11)); // Output: 11
4. endsWith
endsWith() является встроенным строковым (built-in string) методом, который возвращает логическое значение в зависимости от того, заканчивается ли данная строка определенным суффиксом (конечным словом/строкой) в параметрах. Этот метод противоположен методу startsWith() , с которым наверняка знакомы многие разработчики. Синтаксис:
String.endsWith(String suffix);
String phrase = "I like bananas"; System.out.println(phrase.endsWith("bananas")); // true System.out.println(phrase.endsWith("Tandrew")); // false /* Output: true false */
5. divideUnisgned
Метод divideUnsigned() представляет собой метод из класса Integer , который позволяет разделить два числа и вернуть результат деления. Целые числа без знака (Unsigned), по сравнению с обычными целыми числами со знаком (Signed), могут представлять только положительные числа. И целые числа без знака, и целые числа со знаком имеют одинаковое количество чисел в своем диапазоне (размер диапазона составляет 65 536 чисел). Однако поскольку целые числа без знака не могут быть отрицательными, их максимальное значение в положительном диапазоне намного выше, чем максимальное значение для обычного целого числа со знаком. Чтобы упростить это, мы можем вместо этого рассмотреть пример signed и unsigned байта. Байты имеют диапазон 256 чисел. Обычный байт может иметь значение от -128 до 127. Однако байт без знака может иметь значение от 0 до 255. В остальном функция работает точно так же, как обычное деление. Синтаксис:
Integer.divideUnsigned(int dividend, int divisor);
int dividend = 10; int divisor = 5; int quotient = Integer.divideUnsigned(dividend, divisor); System.out.println(quotient); // Output: 2
Заключение
- decrementExact — уменьшает/вычитает заданное число на 1
- getAsDouble — часть функции OptionalDouble , возвращает число с двойным значением или указывает на его отсутствие
- absExact — возвращает абсолютное значение числа, если оно может быть представлено как исходный тип данных
- endsWith() — возвращает логическое значение в зависимости от того, существует ли указанный суффикс в данной строке
- divideUnsigned() — выполняет обычное деление, возвращает результат деления числа