Warum ist „Short 30 = 3 * 10“ eine rechtliche Aufgabe?

102

Wenn in arithmetischen Operationen shortautomatisch inthochgestuft wird, warum dann:

short thirty = 10 * 3;

Eine rechtliche Zuordnung zur shortVariablen thirty?

Dies wiederum:

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

so gut wie das:

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

wird nicht kompiliert, da das Zuweisen eines intWerts zu a shortnicht zulässig ist, ohne wie erwartet zu gießen.

Ist bei numerischen Literalen etwas Besonderes los?

Deckengecko
quelle
23
short thirty = 10 * 3;wird höchstwahrscheinlich durch short thirty = 30;den Compiler ersetzt, der dann eine gültige Anweisung ist. (Ich müsste allerdings den entsprechenden JLS-Abschnitt nachschlagen).
Thomas
Der Compiler berechnet 10 * 3und initialisiert die Variable mit dem Ergebnis. In Ihrem nicht funktionierenden Beispiel erfolgt die Berechnung zur Laufzeit, wenn die JVM den Kurzschluss umwandelt.
Felix
Ich denke, dies ist ein Duplikat von stackoverflow.com/questions/30346587/java-char-to-byte-casting oder stackoverflow.com/questions/9379983/… . Allerdings: Beachten Sie, dass gut final int ten = 10; final int three = 3; short thirty = ten * three;kompiliert wird.
Marco13
7
If short is automatically promoted to int in arithmetic operations- das ist nicht relevant. Weder 10noch 3Shorts noch werden sie befördert, sie sind wörtlich.
Matthew Read
@MatthewRead: Aber selbst als Literale müssen sie als bestimmter Datentyp ausgewertet werden, oder? Stimmt es also, dass 10und vom Compiler 3als ints ausgewertet werden ?
LarsH

Antworten:

139

Weil der Compiler 10*3zur Kompilierungszeit selbst durch 30 ersetzt . Also effektiv: short thirty = 10 * 3wird zur Kompilierungszeit berechnet.

Versuchen Sie, tenund threezu ändern final short(damit sie Zeitkonstanten kompilieren) und sehen Sie, was passiert: P.

Untersuchen Sie den Bytecode mit javap -v für beide Überprüfungen ( 10*3und final short). Sie werden sehen, dass es kaum einen Unterschied gibt.

Ok, hier ist der Bytecode-Unterschied für verschiedene Fälle.

Fall 1 :

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

Bytecode:

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

Fall -2:

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

Bytecode:

  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   

Fall -3:

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

Bytecode:

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 

Im obigen Fall 10und 3werden aus den lokalen Variablen s1und entnommens2

TheLostMind
quelle
17
mochte Try changing ten and three to final shortÜbung :)
Sergey Pauk
1
@ SergeyPauk - Das ist wirklich wichtig für das Verständnis der Kompilierungszeitkonstanten. Gilt für alle
Grundelemente
1
@TheLostMind Ich würde eine bessere Formulierung vorschlagen, you will see that there's no difference (between those two lines in the decompiled code)ist das nicht dein Punkt?
Sergey Pauk
4
Amüsanterweise bedeutet dies auch, dass case 10*3:und ähnliches in einem Switch-Konstrukt legal ist.
Deckengecko
5
Und ähnlich in Enum-Konstrukten. Tatsächlich ist die Verwendung von Dingen wie 1 << 5 für Bitfeld-Enum-Konstanten idiomatisch.
Bathseba
18

Ja, mit dem wörtlichen Fall ist etwas Besonderes los: 10 * 3Wird zur Kompilierungszeit ausgewertet . Sie benötigen also keine explizite (short)Konvertierung für multiplizierte Literale.

ten * three ist zur Kompilierungszeit nicht auswertbar und benötigt daher eine explizite Konvertierung.

Es wäre eine andere Sache, wenn tenund threemarkiert würden final.

Bathseba
quelle
1

Die folgende Antwort fügt den JLS-Abschnitt und einige Details zu diesem Verhalten hinzu.

Wie pro JLS §15.2 - Ausdrucksformen

Einige Ausdrücke haben einen Wert, der zur Kompilierungszeit festgelegt werden kann. Dies sind konstante Ausdrücke (§15.28).

Nicolas Henneaux
quelle