Dlaczego „krótka trzydziestka = 3 * 10” jest zadaniem prawnym?

102

Jeśli shortjest automatycznie promowany do intw operacjach arytmetycznych, to dlaczego:

short thirty = 10 * 3;

Prawne przypisanie do shortzmiennej thirty?

Z kolei to:

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

tak dobrze jak to:

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

nie kompiluje się, ponieważ przypisanie intwartości do a shortnie jest dozwolone bez rzutowania zgodnie z oczekiwaniami.

Czy jest coś specjalnego w literałach liczbowych?

Gekon sufitowy
źródło
23
short thirty = 10 * 3;jest najprawdopodobniej zastępowany przez short thirty = 30;kompilator, który jest wówczas prawidłową instrukcją. (Musiałbym jednak sprawdzić odpowiednią sekcję JLS).
Thomas
Kompilator oblicza 10 * 3i inicjalizuje zmienną z wynikiem. W twoim niedziałającym przykładzie obliczenia są wykonywane w czasie wykonywania, gdzie JVM rzuca skrót.
Felix
Myślę, że jest to duplikat stackoverflow.com/questions/30346587/java-char-to-byte-casting lub stackoverflow.com/questions/9379983/… . Jednak: Zauważ, że final int ten = 10; final int three = 3; short thirty = ten * three;kompiluje się dobrze.
Marco13
7
If short is automatically promoted to int in arithmetic operations- to nie ma znaczenia. Ani 10też nie 3są szorty, ani nie są promowane, są literały.
Matthew Przeczytaj
@MatthewRead: ale nawet jako literały muszą zostać ocenione jako określony typ danych, prawda? Czy to prawda, że 10i 3są oceniane jako ints przez kompilator?
LarsH

Odpowiedzi:

139

Ponieważ kompilator zastępuje 10*330 w czasie kompilacji . A więc skutecznie:short thirty = 10 * 3 jest obliczane w czasie kompilacji.

Spróbuj zmienić teni threenafinal short (sprawić, by kompilowały stałe czasowe) i zobacz, co się stanie: P

Sprawdź kod bajtowy, używając javap -v obu wersji ( 10*3ifinal short ). Będziesz mógł zobaczyć, że różnica jest niewielka.

Ok, oto różnica w kodzie bajtów dla różnych przypadków.

Przypadek 1 :

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

Kod bajtu:

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

Przypadek -2:

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

Kod bajtu:

  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   

Przypadek -3:

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

Kod bajtu:

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 

W powyższym przypadku 10i 3są pobierane ze zmiennych lokalnych s1is2

TheLostMind
źródło
17
lubił Try changing ten and three to final shortćwiczenia :)
Sergey Pauk
1
@SergeyPauk - To naprawdę ważne w zrozumieniu stałych czasu kompilacji .. dotyczy wszystkich prymitywów (również ciągów
znaków
1
@TheLostMind Sugerowałbym lepsze sformułowanie, you will see that there's no difference (between those two lines in the decompiled code)ponieważ nie o to ci chodzi?
Sergey Pauk
4
Co zabawne, oznacza to również, że case 10*3:i podobnie jest legalne w konstrukcji przełącznika.
Ceiling Gecko
5
I podobnie w konstrukcjach wyliczeniowych. W rzeczywistości używanie takich elementów jak 1 << 5 dla stałych wyliczeniowych pola bitowego jest idiomatyczne.
Batszeba
18

Tak, dzieje się coś specjalnego w przypadku literału: 10 * 3zostanie sprawdzone w czasie kompilacji . Więc nie potrzebujesz jawnej (short)konwersji dla zwielokrotnionych literałów.

ten * three nie podlega ocenie w czasie kompilacji, dlatego wymaga jawnej konwersji.

Byłoby inaczej, gdyby teni threezostały oznaczone final.

Batszeba
źródło
1

Poniższa odpowiedź dodaje sekcję JLS i kilka szczegółów na temat tego zachowania.

Zgodnie z JLS §15.2 - Formy wyrażeń

Niektóre wyrażenia mają wartość, którą można określić w czasie kompilacji. Są to wyrażenia stałe (§15.28).

Nicolas Henneaux
źródło