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

Перегрузка методов | часть 2

Открыта

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

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

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

Код
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), чтобы точно знать, какой метод вызовется.

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

Комментарии (293)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Grigoryvvv
Уровень 28
Expert
23 августа, 20:13
23.08.2026 / 25 уровень
Vladislav Terekh
Уровень 34
23 ноября 2025, 14:37
Копипаста для тех кому лень нажать на самые популярные: Для тех кто читает только первые несколько комментариев, а вопрос про String и null появился: "В первом примере он не может скомпилироваться не от того, что null не может взять не один конструктор, а наоборот, его готовы взять сразу два: String и Integer. Поэтому возникает неопределенность на которую указывает компилятор. Во втором примере, null тоже готовы взять двое, но так как String - потомок Object'a, предпочтение отдается String'у. Не будь его, null взял бы себе Object."
Euraks Backend Developer
16 октября, 05:06
Причина в том, что выбор перегруженного конструктора происходит на этапе компиляции: компилятор ищет самый специфичный подходящий вариант. В первом примере String и Integer не связаны наследованием, ни один не специфичнее другого, отсюда ambiguous. Во втором String — подтип Object, поэтому выбирается он. Похожее требование однозначности есть у интерфейсов с одинаковыми default-методами, но там механизм другой. Устранить неоднозначность можно приведением: (String) null.
Anonymous #3585174
Уровень 33
18 августа 2025, 14:58
Like
Seka
Уровень 20
6 августа 2025, 12:18
поставьте лайк на этот коммент и вы получите ответ на возникший у вас вопрос касательно null в первом и во втором случае. просто нажмите на "популярные" комментарии. Нужна ачивка)
T V
Уровень 34
13 июня 2025, 17:54
Не копипаста для тех, кто печатает копипасту, чтоб его сообщение было популярным: Для тех кто копирует нижний комментарий по вопросу про String и null, и пока копипаста не опуститься - она собирает собирает лайки, потому что есть те, кому лень нажать на самые популярные и эти самые "те" читают только первые несколько комментариев, а вопрос про String и null появился: Похоже, Ваш план по сбору ачивки работает!
VictorThe main expert in Automa в Строительная компани
28 марта 2025, 08:08
Похоже Риша не раскрыл тему, зато комментарии раскрыли тему полностью.
Henry Creel
Уровень 32
22 марта 2025, 11:31
Копипаста для тех кому лень нажать на самые популярные: Для тех кто читает только первые несколько комментариев, а вопрос про String и null появился: "В первом примере он не может скомпилироваться не от того, что null не может взять не один конструктор, а наоборот, его готовы взять сразу два: String и Integer. Поэтому возникает неопределенность на которую указывает компилятор. Во втором примере, null тоже готовы взять двое, но так как String - потомок Object'a, предпочтение отдается String'у. Не будь его, null взял бы себе Object."
kddima0
Уровень 1
8 марта 2025, 05:16
Не понял, мы ведь тут делаем даункастинг, а не апкастинг: мы short сужаем до byte, а не наоборот. Почему я не прав, не понимаю. Посните пожалуйста "Во втором случае, у нас нет метода, который принимает byte. Но есть два метода, которые принимают short и int. По стандарту расширения типов, byte сначала будет расширен до short, а уж затем расширен до int". Мы ведь тут приводим short к byte: Cat.print((byte)1);
lom1tr
Уровень 44
12 декабря 2024, 17:53
Копипаста для тех кому лень нажать на самые популярные: Для тех кто читает только первые несколько комментариев, а вопрос про String и null появился: "В первом примере он не может скомпилироваться не от того, что null не может взять не один конструктор, а наоборот, его готовы взять сразу два: String и Integer. Поэтому возникает неопределенность на которую указывает компилятор. Во втором примере, null тоже готовы взять двое, но так как String - потомок Object'a, предпочтение отдается String'у. Не будь его, null взял бы себе Object."
12 декабря 2024, 11:39
Не буду писать "Копипаста ..." Просто советую прочитать комментарий ниже👇