Как JVM находит метод (параметр с ближайшим совпадением) для вызова в случае перегрузки функции

JVM решает, какой перегруженный метод нужно вызвать во время компиляции. У меня есть один пример:

public class MainClass{

  public static void go(Long n) {System.out.println("takes Long ");}
  public static void go(Short n) {System.out.println("takes Short ");}
  public static void go(int n) {System.out.println("takes int ");}

  public static void main(String [] args) {
    short y = 6;
    long z = 7;
    go(y);
    go(z);
    go((Short)y);
  }
}

По моему мнению, он должен напечатать следующее:

takes Short
takes Long
takes Short

... но фактический вывод:

takes int
takes Long
takes Short

Однако, если у меня есть три функции:

public static void go(Integer n) {System.out.println("takes Integer");}
public static void go(Long n) {System.out.println("takes Long ");}
public static void go(Short n) {System.out.println("takes Short ");}

... и назовите его, используя:

int a= 10; and go(i);  //output : takes Integer.

... почему существует разница для short и int?

Ответ 1

См. JLS Section 15.12.2, для компилятора правил следует определить, какой метод вызывать. Компилятор всегда выбирает наиболее специфический метод, если ваши методы перегружены:

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

Компилятор сначала пытается разрешить метод без бокса или распаковки, как указано там:

Первая фаза (§15.12.2.2) выполняет разрешение перегрузки без разрешения преобразования бокса или распаковки или использования вызова метода переменной arity. Если на этом этапе не обнаружен какой-либо применимый метод, обработка продолжается до второй фазы.

Акцент мой.

Итак, в вашем 1 st код, так как short может использоваться как аргумент для параметра типа int. Компилятор не будет использовать метод с параметром Short, поскольку для этого требуется бокс. Хотя в случае длинного типа, поскольку он не может использоваться в качестве аргумента для типа int, он отправляет его в Long. Помните, что расширение зависит от Бокса.

В вашем 2 nd нет другого способа, чем бокс int - Integer. Таким образом, он вызывает метод с параметром Integer.

Ответ 2

JVM не находит его вообще. Компилятор делает. Он выбирает наиболее специфический метод, следуя правилам в JLS-разделе 15.12.2.5:

Если более чем один метод-член доступен и применим к вызову метода, необходимо выбрать его для предоставления дескриптора для отправки времени выполнения. Язык программирования Java использует правило, в котором выбран наиболее специфический метод.

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

... (полные правила)...

Ответ 3

Так как upcasting to int был в версии 1.0 Java и авто-бокс был добавлен в версии 5.0. Изменение поведения приведет к поломке кода написанный для более старой версии Java.

Ответ 4

Расширение происходит перед боксом (если есть). Таким образом, short станет int и вызовет эти методы.

Кроме того, не имеет прямого отношения к этим вопросам, но интересный момент: вы не можете вставлять и расширять, т.е. short не может стать Integer

Ответ 5

Java сначала ищет ближайшее совпадение. Он пытается найти следующее:

  • Точное совпадение по типу
  • Соответствие типа суперкласса
  • Преобразование в более примитивный тип
  • Преобразование в автоматический тип коробки
  • Varargs

Ответ 6

В приведенном ниже видео ясно объясняется, как JVM выбирает один метод среди различных подходящих методов в случае перегрузки метода.

https://www.youtube.com/watch?v=P4XtP1aeI3g