Menu

Перегрузка методов в Java: одно имя, разные параметры

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

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Одно имя, несколько версий

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

Именно поэтому System.out.println спокойно выводит int, String, boolean или double — существует не один println, а множество перегрузок с общим именем. Вы пишете нужный вызов, а компилятор сопоставляет его с подходящей версией.

Оба метода называются square, но один принимает int, а другой — double. Литерал 5 — это int, поэтому выполняется первая перегрузка; 2.5 — это double, поэтому выполняется вторая.

Что считается другой перегрузкой

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

  • другим числом параметров,
  • другими типами параметров или
  • другим порядком типов.

У каждого вызова список параметров точно совпадает ровно с одним из трёх методов join, поэтому никакой путаницы нет.

Тип возвращаемого значения не учитывается

Частая ловушка для новичков: попытка перегрузить только по типу возвращаемого значения. Тип возвращаемого значения не входит в сигнатуру, которую использует компилятор, поэтому это не компилируется:

// НЕ компилируется - одно имя, одни параметры, различается только тип возврата
static int   value() { return 1; }
static double value() { return 1.0; }   // ошибка: value() уже определён

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

Как Java выбирает перегрузку

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

show(7) точно совпадает с int, хотя long и double тоже могли бы вместить 7 после расширения. Только если убрать точную перегрузку, компилятор расширил бы int до long, а затем до double. Это разрешение полностью определяется на этапе компиляции, исходя из объявленных типов ваших аргументов.

Остерегайтесь неоднозначных вызовов

Если ни одна перегрузка не является явно лучшим совпадением, компилятор отказывается угадывать и сообщает об ошибке. Чаще всего это случается с null, который подходит к любому ссылочному типу:

static void handle(String s) { }
static void handle(StringBuilder b) { }

handle(null);   // ошибка: ссылка на handle неоднозначна

Обе перегрузки принимают null, и ни одна не является более конкретной, поэтому вызов не компилируется. Исправьте это, явно указав тип через приведениеhandle((String) null) — или переработав код так, чтобы перегрузки не конфликтовали. Та же осторожность нужна при сочетании автоупаковки и расширения; держите наборы перегрузок достаточно простыми, чтобы у каждого вызова был один очевидный победитель.

Перегрузка конструкторов

Перегрузка не ограничивается обычными методами — конструкторы используют её постоянно, чтобы предложить несколько способов создания объекта. Конструктор без аргументов может делегировать более полному через this(...):

Оба конструктора носят имя Point, но различаются числом параметров — ровно как перегруженные методы. Делегирование через this(...) оставляет логику инициализации в одном месте.

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

Эти два понятия звучат похоже, но между ними нет связи:

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

Если списки параметров одинаковы — это переопределение (или ошибка дублирования метода в одном классе); если различаются — это перегрузка.

Далее: Varargs

Перегрузка позволяет написать join(a, b) и join(a, b, c) как отдельные методы — но что, если нужно принимать любое число аргументов, не объявляя перегрузку для каждого количества? Синтаксис varargs в Java позволяет одному методу принимать список аргументов переменной длины, и это тема следующей страницы.

Часто задаваемые вопросы

Что такое перегрузка методов в Java?

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

Могут ли два метода в Java различаться только типом возвращаемого значения?

Нет. Тип возвращаемого значения не входит в сигнатуру метода с точки зрения перегрузки, поэтому int total() и double total() в одном классе вызывают ошибку компиляции. Перегрузки должны различаться списком параметров: их числом, типами или порядком. Тип возвращаемого значения может отличаться, но только в дополнение к различию в параметрах, а не сам по себе.

В чём разница между перегрузкой и переопределением в Java?

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

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