JavaRush/Курси/Java Core/Перевантаження методів | частина 2

Перевантаження методів | частина 2

Рівень 5, Лекція 3
Відкрита

— Привіт! У попередній лекції я тобі розповідав про перевантаження методів. Ти все зрозумів?

— Так. Я пам'ятаю. Кожен метод класу має бути унікальним. Метод класу є унікальним, якщо в цьому класі немає методу з таким же ім'ям і типом параметрів, де порядок параметрів має значення.

— Чудово! Я бачу, що ти добре вивчив той урок. Сьогодні я хочу лише трохи розширити твої знання у цьому напрямку. Як ти думаєш, який метод викличеться у кожному випадку?

Код
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)
  • популярні
  • нові
  • старі
Щоб залишити коментар, потрібно ввійти в систему
IronMan57
Рівень 28
24 лютого, 23:09
Щось я не зрозумів. Яка різниця в самому першому і в самому останньому фрагментах коду, коли в метод print передається значення null? Чому в першому випадку код не скомпілюється, а в останньому буде викликано метод з параметром типу String?
Андрій Андрушків QA Automation Engineer в IT Specialist
15 квітня, 19:26
гарне питання, розібрався в ньому. В першому випадку компілятор думає до чого присвої null - до String чи до Integer? Оскільки null підходить і для String, і для Integer, то компілятор не розуміє який метод використати і виникає помилка. В другому ж варіанті компліятор думає між String та Object і між цими типами компілятор явно бачить більш специфічний тип для null - це String. Надіюсь норм пояснив)
IronMan57
Рівень 28
20 квітня, 21:12
Дякую, все так. Відразу полінувався сам перевірити. З тексту під першим фрагментом коду зрозумів так, що null не приводиться ні до якого іншого типу. Після вашого коментаря перевірив. Виявляється, що навпаки, null, схоже, можна передати замість параметра будь якого не примітивного типу. Наприклад такий код:
class Cat {

    public static void print(String[] array) {
        System.out.println(array);
    }

    public static void main(String[] args) {
        Cat.print(null);
    }
}
також працює. І, в принципі, зрозуміло, чому так - замість посилання ми передаємо null, тобто "пусте" посилання.