Как сделать перегрузку метода java

Обновлено: 07.07.2024

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

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

Перегрузка метода может быть применена по ряду причин. Одной из целей перегрузки методов может быть поддержка одной и той же функциональности для разных типов (особенно если обобщенные элементы не могут использоваться для того, чтобы метод мог поддерживать разные типы, или если методы были написаны до того, как обобщенные значения стали доступны). Примеры перегрузки методов с учетом этого намерения включают String.valueOf (boolean) , String.valueOf (char) , String.valueOf (double) , String.valueOf (long) , String.valueOf (Object) и еще несколько версий String.valueOf перегружен на несколько дополнительных типов.

Другая причина, по которой можно выбрать перегрузку методов, заключается в том, что клиент может вызвать соответствующую версию метода для предоставления только необходимых параметров. Это может быть сделано, например, чтобы устранить необходимость передачи клиентом одного или нескольких значений NULL для параметров, которые не применяются или являются необязательными. Примеры перегруженных методов, написанных для достижения этой цели, включают конструкторы класса Date, такие как Date (int, int, int) , Date (int, int, int, int, int) и Date (int, int, int, int, int , int, int) .

Этот подход, состоящий из множества перегруженных конструкторов версий, каждый из которых принимает различное количество параметров, известен как телескопические конструкторы, и некоторые из них пометили его как анти-шаблон . Фактически, недостатки этого подхода к телескопическим конструкторам являются одним из факторов, на которых Джош Блох сфокусировал внимание на шаблоне Builder в пункте № 2 второго издания Effective Java . Между прочим, класс Date также предоставляет некоторые перегруженные конструкторы, предназначенные также для достижения ранее упомянутой цели, позволяя, например, Date быть составленным из String .

Идея предоставления нескольких перегруженных методов и конструкторов для принятия сокращенного набора обязательных или минимально применимых параметров может быть применена к нашим собственным классам. Следующий листинг кода предоставляет исходному методу слишком много параметров, а затем показывает некоторые потенциально перегруженные версии этого метода, которые принимают сокращенный набор параметров. В целях этого обсуждения мы предполагаем, что любой параметр, не предоставленный в одной из переопределенных сигнатур методов, является необязательным или неприменимым для этого конкретного вызова метода. Комментарии к коду объясняют, как каждый метод делает определенные предположения, чтобы уменьшить количество параметров.

Пример параметра со слишком многими методами и перегруженными версиями

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

Затраты и недостатки

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

Мой пример показал, что комментарии должны использоваться для объяснения предположений, сделанных перегруженными методами. Как только что упоминалось, они могут быть устаревшими или неточными или даже недоступными, если разработчик не удосужился их написать. Очевидно, было бы лучше иметь возможность называть методы по-разному, чтобы имя метода могло дать подсказки о его предположениях, а не полагаться исключительно на Javadoc. Использование именованных методов таким образом будет предметом более поздней публикации, но использование разных имен для методов по определению делает их больше не перегруженными методами.

Мои примеры показали конкретное ограничение использования перегруженных (с тем же именем) методов с несколькими параметрами одного типа. Третий пример принимает один boolean , но только Javadoc и имя этого параметра могут сказать мне, что он применяется к домовладению, а не к полу или статусу занятости. Я не могу предоставить аналогичные перегруженные методы для получения одной и той же информации имени и boolean указывающего что-то другое (например, пол или статус занятости), потому что этот метод будет иметь ту же сигнатуру, что и метод, в котором boolean указывает на статус владения домом. Это снова может быть исправлено путем использования методов с разными именами, которые указывают, к какому булевому условию они применяются.

Другим способом устранения этого последнего упомянутого ограничения будет использование пользовательских типов и / или параметров объектов и предоставление различных версий перегруженных методов, принимающих различные комбинации этих пользовательских типов. Это показано с пользовательскими типами в следующем листинге кода, который показывает, как метод, принимающий две строки имени, может быть перегружен одним третьим параметром для всех трех случаев, когда эти три случая не обязательно должны иметь один и тот же тип.

