Цикл статей «Учебник Java 8».
Следующая статья — «Java 8 обобщения».
Предыдущая статья — «Java 8 автоупаковка и распаковка».
В некоторых случаях бывает трудно выбрать, какой метод из перегруженных будет выполняться. В этой статье описаны основные правила, которыми нужно руководствоваться при определении вызываемого перегруженного метода.
Посмотрите на следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
class Main { static void method1(int x) { System.out.println("1"); } static void method1(long x) { System.out.println("2"); } static void method1(float x) { System.out.println("3"); } static void method1(double x) { System.out.println("4"); } static void method1(Short x) { System.out.println("5"); } static void method1(short... x) { System.out.println("6"); } public static void main(String[] args) { short x = 20; method1(x); } } |
Вопрос: что будет выведено в консоли?
Правильный ответ: 1
Выбор перегруженного метода происходит по следующим правилам:
- Выбирается наиболее подходящий метод. Если бы у нас был метод, принимающий short x , то он бы и выполнился. Если нужно, то может выполняться расширяющее преобразование примитивов. Выбирается метод, для которого нужно наиболее близкое расширяющее преобразование. В данном случае до int , так как long , float и double «большие» типы.
- Расширяющее преобразование примитивов имеет приоритет над автоупаковкой/распаковкой.
- Автоупаковка/распаковка имеет приоритет перед методом с переменным количеством аргументов.
- Сужающее преобразование примитивов автоматически НЕ выполняется.
Если бы в примере выше метода method1(int x) не было, то выполнился бы метод method1(long x) .
А вот в при таком коде:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Main { static void method1(Short x) { System.out.println("5"); } static void method1(short... x) { System.out.println("6"); } public static void main(String[] args) { short x = 20; method1(x); } } |
Выполнится метод method1(Short x).
Следующий пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Main { static class Monster {} static class Goblin extends Monster {} static class Hobgoblin extends Goblin {} static void method1(Monster obj) { System.out.println("1"); } static void method1(Goblin obj) { System.out.println("2"); } public static void main(String[] args) { Monster obj = new Hobgoblin(); method1(obj); } } |
Этот код выведет в консоль:
1 |
1 |
Так как переменная obj имеет тип Monster . Фактически, конечно, obj ссылается на экземпляр Hobgoblin , но выбор перегруженного метода осуществляется на этапе компиляции, а не на этапе выполнения, поэтому метод выбирается на основе типа объявленной переменной.
Но если переписать так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Main { static class Monster {} static class Goblin extends Monster {} static class Hobgoblin extends Goblin {} static void method1(Monster obj) { System.out.println("1"); } static void method1(Goblin obj) { System.out.println("2"); } public static void main(String[] args) { Hobgoblin obj = new Hobgoblin(); method1(obj); } } |
То в консоль выведется число 2, так как теперь переменная obj имеет тип Hobgoblin, и наиболее подходящим методом будет method1(Goblin obj)
Цикл статей «Учебник Java 8».
Следующая статья — «Java 8 обобщения».
Предыдущая статья — «Java 8 автоупаковка и распаковка».