Разве это действительно расширяется против 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...
Ответы
Ответ 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.