Подтвердить что ты не робот

Разве это действительно расширяется против autoboxing?

Я видел это в ответе на другой вопрос в отношении недостатков спецификации 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...

4b9b3361

Ответ 1

В первом случае у вас происходит расширяющееся преобразование. Это можно увидеть при запуске служебной программы "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", вы получите этот код в основном методе:

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), чтобы вставить примитив внутри обертки.

Ответ 2

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

Изменить: исходное сообщение, на которое ссылаются.

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

Ответ 3

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

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);
}

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

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