class Test {
public static void main(String arg[]) {
System.out.println("**MAIN METHOD");
System.out.println(Mno.VAL); // SOP(9090);
System.out.println(Mno.VAL + 100); // SOP(9190);
}
}
class Mno {
final static int VAL = 9090;
static {
System.out.println("**STATIC BLOCK OF Mno\t: " + VAL);
}
}
Saya tahu bahwa static
blok dieksekusi ketika kelas dimuat. Tetapi dalam hal ini variabel instan di dalam kelas Mno
adalah final
, karena itu static
blok tidak dieksekusi.
Mengapa demikian? Dan jika saya akan menghapusnya final
, apakah itu akan berfungsi dengan baik?
Memori mana yang akan dialokasikan terlebih dahulu, static final
variabel atau static
blok?
Jika karena final
pengubah akses kelas tidak dimuat, lalu bagaimana variabel mendapatkan memori?
java
static
access-modifiers
Sthita
sumber
sumber
Jawaban:
static final int
lapangan adalah kompilasi waktu yang konstan dan nilainya hardcoded ke kelas tujuan tanpa referensi ke asalnya;Secara spesifik, bytecode yang dikompilasi sesuai dengan ini:
public static void main(String arg[]){ System.out.println("**MAIN METHOD"); System.out.println(9090) System.out.println(9190) }
Segera setelah Anda menghapusnya
final
, ini bukan lagi konstanta waktu kompilasi dan perilaku khusus yang dijelaskan di atas tidak berlaku. TheMno
kelas dimuat seperti yang Anda harapkan dan statis initializer mengeksekusi.sumber
Alasan mengapa kelas tidak dimuat adalah bahwa
VAL
adalahfinal
DAN itu dijalankan dengan ekspresi konstan (9090). Jika, dan hanya jika, kedua ketentuan tersebut terpenuhi, konstanta dievaluasi pada waktu kompilasi dan "hardcode" jika diperlukan.Untuk mencegah ekspresi dievaluasi pada waktu kompilasi (dan agar JVM memuat kelas Anda), Anda dapat:
hapus kata kunci terakhir:
static int VAL = 9090; //not a constant variable any more
atau ubah ekspresi sisi kanan menjadi sesuatu yang tidak konstan (bahkan jika variabel masih final):
final static int VAL = getInt(); //not a constant expression any more static int getInt() { return 9090; }
sumber
Jika Anda melihat bytecode yang dihasilkan menggunakan
javap -v Test.class
, main () keluar seperti:public static void main(java.lang.String[]) throws java.lang.Exception; flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String **MAIN METHOD 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 11: sipush 9090 14: invokevirtual #5 // Method java/io/PrintStream.println:(I)V 17: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 20: sipush 9190 23: invokevirtual #5 // Method java/io/PrintStream.println:(I)V 26: return
Anda dapat melihat dengan jelas di "
11: sipush 9090
" bahwa nilai akhir statis langsung digunakan, karena Mno.VAL adalah konstanta waktu kompilasi. Oleh karena itu tidak perlu memuat kelas Mno. Karenanya blok statis Mno tidak dieksekusi.Anda dapat menjalankan blok statis dengan memuat Mno secara manual seperti di bawah ini:
class Test{ public static void main(String arg[]) throws Exception { System.out.println("**MAIN METHOD"); Class.forName("Mno"); // Load Mno System.out.println(Mno.VAL); System.out.println(Mno.VAL+100); } } class Mno{ final static int VAL=9090; static{ System.out.println("**STATIC BLOCK OF Mno\t:"+VAL); } }
sumber
Sebenarnya Anda belum memperluas kelas Mno itu sehingga ketika kompilasi dimulai akan menghasilkan konstanta variabel VAL dan saat eksekusi dimulai ketika variabel itu dibutuhkan bebannya itu dari memori. Jadi tidak diperlukan referensi kelas Anda sehingga bock statis tidak dijalankan.
jika kelas
A
memperluas kelasMno
, blok statis disertakan dalam kelasA
jika Anda melakukan ini maka blok statis itu dijalankan. Sebagai contoh..public class A extends Mno { public static void main(String arg[]){ System.out.println("**MAIN METHOD"); System.out.println(Mno.VAL);//SOP(9090); System.out.println(Mno.VAL+100);//SOP(9190); } } class Mno { final static int VAL=9090; static { System.out.println("**STATIC BLOCK OF Mno\t:"+VAL); } }
sumber
Sejauh yang saya tahu, itu akan dieksekusi dalam urutan tampilan. Misalnya :
public class Statique { public static final String value1 = init1(); static { System.out.println("trace middle"); } public static final String value2 = init2(); public static String init1() { System.out.println("trace init1"); return "1"; } public static String init2() { System.out.println("trace init2"); return "2"; } }
akan mencetak
Saya baru saja mengujinya dan statika diinisialisasi (=> print) ketika kelas "Statique" benar-benar digunakan dan "dieksekusi" di bagian kode lain (kasus saya, saya melakukan "Statique baru ()".
sumber
Statique
kelas dengan melakukannew Statique()
. Sedangkan pada pertanyaan yang diajukan,Mno
kelas tidak dimuat sama sekali.