Pourquoi «court trente = 3 * 10» est une cession légale?

103

Si shortest automatiquement promu intdans les opérations arithmétiques, alors pourquoi:

short thirty = 10 * 3;

Une affectation légale à la shortvariable thirty?

À son tour, ceci:

short ten = 10;
short three = 3;
short thirty = ten * three; // DOES NOT COMPILE AS EXPECTED

ainsi que cette:

int ten = 10;
int three = 3;
short thirty = ten * three; // DOES NOT COMPILE AS EXPECTED

ne compile pas car l'attribution d'une intvaleur à a shortn'est pas autorisée sans la conversion comme prévu.

Y a-t-il quelque chose de spécial à propos des littéraux numériques?

Plafond Gecko
la source
23
short thirty = 10 * 3;est très probablement remplacé par short thirty = 30;le compilateur qui est alors une instruction valide. (Je devrais cependant rechercher la section JLS pertinente).
Thomas
Le compilateur calcule 10 * 3et initialise la variable avec le résultat. Dans votre exemple non fonctionnel, le calcul se produit au moment de l'exécution, où la JVM lance le court-circuit.
Felix
Je pense que c'est un doublon, de stackoverflow.com/questions/30346587/java-char-to-byte-casting ou stackoverflow.com/questions/9379983/… . Cependant: notez que final int ten = 10; final int three = 3; short thirty = ten * three;compile bien.
Marco13
7
If short is automatically promoted to int in arithmetic operations- ce n'est pas pertinent. Ni 10ne 3sont courts et ne sont pas promus, ils sont littérales.
Matthew Lire
@MatthewRead: mais même en tant que littéraux, ils doivent être évalués comme un type de données particulier, non? Alors est-il vrai que 10et 3sont évalués comme ints par le compilateur?
LarsH

Réponses:

139

Parce que le compilateur remplace 10*3par 30 au moment de la compilation . Donc, effectivement: short thirty = 10 * 3est calculé au moment de la compilation.

Essayez de changer tenet threede final short(en leur faisant compiler des constantes de temps) et voyez ce qui se passe: P

Examinez le code d'octet en utilisant javap -v pour les deux versions ( 10*3et final short). Vous pourrez voir qu'il y a peu de différence.

Ok, donc, voici la différence de code d'octet pour différents cas.

Cas 1 :

Code Java: main () {short s = 10 * 3; }

Code d'octet:

stack=1, locals=2, args_size=1
         0: bipush        30  // directly push 30 into "s"
         2: istore_1      
         3: return   

Cas -2:

public static void main(String arf[])  {
   final short s1= 10;
   final short s2 = 3;
   short s = s1*s2;
}

Code d'octet:

  stack=1, locals=4, args_size=1
         0: bipush        10
         2: istore_1      
         3: iconst_3      
         4: istore_2      
         5: bipush        30 // AGAIN, push 30 directly into "s"
         7: istore_3      
         8: return   

Cas -3:

public static void main(String arf[]) throws Exception {
     short s1= 10;
     short s2 = 3;
     int s = s1*s2;
}

Byte-code:

stack=2, locals=4, args_size=1
         0: bipush        10  // push constant 10
         2: istore_1      
         3: iconst_3        // use constant 3 
         4: istore_2      
         5: iload_1       
         6: iload_2       
         7: imul          
         8: istore_3      
         9: return 

Dans le cas ci-dessus, 10et 3sont tirés des variables locales s1ets2

TheLostMind
la source
17
aimé l' Try changing ten and three to final shortexercice :)
Sergey Pauk
1
@SergeyPauk - C'est vraiment important pour comprendre les constantes de temps de compilation .. s'applique à toutes les primitives (Strings aussi ..) :)
TheLostMind
1
@TheLostMind Je suggérerais une meilleure formulation you will see that there's no difference (between those two lines in the decompiled code)car n'est-ce pas votre propos?
Sergey Pauk
4
De manière amusante, cela signifie également que case 10*3:et similaire est légal dans une construction de commutateur.
Ceiling Gecko
5
Et de même dans les constructions enum. En fait, utiliser des trucs comme 1 << 5 pour les constantes d'énumération de champ de bits est idiomatique.
Bathsheba
18

Oui, il se passe quelque chose de spécial avec le cas littéral: 10 * 3sera évalué au moment de la compilation . Vous n'avez donc pas besoin d'une (short)conversion explicite pour les littéraux multipliés.

ten * three n'est pas évaluable à la compilation et nécessite donc une conversion explicite.

Ce serait une autre question si tenet threeétaient marqués final.

Bathsheba
la source
1

La réponse suivante ajoute la section JLS et quelques détails sur ce comportement.

Selon JLS §15.2 - Formes d'expressions

Certaines expressions ont une valeur qui peut être déterminée au moment de la compilation. Ce sont des expressions constantes (§15.28).

Nicolas Henneaux
la source