2008-08-07 13 views
26

Widziałem to w an answer to another question, w odniesieniu do braków java spec:Czy to naprawdę poszerza się przeciwko autoboxingowi?

Istnieją niedociągnięcia więcej i jest to subtelny temat. Sprawdzić this Wymeldowanie:

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

Tutaj „długa” będzie drukowana (nie sprawdził to sam), ponieważ kompilator wybiera> poszerzenie nad autoboxing. Zachowaj ostrożność podczas korzystania z autoboxing lub w ogóle go nie używaj!

Czy jesteśmy pewni, że jest to faktycznie przykład poszerzenia zamiast autoboxingu, czy też jest to coś zupełnie innego?

Podczas pierwszego skanowania zgadzam się z oświadczeniem, że wynik będzie "długi" na podstawie i zadeklarowany jako prymitywny, a nie obiekt. Jeśli jednak zmieniło

hello(long x) 

do

hello(Long x) 

wyjściem byłoby wydrukować "Integer"

Co się naprawdę dzieje? Nic nie wiem o interpreterach kompilatorów/kodu bajtowego dla java ...

+0

Z pewnością się poszerza. Int jest rozszerzony na długi. – EJP

Odpowiedz

12

W pierwszym przypadku mamy do czynienia z rozszerzającą się konwersją. Można to sprawdzić, kiedy runinng się „javap” program użytkowy (wliczone w/JDK), na skompilowane klasy:

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 

} 

Oczywiście, można zobaczyć I2L, która jest pamięciowy dla rozszerzającej Integer-to- Instrukcja długiego kodu bajtowego. Zobacz odniesienie here.

A w innym przypadku, zastępując „długi X” obiektu „Długi x” podpis, będziesz miał ten kod w głównym sposobem:

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 

} 

Więc widać kompilator stworzył instrukcja Integer.valueOf (int), aby umieścić prymityw w opakowaniu.

+5

Myślę, że to oczywiste, że Java musi się poszerzyć przed auto-boxingiem, ponieważ starszy kod zależał od rozszerzenia i pękłby, gdyby ten kod nagle zmienił się na auto-boxing. –

3

Tak, wypróbuj to w teście. Zobaczysz "długi" wydrukowany. Rozszerza się, ponieważ Java zdecyduje się rozszerzyć int na długo, zanim zdecyduje się na autobox na Integer, więc metoda hello (długa) zostaje wybrana do wywołania.

Edytuj: the original post being referenced.

Dalsza edycja: Powodem, dla którego druga opcja wydrukowałaby liczbę całkowitą jest to, że nie ma "poszerzenia" do większego prymitywu jako opcji, więc MUSI to zapakować, a zatem opcja Integer jest jedyną opcją. Co więcej, java będzie tylko autoboxem do oryginalnego typu, więc dałoby to błąd kompilatora, jeśli opuścisz hello (Long) i usunięto hello (Integer).

1

Inną interesującą rzeczą związaną z tym przykładem jest przeciążenie metody. Połączenie poszerzania typów i przeciążania metod działa tylko dlatego, że kompilator musi podjąć decyzję, którą metodę wybrać.Rozważmy następujący przykład:

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

Nie używa typu run-time, która jest Lista, używa typ kompilacji, który jest Collection a więc drukuje „Collection”.

Zachęcam do przeczytania Effective Java, która otworzyła mi oczy na niektóre narożne przypadki JLS.

Powiązane problemy