Чтобы избежать дублирования методов, 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)
draw (int, int).

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

    Переопределение методов (override)

    Переопределение – это изменение реализации уже существующего в суперклассе м етода (override). В новом методе должны быть те же сигнатура и тип возвращаемого результата, что и у метода родительского класса.

    Имеем родительский класс A, в нем определен метод message() . В подклассе В родительский метод переопределен.

    Будет выведено:
    Класс A
    Класс В

    Запись @Override называется аннотацией и указывает, что метод базового класса должен быть переопределен. Если в базовом классе не окажется метода с аналогичной сигнатурой, то мы получим предупреждение компилятора о том, что метод переопределить невозможно. Аннотация не влияет на переопределение метода, но служит лишь для контроля успешности переопределения. Аннотацию можно удалить, но этого делать не надо, потому что в случае ошибки вместо переопределения будет выполнена перегрузка метода.

    Перегрузка методов есть эффективным механизмом реализации полиморфизма в классах.

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

    • CMyClass – имя класса;
    • OverloadedMethod1() – имя перегруженного метода;
    • parameters1 , parameters2 , …, parametersN – параметры (список параметров) любого из перегруженных методов. Эти параметры обязательно должны отличаться между собой типами или количеством.
    2. Пример класса, содержащего перегруженные методы

    В примере объявляется класс Complex , реализующий комплексное число, состоящее из действительной и мнимой части. В классе реализованы:

    • внутренние переменные вещественного типа с именами a , b . Эти переменные соответствуют действительной и мнимой части числа: z = a+bi ;
    • конструктор класса Complex() без параметров;
    • методы доступа GetA() , GetB() , SetComplex() ;
    • перегруженный метод Mult() , который реализует разные варианты умножения комплексного числа, реализованного в классе.

    Текст объявления класса

    Использование класса в другом методе

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

    Если имя метода перегружено в классе, то параметры этого метода могут отличаться:

    • количеством параметров;
    • типами параметров, которые получает метод.
    4. Сколько методов может быть перегружено в классе?

    В классе может быть перегружено любое количество методов.

    5. Сколько перегруженных реализаций может иметь метод в классе?

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

    6. Каким образом реализуется перегрузка конструкторов в классе?

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

    Ниже приведен класс Circle , реализующий окружность. В классе определены следующие переменные-экземпляры класса и методы:

    • скрытые ( private ) переменные x , y , r , определяющие координаты центра окружности и ее радиус;
    • четыре перегруженных конструктора;
    • методы доступа к внешним переменным класса GetCircle() , GetX() , GetY() , GetR() , SetXYR() ;
    • метод, возвращающий площадь круга GetSquare() .

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

    Использование класса в другом программном коде

    В вышеприведенном коде перегружается 4 конструктора:

    Эти конструкторы отличаются разным количеством параметров.

    7. Можно ли в классе объявить два метода, которые имеют одинаковые сигнатуры входных параметров, но которые возвращают разные типы значений?

    Да, можно. Нижеследующий пример демонстрирует использование перегруженного метода Get() , который не получает параметров, но возвращает разные типы значений ( int , double ).

    Объявляется класс Demo , в котором реализованы:

    • внутренняя переменная d ;
    • перегруженный метод доступа Get() без параметров, который возвращает разные типы значений.

    Демонстрация использования метода Get() класса Demo в другом программном коде

    Java разрешает определение внутри одного класса двух или более методов с одним именем, если только они содержат разные параметры.

    В этом случае методы называют перегруженными, а процесс — перегрузкой ( overloading ) методов. Перегрузка методов — один из способов поддержки полиморфизма в Java.

    На заметку! Не надо путать перегрузку методов с их переопределением (overriding). Переопределение мы рассмотрим когда будем изучать наследование.

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

    N0005

    Если помните, то в первой части посвященной классам, мы использовали два разных метода, для задания размеров нашего ящика. Для обратной совместимости, мы сохраним эти методы, но так же создадим перегруженный метод setData(), который будет принимать разное количество параметров и разный их тип.

    Слева приведен отрывок из кода класса Box в текущей его инкарнации. В котором добавлен перегруженный метод setData(). У него есть три варианта, которые принимают один параметр типа double, три double и одну строку, соответственно. И каждый из них выполняет свой код и задает значения надлежащим полям.

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

    Пример использования этих методов приведен ниже:

    N0006

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

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

    Стоит еще заметить что в данном случае происходит неявное преобразование типов данных, так как мы задаем размеры целочисленным литералом, а метод принимает double.

    Перегрузка методов это полиморфизм, поскольку это один из способов реализации концепции "один интерфейс, несколько методов". Приведенный пример демонстрирует этот принцип, но стоит еще рассмотреть методы возвращающие значения.

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

    O001

    Я сразу привел код и вывод программы. В принципе здесь все очень просто.

    У нас есть перегруженный метод multiplay(), который принимает разное количество аргументов разных типов, и так же возвращает разные типы.

    Обратите внимание что в предпоследней строке кода происходит неявное преобразование типов из int в double.

    Читайте также: