Это действительно расширяется против автобокса?

Я увидел это в ответе на другой вопрос , касающийся недостатков спецификации Java:

Есть еще недостатки, и это тонкая тема. Проверьте это :

public class methodOverloading{
     public static void hello(Integer x){
          System.out.println("Integer");
     }

     public static void hello(long x){
          System.out.println("long");
     }

     public static void main(String[] args){
         int i = 5;
         hello(i);
     }
}

Здесь будет напечатано «long» (сам не проверял), потому что компилятор выбирает расширение вместо автобокса. Будьте осторожны при использовании автобокса или не используйте его вообще!

Мы уверены, что это на самом деле пример расширения вместо автобокса, или это что-то совсем другое?

При моем первоначальном сканировании я согласился бы с утверждением, что вывод будет «длинным» на основании того, iчто он объявлен как примитив, а не объект. Однако, если вы изменили

hello(long x)

в

hello(Long x)

вывод будет выводить «Integer»

Что на самом деле здесь происходит? Я ничего не знаю о компиляторах / интерпретаторах байт-кода для Java ...

7.08.2008 16:30:32
Конечно, это расширяется. Инт расширился на долго.
user207421 11.01.2013 23:48:21
3 ОТВЕТА
РЕШЕНИЕ

В первом случае происходит расширение конверсии. Это можно увидеть при запуске служебной программы "javap" (входит в JDK) в скомпилированном классе:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_ 5
   1:   istore_ 1
   2:   iload_ 1
   3:   i2l
   4:   invokestatic    #6; //Method hello:(J)V
   7:   return

}

Очевидно, вы видите I2L, который является мнемоникой для расширяющейся инструкции байт-кода Integer-To-Long. Смотрите ссылку здесь .

А в другом случае, заменив «long x» на сигнатуру объекта «Long x», вы получите следующий код в методе main:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_ 5
   1:   istore_ 1
   2:   iload_ 1
   3:   invokestatic    #6; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   6:   invokestatic    #7; //Method hello:(Ljava/lang/Integer;)V
   9:   return

}

Итак, вы видите, что компилятор создал инструкцию Integer.valueOf (int), чтобы поместить примитив в оболочку.

14
7.08.2008 18:18:34
Я думаю, очевидно, что Java должна расширяться перед автобоксом, потому что старый код зависел от расширения и сломался бы, если бы этот код внезапно изменился на автобокс.
Mr. Shiny and New 安宇 23.09.2008 19:22:55

Да, попробуйте в тесте. Вы увидите «длинный» напечатанный. Он расширяется, потому что Java выберет расширение int на долгое время, прежде чем оно решит автоматически помещать его в Integer, поэтому выбирается метод hello (long).

Изменить: исходное сообщение со ссылкой .

Дальнейшее редактирование: причина, по которой второй вариант будет выводить Integer, заключается в том, что в качестве опции нет «расширения» в больший примитив, поэтому он ДОЛЖЕН быть помещен в него, поэтому Integer является единственной опцией. Кроме того, java будет автоматически блокировать только исходный тип, поэтому он выдаст ошибку компилятора, если вы оставите hello (Long) и удалите hello (Integer).

4
23.05.2017 12:31:55

Еще одна интересная вещь в этом примере - перегрузка метода. Сочетание расширения типов и перегрузки методов работает только потому, что компилятор должен решить, какой метод выбрать. Рассмотрим следующий пример:

public static void hello(Collection x){
   System.out.println("Collection");
}

public static void hello(List x){
   System.out.println("List");
}

public static void main(String[] args){
   Collection col = new ArrayList();
   hello(col);
}

Он не использует тип времени выполнения, который является списком, он использует тип времени компиляции, который является коллекцией, и, таким образом, печатает «коллекцию».

Я призываю вас прочитать Effective Java , что открыло мне глаза на некоторые угловые случаи JLS.

2
7.08.2008 19:02:29