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

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