Что означает перегрузка метода в java overload
Перейти к содержимому

Что означает перегрузка метода в java overload

  • автор:

Чем отличается перегрузка от переопределения?

Полиморфизм – соль ООП. Перегрузка (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 . Ее отсутствие допускается, но компиляция не перегружающего метода с такой аннотацией приведет к ошибке.

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

Статические методы нельзя переопределить, можно только перегрузить.

О внутренностях процесса связывания можно почитать в этой статье.

Перегрузка методов

Java разрешает определение внутри одного класса двух или более методов с одним именем, если только объявления их параметров различны. В этом случае методы называют перегруженными, а процесс — перегрузкой методов. Перегрузка методов — один из способов поддержки полиморфизма в Java. Тем читателям, которые никогда не использовали язык, допускающий перегрузку методов, эта концепция вначале может показаться странной. Но, как вы вскоре убедитесь, перегрузка методов — одна из наиболее впечатляющих и полезных функциональных возможностей Java.

При вызове перегруженного метода для определения нужной версии Java использует тип и/или количество аргументов метода. Следовательно, перегруженные методы должны различаться по типу и/или количеству их параметров. Хотя возвращаемые типы перегруженных методов могут быть различны, самого возвращаемого типа не достаточно для различения двух версий метода. Когда Java встречает вызов перегруженного метода, она просто выполняет ту его версию, параметры которой соответствуют аргументам, использованным в вызове.

Следующий простой пример иллюстрирует перегрузку метода.

// Демонстрация перегрузки методов.
class OverloadDemo void test () System.out.println(«Параметры отсутствуют»);
// Проверка перегрузки на наличие одного целочисленного параметра.
void test(int а) System.out.println(«а: » + a);
>
// Проверка перегрузки на наличие двух целочисленных параметров.
void test(int a, int b) System.out .println («а и b: » + a + » » + b) ;
>
// Проверка перегрузки на наличие параметра типа double
double test(double a) System.out.println(«double a: » + a);
return a*a;
>
>
class Overload public static void main(String args[]) OverloadDemo ob = new OverloadDemo() ;
double result;
// вызов всех версий метода test()
ob.test () ;
ob.test (10);
ob.test (10, 20);
result = ob.test(123.25) ;
System.out.println(«Результат ob.test(123.25) : » + result);
>
>

Эта программа генерирует следующий вывод:

Параметры отсутствуют
а: 10
а и b: 10 20
double а: 123.25
Результат ob.test(123.25): 15190.5625

Как видите, метод test () перегружается четыре раза. Первая версия не принимает никаких параметров, вторая принимает один целочисленный параметр, третья — два целочисленных параметра, а четвертая — один параметр типа double. То, что четвертая версия метода test () возвращает также значение, не имеет никакого значения для перегрузки, поскольку возвращаемый тип никак не влияет на разрешение перегрузки.

При вызове перегруженного метода Java ищет соответствие между аргументами, которые были использованы для вызова метода, и параметрами метода. Однако это соответствие не обязательно должно быть полным. В некоторых случаях к разрешению перегрузки может применяться автоматическое преобразование типов Java. Например, рассмотрим следующую программу:

// Применение автоматического преобразования типов к перегрузке.
class OverloadDemo void test () System.out.println(«Параметры отсутствуют»);
>
// Проверка перегрузки на наличие двух целочисленных параметров.
void test(int a, int b) System.out.println(«а и b: » + a + » » + b);
class Overload public static void main(String args[]) OverloadDemo ob = new OverloadDemo ();
int i = 88;
ob. test () ;
ob.test(10, 20) ;
ob.test(i);
// этот оператор вызовет test(double)
ob.test(123.2);
// этот оператор вызовет test(double)
>
>

Программа генерирует следующий вывод:

Параметры отсутствуют
а и b: 10 20

Внутреннее преобразование test(double) а: 88
Внутреннее преобразование test(double) а: 123.2

Как видите, эта версия класса OverloadDemo не определяет перегрузку test (int). Поэтому при вызове метода test () с целочисленным аргументом внутри класса Overload какой-то соответствующий метод отсутствует. Однако Java может автоматически преобразовывать тип integer в тип double, и это преобразование может использоваться для разрешения вызова. Поэтому после того, как версия test (int) не обнаружена, Java повышает тип i до double, а затем вызывает метод test (double). Конечно, если бы метод test (int) был определен, вызвался бы он. Java будет использовать автоматическое преобразование типов только при отсутствии полного соответствия.

Перегрузка методов поддерживает полиморфизм, поскольку это один из способов реализации в Java концепции «один интерфейс, несколько методов». Для пояснения приведем следующие рассуждения. В тех языках, которые не поддерживают перегрузку методов, каждому методу должно быть присвоено уникальное имя. Однако часто желательно реализовать, по сути, один и тот же метод для различных типов данных. Например, рассмотрим функцию вычисления абсолютного значения. Обычно в языках, которые не поддерживают перегрузку, существует три или более версии этой функции со слегка различающимися именами. Например, в С функция abs () возвращает абсолютное значение значения типа integer, labs () — значения типа long integer, a fabs () — значения с плавающей точкой. Поскольку язык С не поддерживает перегрузку, каждая функция должна обладать собственным именем, несмотря на то, что все три функции выполняют по существу одно и то же действие. В результате в концептуальном смысле ситуация становится более сложной, чем она есть на самом деле. Хотя каждая из функций построена на основе одной и той же концепции, программист вынужден помнить три имени. В Java подобная ситуация не возникает, поскольку все методы вычисления абсолютного значения могут использовать одно и то же имя. И действительно, стандартная библиотека классов Java содержит метод вычисления абсолютного значения, названный abs (). Перегрузки этого метода для обработки всех численных типов определены в Java-классе Math. Java выбирает для вызова нужную версию метода abs () в зависимости от типа аргумента.

Перегрузка ценна тем, что она позволяет обращаться к схожим методам по общему имени. Таким образом, имя abs представляет общее действие, которое должно выполняться. Выбор нужной конкретной версии для данной ситуации — задача компилятора. Программисту нужно помнить только об общем выполняемом действии. Полиморфизм позволяет свести несколько имен к одному. Хотя приведенный пример весьма прост, если эту концепцию расширить, легко убедиться в том, что перегрузка может облегчить выполнение более сложных задач.

При перегрузке метода каждая версия этого метода может выполнять любые необходимые действия. Не существует никакого правила, в соответствии с которым перегруженные методы должны быть связаны между собой. Однако со стилистической точки зрения перегрузка методов предполагает определенную связь. Таким образом, хотя одно и то же имя можно использовать для перегрузки несвязанных методов, поступать так не следует. Например, имя sqr можно было бы использовать для создания методов, которые возвращают квадрат целочисленного значения и квадратный корень значения с плавающей точкой. Но эти две операции принципиально различны. Такое применение перегрузки методов противоречит ее исходному назначению. В частности, следует перегружать только тесно связанные операции.

Переопределение и перегрузка в Java

Переопределение (overriding) и перегрузка (overloading) – одни из ключевых понятий в программировании на Java. Эти механизмы позволяют реализовать полиморфизм в программах Java. Полиморфизм — одна из концепций ООП.

На этом скриншоте показано, где в коде Java происходит перегрузка, а где – переопределение.

Переопределением называют случаи, когда сигнатура метода (имя и параметры) в суперклассе и дочернем классе совпадают. Когда два или более метода в одном классе имеют одинаковое имя, но разные параметры, это называется перегрузкой.

Перегрузка и переопределение: сравнительный анализ

Переопределение Перегрузка
Реализует «полиморфизм времени выполнения» Реализует «полиморфизм времени компиляции»
Вызов метода определяется во время выполнения на основе типа объекта. Вызов метода определяется во время компиляции
Происходит между суперклассом и подклассом Происходит между методами в рамках одного класса
Одинаковая сигнатура (имя и аргументы метода) Одинаковое имя, но разные параметры
В случае возникновения ошибки эффект будет виден во время выполнения Ошибка может быть обнаружена во время компиляции.

Переопределение и перегрузка: примеры

Давайте рассмотрим следующие примеры, чтобы понять, как работает переопределение и перегрузка в программах Java. За основу возьмем такой код:

package com.journaldev.examples; import java.util.Arrays; public class Processor < public void process(int i, int j) < System.out.printf("Processing two integers:%d, %d", i, j); >public void process(int[] ints) < System.out.println("Adding integer array:" + Arrays.toString(ints)); >public void process(Object[] objs) < System.out.println("Adding integer array:" + Arrays.toString(objs)); >> class MathProcessor extends Processor < @Override public void process(int i, int j) < System.out.println("Sum of integers is " + (i + j)); >@Override public void process(int[] ints) < int sum = 0; for (int i : ints) < sum += i; >System.out.println("Sum of integer array elements is " + sum); > >

Переопределение

Метод process() и параметры int i, int j в Processor переопределяются дочерним классом MathProcessor. Обратите внимание на строки 7 и 23:

public class Processor  public void process(int i, int j) < /* . */ > > /* . */ class MathProcessor extends Processor  @Override public void process(int i, int j) < /* . */ > >

Метод process() и int[] ints в Processor также переопределяются в дочернем классе. Смотрите строки 11 и 28.

public class Processor  public void process(int[] ints) < /* . */ > > /* . */ class MathProcessor extends Processor  @Override public void process(Object[] objs) < /* . */ > >

Перегрузка

Метод process() перегружается в классе Processor. Об этом говорят строки 7, 11 и 15:

public class Processor  public void process(int i, int j) < /* . */ > public void process(int[] ints) < /* . */ > public void process(Object[] objs) < /* . */ > > Итоги

В этом руководстве мы на простом примере рассмотрели переопределение и перегрузку в Java. Переопределение происходит, когда сигнатура метода в суперклассе и дочернем классе одинакова. Перегрузка возникает, когда два или более метода в одном классе имеют одинаковое имя, но разные параметры.

Перегрузка методов — overloading

И еще одна новая и интересная тема на сегодня — перегрузка методов . Или как ее еще часто называют, overloading (переопределение — это overriding).

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

Дело в том, что все методы внутри класса должны иметь уникальные имена. Так вот, это не совсем так. Вернее, совсем не так. Метод не должен иметь уникальное имя. Уникальным должно быть объединение имени и типов параметров этого метода. Такие объединения еще называют сигнатурами методов

public void print(); public void print2();
public void print(); public void print(int n);
public void print(int n, int n2); public void print(int n);
public int print(int a); public void print(int n);
public int print(int a, long b); public long print(long b, int a);

В сигнатуру входит: имя метода и типы параметров . Не входит: тип результата метода и имена параметров. В классе не может быть двух методов с одинаковыми сигнатурами: компилятор не разберется, какой из них нужно вызвать.

Имена параметров роли не играют : они теряются при компиляции. После компиляции о методе известно только его имя и типы параметров. Тип результата не теряется, но результат функции не обязательно чему-то присваивать, поэтому его тоже не включают в сигнатуру.

Согласно принципам ООП , полиморфизм — это сокрытие различных реализаций за одним интерфейсом. А т.к. при вызове метода System.out.println() , например, в зависимости от параметров вызываются различные методы, формально это подпадает под определение полиморфизма.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *