Question

J'ai vu ça dans une réponse à une autre question, en référence aux lacunes de la spécification Java :

Il y a d'autres défauts et c'est un sujet subtil.Vérifier ce dehors:

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

Ici, "long" serait imprimé (je ne l'ai pas vérifié moi-même), car le compilateur choisit l'élargissement plutôt que la boxe automatique.Soyez prudent lorsque vous utilisez l'auto-boxing ou ne l'utilisez pas du tout !

Sommes-nous sûrs qu’il s’agit réellement d’un exemple d’élargissement au lieu d’autoboxing, ou s’agit-il de tout autre chose ?

Lors de mon analyse initiale, je serais d'accord avec l'affirmation selon laquelle le résultat serait "long" sur la base de i étant déclaré comme un primitif et non comme un objet.Cependant, si vous avez changé

hello(long x)

à

hello(Long x)

la sortie imprimerait "Integer"

Que se passe-t-il réellement ici ?Je ne connais rien aux compilateurs/interpréteurs de bytecode pour Java...

Était-ce utile?

La solution

Dans le premier cas, vous avez une conversion élargie.Cela peut être constaté lors de l'exécution du programme utilitaire "javap" (inclus avec le JDK), sur la classe compilée :

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

}

De toute évidence, vous voyez le I2L, qui est le mnémonique de l’instruction de bytecode d’élargissement Integer-To-Long.Voir référence ici.

Et dans l'autre cas, en remplaçant le "long x" par la signature de l'objet "Long x", vous aurez ce code dans la méthode main :

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

}

Vous voyez donc que le compilateur a créé l'instruction Integer.valueOf(int), pour encadrer la primitive à l'intérieur du wrapper.

Autres conseils

Oui, essayez-le lors d'un test.Vous verrez « long » imprimé.Il s'élargit parce que Java choisira d'élargir l'int en un long avant de choisir de le transformer automatiquement en Integer, donc la méthode hello(long) est choisie pour être appelée.

Modifier: le message original étant référencé.

Modification supplémentaire :La raison pour laquelle la deuxième option afficherait Integer est qu'il n'y a pas d'"élargissement" dans une primitive plus grande en option, elle DOIT donc la mettre en boîte, donc Integer est la seule option.De plus, Java ne passera automatiquement qu'au type d'origine, ce qui générerait une erreur du compilateur si vous laissez le bonjour (Long) et supprimez le bonjour (Integer).

Une autre chose intéressante avec cet exemple est la surcharge de méthode.La combinaison de l'élargissement de type et de la surcharge de méthodes ne fonctionne que parce que le compilateur doit décider quelle méthode choisir.Prenons l'exemple suivant :

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

Il n'utilise pas le type d'exécution qui est List, il utilise le type de compilation qui est Collection et imprime ainsi "Collection".

Je vous encourage à lire Java efficace, ce qui m'a ouvert les yeux sur quelques cas de coin du JLS.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top