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

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

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

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

— Від чого, а від перевантаження методів я жодних проблем не очікував. І тут – на тобі. Дякую, Рішо, буду пильним і не розслаблятимуся.