JavaRush /Курсы /Модуль 2. Java Core /Перегрузка методов ч.2

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

Модуль 2. Java Core
2 уровень , 4 лекция
Открыта

— Привет, Амиго! Пару дней назад я тебе рассказывал о перегрузке методов. Ты все понял?

— Да. Я помню. Каждый метод класса должен быть уникальным. Метод класса уникальный, если в этом классе нет метода с таким же именем и типом параметров, где порядок параметров имеет значение. 

— Отлично! Я вижу, что ты хорошо выучил тот урок. Сегодня я хочу лишь немного расширить твои познания в этом деле. Как ты думаешь, какой метод будет вызван в каждом случае?

Код
class Cat
{
 public static void print(int n)
 {
  System.out.println(n);
 }
 public static void print(short n)
 {
  System.out.println(n);
 }
 public static void print(Integer n)
 {
  System.out.println(n);
 }
 public static void print(String s)
 {
  System.out.println(s);
 } 
public static void main(String[] args)
{
  Cat.print(1);
  Cat.print((byte)1);
  Cat.print("1");
  Cat.print(null);
 }
}

— Затрудняюсь ответить.

— В первом случае 1 имеет тип int, у нас есть 100% совпадение метода, который принимает int. Будет вызван первый void print(int n).

Во втором случае, у нас нет метода, который принимает byte. Но есть два метода, которые принимают short и int. По стандарту расширения типов, byte сначала будет расширен до short, а уж затем расширен до int. Вердикт – будет вызван метод void print(short n).

В третьем случае у нас есть 100% совпадение метода, который принимает String. Будет вызван метод void print(String s).

В четвертом случае у нас неопределенность. null не имеет определенного типа, компилятор откажется компилировать этот код. В таком случае нужно написать Cat.print((Integer)null), чтобы вызвать третий метод и Cat.print((String)null), чтобы вызвать четвертый.

— Очень познавательно, спасибо.

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

Код
class Cat
{
 public static void print(short n)
 {
  System.out.println(n);
 }
 public static void print(Integer n)
 {
  System.out.println(n);
 }

 public static void main(String[] args)
 {
  Cat.print((byte)1);
  Cat.print(1);
 }
}

В первом случает, тип byte будет расширен до short и произойдет вызов первого метода: void print(short n).

Во втором случае неявно будет выполнено разрешенное преобразование от int к Integer, и произойдет вызов второго метода void print(Integer n).

— Неожиданно.

— Нет, неожиданно – это тут:

Код на Java Описание
 class Cat
{
 public static void print(Object o)
 {
  System.out.println(o);
 }
 public static void print(String s)
 {
  System.out.println(s);
 }

 public static void main(String[] args)
 {
  Cat.print(1);
  Cat.print(null);
 }
}
В первом случае int будет расширен до Integer, а так как нет метода для Integer, то вызовется наиболее подходящий метод, т.е. метод void print(Object o)

Во втором случае, ошибки компиляции не будет и вызовется метод void print(String s), что несколько не очевидно.

— Надеюсь, Амиго ты понял, что лучше всего в таких случаях указать оператор преобразования типа, как в случае с (byte), чтобы точно знать, какой метод вызовется.

— Уж от чего, от чего, а от перегрузки методов я никаких проблем не ожидал. И тут – на тебе. Спасибо, Риша, буду держать ухо востро и не расслабляться.

3
Задача
Java Core, 2 уровень, 4 лекция
Недоступна
print(int) и print(String)
print(int) и print(String)
3
Задача
Java Core, 2 уровень, 4 лекция
Недоступна
print(int) и print(Integer)
print(int) и print(Integer)
3
Задача
Java Core, 2 уровень, 4 лекция
Недоступна
Пять методов print с разными параметрами
Пять методов print с разными параметрами
3
Задача
Java Core, 2 уровень, 4 лекция
Недоступна
Меньшее из двух
Меньшее из двух
3
Задача
Java Core, 2 уровень, 4 лекция
Недоступна
Большее из двух
Большее из двух
Комментарии (12)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Роман Уровень 47
10 февраля 2026
По второй задаче объясните, плз. Почему работает, когда меняем местами переменные man и woman? Если оставляем, как есть, не работает?
Руслан Никитин Уровень 109
25 июля 2024
"Прежде всего, JVM разумно ленива: она всегда будет прилагать наименьшие усилия для выполнения метода. Таким образом, когда вы думаете о том, как JVM обрабатывает перегрузку, имейте в виду три важных особенности компилятора: 1. Расширение (widening). 2. Упаковка (autoboxing and unboxing). 3. Аргументы переменной длины (varargs). Обратите внимание, что JVM выполняет их в том порядке, в котором они указаны. Если не найден подходящий метод сначала примитив расширяется: byte -> short -> int -> long -> float -> double. Если не будет найдено не одного метода для расширенного типа, то упаковывается в свой объект обёртку( int - > Integer, short - Short, double - Double и т.д) и начинает искать метод принимающий обёртку. Если не находит и его, то расширяется(уже будучи объектом) до Number, и затем до Object. " habr(c)
25 января 2023

Во втором случае, ошибки компиляции не будет и вызовется метод 
void print(String s), что несколько не очевидно.
Интересно, по какой причине будет вызван void print(String s)
Вячеслав Уровень 108 Expert
2 марта 2023
Т.к. у тебя метод с переданным в него null может примениться только методу с ссылочным типом - String. String "уже" чем Object, поэтому у компилятора не возникает проблемы с вызовом, они на разных уровнях находятся. А в первом примере была ошибка из-за того, что там указано было 2 метода, которые компилятор мог вызвать при передаваемом null: в котором принимается Integer и String. И уже между ними он не понимает, куда передать null - оба они на одном уровне находятся
17 июля 2023
О, спасибо! Я тоже якорь бросил на этом вопросе
Марат Гарипов Уровень 108 Expert
13 июня 2022
Кто бы мог подумать, что подсказки IDEA могут мешать обучению... Увидев, развидеть уже не получается)) Лишают удовольствия от решения задач!
ZloyLis Уровень 58
5 апреля 2022
Мне кажется или задача "Что-то лишнее" - слегка глуповатая. Достаточно прочитать задание до конца, где и прописан ответ.
Pavel Уровень 48
13 апреля 2022
А я искал в чем подвох, не может быть так легко)))
Сергей Уровень 108 Expert
5 апреля 2022
В первом листинге говорится, что print(null) не найдет правильного метода и компилятор выдаст ошибку. В последнем листинге про этот же пример говорится, что будет вызвать метод print(String s). Где правда?
Денис Уровень 108 Expert
6 апреля 2022
Правда в силе.
Stas S Уровень 108 Expert
14 апреля 2022
Если я правильно понял, вся магия в том, что для компилятора Integer == String , как два ссылочных типа переменных и он не знает к какому именно приводить наш null - ошибка "Ambiguous method call. Both" (двусмысленный вызов метода т.е. не явный) В то же время String гораздо "уже", чем Object т.е. ближе к нашему null , грубо говоря сначала приведение сработало бы к String, а потом уже к Object. А раз мы уже привели к String и у нас есть такой метод, нет конфликта с Object и все прекрасно работает.
Владимир Уровень 109 Expert
20 мая 2022
в точку, полезный коммент!