Mengapa "short three = 3 * 10" merupakan tugas hukum?

102

Jika shortsecara otomatis dipromosikan ke intdalam operasi aritmatika, mengapa:

short thirty = 10 * 3;

Penugasan hukum untuk shortvariabel thirty?

Selanjutnya, ini:

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

serta ini:

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

tidak dapat dikompilasi karena menetapkan intnilai ke a shorttidak diperbolehkan tanpa melakukan cast seperti yang diharapkan.

Apakah ada sesuatu yang istimewa tentang literal numerik?

Plafon Tokek
sumber
23
short thirty = 10 * 3;kemungkinan besar digantikan oleh short thirty = 30;kompiler yang kemudian merupakan pernyataan yang valid. (Saya harus mencari bagian JLS yang relevan).
Thomas
Kompilator menghitung 10 * 3dan menginisialisasi variabel dengan hasilnya. Dalam contoh non-kerja Anda, penghitungan terjadi pada waktu proses di mana JVM mentransmisikan short.
Felix
Saya pikir ini adalah duplikat, dari stackoverflow.com/questions/30346587/java-char-to-byte-casting atau stackoverflow.com/questions/9379983/… . Namun: Perhatikan bahwa final int ten = 10; final int three = 3; short thirty = ten * three;mengkompilasi dengan baik.
Marco13
7
If short is automatically promoted to int in arithmetic operations- itu tidak relevan. Baik 10atau 3yang celana pendek mereka juga tidak dipromosikan, mereka literal.
Matius Baca
@ MatthewRead: tetapi bahkan sebagai literal, mereka harus dievaluasi sebagai tipe data tertentu, bukan? Jadi apakah benar itu 10dan 3dievaluasi sebagai intoleh kompilator?
LarsH

Jawaban:

139

Karena kompilator mengganti 10*3dengan 30 pada waktu kompilasi itu sendiri. Jadi, efektif: short thirty = 10 * 3dihitung pada waktu kompilasi.

Coba ubah tendan threeke final short(buat mereka menyusun konstanta waktu) dan lihat apa yang terjadi: P

Periksa kode byte yang digunakan javap -v untuk kedua verisi ( 10*3dan final short). Anda akan dapat melihat bahwa ada sedikit perbedaan.

Oke, Jadi, inilah perbedaan kode byte untuk kasus yang berbeda.

Kasus 1 :

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

Kode byte:

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

Kasus -2:

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

Kode byte:

  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   

Kasus -3:

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

Kode byte:

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 

Dalam kasus di atas, 10dan 3diambil dari variabel lokal s1dans2

TheLostMind
sumber
17
menyukai Try changing ten and three to final shortlatihan :)
Sergey Pauk
1
@SergeyPauk - Itu sangat penting dalam memahami konstanta waktu kompilasi .. berlaku untuk semua primitif (String juga ..) :)
TheLostMind
1
@TheLostMind Saya akan menyarankan you will see that there's no difference (between those two lines in the decompiled code)penyebab kata-kata yang lebih baik bukankah ini maksud Anda?
Sergey Pauk
4
Menariknya, ini juga berarti bahwa case 10*3:dan sejenisnya legal dalam konstruksi sakelar.
Ceiling Gecko
5
Dan serupa dalam konstruksi enum. Faktanya, menggunakan hal-hal seperti 1 << 5 untuk konstanta enum bitfield adalah idiomatik.
Batsyeba
18

Ya, ada sesuatu yang istimewa yang terjadi dengan kasus literal: 10 * 3akan dievaluasi pada waktu kompilasi . Jadi, Anda tidak memerlukan (short)konversi eksplisit untuk literal yang dikalikan.

ten * three bukan waktu kompilasi yang dapat dievaluasi sehingga membutuhkan konversi eksplisit.

Ini akan menjadi masalah yang berbeda jika tendan threeditandai final.

Batsyeba
sumber
1

Jawaban berikut menambahkan bagian JLS dan beberapa detail tentang perilaku ini.

Sesuai JLS §15.2 - Bentuk Ekspresi

Beberapa ekspresi memiliki nilai yang dapat ditentukan pada waktu kompilasi. Ini adalah ekspresi konstan (§15.28).

Nicolas Henneaux
sumber