2008-08-07 2 views
26

Я видел это в an answer to another question, ссылаясь на недостатки Java спецификации:Разве это действительно расширяется против автобоксинга?

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

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

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

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

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

hello(long x) 

в

hello(Long x) 

результат будет печатать "Integer"

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

+0

Конечно, это расширение. Int расширяется дольше. – EJP 2013-01-11 23:48:21

ответ

12

В первом случае у вас есть расширяющееся преобразование. Это может быть увидеть, когда runinng сервисную программу «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- Длинная инструкция байткода. См. Ссылку here.

А в другом случае, заменив «длинный х» с объектом «Long х» подпись, вы будете иметь этот код в основной метод:

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

+5

Я думаю, что очевидно, что Java должна расшириться до автоматического бокса, потому что более старый код зависел от расширения и сломался, если бы этот код внезапно изменился на авто-бокс. – 2008-09-23 19:22:55

3

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

Редактировать: the original post being referenced.

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

1

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

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, он использует тип времени компиляции, который является сбор и, таким образом, печатает «Коллекция».

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

Смежные вопросы