Domanda

L'ho visto dentro una risposta ad un'altra domanda, in riferimento alle carenze delle specifiche Java:

Ci sono più carenze e questo è un argomento delicato.Controllo Questo fuori:

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

Qui verrebbe stampato "long" (non l'ho controllato personalmente), perché il compilatore sceglie l'ampliamento rispetto al boxing automatico.Fai attenzione quando usi l'auto-boxing o non usarlo affatto!

Siamo sicuri che questo sia effettivamente un esempio di widening invece che di autoboxing, o si tratta di qualcos'altro?

Durante la mia scansione iniziale, sarei d'accordo con l'affermazione secondo cui l'output sarebbe "lungo" sulla base di i essere dichiarato come primitivo e non come oggetto.Tuttavia, se sei cambiato

hello(long x)

A

hello(Long x)

l'output stamperebbe "Integer"

Cosa sta succedendo veramente qui?Non so nulla dei compilatori/interpreti bytecode per Java...

È stato utile?

Soluzione

Nel primo caso, si verifica una conversione allargata.Questo può essere visto quando si esegue il programma di utilità "javap" (incluso con JDK), sulla classe compilata:

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

}

Chiaramente, vedi I2L, che è il mnemonico per l'ampliamento dell'istruzione bytecode da intero a lungo.Vedi riferimento Qui.

E nell'altro caso, sostituendo la "x lunga" con la firma dell'oggetto "Long x", avrai questo codice nel metodo principale:

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

}

Quindi vedi che il compilatore ha creato l'istruzione Integer.valueOf(int), per racchiudere la primitiva all'interno del wrapper.

Altri suggerimenti

Sì, provalo con un test.Vedrai stampato "lungo".Si sta ampliando perché Java sceglierà di ampliare l'int in un long prima di scegliere di trasformarlo automaticamente in un numero intero, quindi viene scelto di chiamare il metodo hello(long).

Modificare: il post originale a cui si fa riferimento.

Ulteriore modifica:Il motivo per cui la seconda opzione stamperebbe Integer è perché non c'è alcun "ampliamento" in una primitiva più grande come opzione, quindi DEVE racchiuderlo, quindi Integer è l'unica opzione.Inoltre, Java eseguirà il box automatico solo sul tipo originale, quindi darebbe un errore del compilatore se si lascia hello (Long) e si rimuove hello (Integer).

Un'altra cosa interessante di questo esempio è l'overload del metodo.La combinazione di ampliamento del tipo e sovraccarico del metodo funziona solo perché il compilatore deve decidere quale metodo scegliere.Considera il seguente esempio:

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

Non utilizza il tipo in fase di esecuzione che è List, utilizza il tipo in fase di compilazione che è Collection e quindi stampa "Collection".

Ti incoraggio a leggere Java efficace, che mi ha aperto gli occhi su alcuni casi angolari della JLS.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top