Este aceasta într-adevăr lărgi vs autoboxing?

Am văzut acest lucru în un răspuns la o altă întrebare , referilar la deficiențele Java spec:

Există mai multe deficiențe și acesta este un subiect subtil. Consultați acest afară:

  melada public classOverloading {
     public static vid void (Integer x) {
          System.out.println ( "Integer");
     }

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

     public static void principal (String [] args) {
         int i = 5;
         buna eu);
     }
}
 
     

Aici se va tipări "lung" (nu am verificat-o eu), deoarece compilalarul alege să se lărgească peste aula-box. Aveți grijă atunci când utilizați aula-box sau nu-l utilizați deloc!

Suntem siguri că acest lucru este de fapt un exemplu de extindere în loc de aulaboxing sau este altceva în întregime?

La scanarea mea inițială, aș fi de acord cu afirmația că ieșirea va fi "lungă" pe baza i fiind declarată ca primitivă și nu ca obiect. Cu laate acestea, dacă v-ați schimbat

hello(long x)

la

hello(Long x)

ieșirea va imprima "Integer"

Ce se întâmplă cu adevărat aici? Nu știu nimic despre interpreții compilatori / bytecode pentru java ...

0
fr hi bn
Desigur, se lărgește. Int este lărgit până la lung.
adăugat autor EJP, sursa

3 răspunsuri

Da, încercați-l într-un test. Veți vedea imprimate "lungi". Se lărgește deoarece Java va alege să lărgească int într-o perioadă lungă înainte de a alege să-l autobox la un întreg, astfel încât metoda de salut (lung) este aleasă să fie numit.

Editați: postarea originală fiind menționată .

Editarea ulterioară: Motivul pentru care a doua opțiune va imprima Integer este că nu există o "lărgire" într-un primitiv mai mare ca opțiune, așa că trebuie să-l încadreze, astfel Integer este singura opțiune. În plus, java va avea numai autobox la tipul original, deci ar da o eroare de compilator dacă lăsăm salutul (Long) și îl ștergem (hello) (Integer).

0
adăugat

În primul caz, se întâmplă o conversie lărgită. Acest lucru poate fi văzut când se execută programul utilitar "javap" (inclus cu w / JDK), pe clasa compilată:

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

}

În mod evident, vedeți I2L, care este mnemonica pentru lărgirea instrucțiunii bytecode Integer-To-Long. Vedeți referința aici .

În celălalt caz, înlocuind semnul "long x" cu obiectul "Long x", veți avea acest cod în metoda principală:

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

}

Deci, veți vedea că compilatorul a creat instrucțiunea Integer.valueOf (int), pentru a plasa elementul primitiv în interiorul ambalajului.

0
adăugat
Cred că este evident că Java trebuie să se lărgească înainte de auto-box deoarece codul mai în vârstă depinde de lărgire și s-ar rupe în cazul în care codul a trecut brusc la auto-box.
adăugat autor Mr. Shiny and New 安宇, sursa

Un alt lucru interesant cu acest exemplu este supraîncărcarea metodei. Combinația de lărgire de tip și de supraîncărcare a metodei funcționează numai pentru că compilatorul trebuie să decidă ce metodă să aleagă. Luați în considerare următorul exemplu:

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

Nu utilizează tipul run-time care este List, folosește tipul de timp de compilare care este Colecția și imprimă astfel "Colecția".

Vă încurajez să citiți Java eficient , care mi-a deschis ochii la unele cazuri de JLS.

0
adăugat