一、定義一個常量java
public class MyTest2 { public static void main(String[] args) { System.out.println(MyParent2.str); } } class MyParent2{ public static final String str = "hello world"; static { System.out.println("MyParent2 static block"); } }
打印結果:apache
hello world
此時MyParent2類不會進行實例化,由於str是一個常量。常量在編譯階段,會存如調用這個常量的方法所在類的常量池中。本質上,調用類並無直接引用到定義常量的類,所以並不會觸發定義常量的類初始化。 dom
注意: 這裏值的是將常量str存放到MyTest2類的常量池中,以後MyTest2和MyParent2就沒有任何關係了。甚至,咱們能夠將MyParent2的class文件刪除。code
2.使用javap反編譯class文件(jdk版本1.7)blog
命令:javap -c MyTest2.classip
3: ldc #3 // String hello world源碼
說明System.out.println(MyChild1.str); 這行代碼已經成爲hello world編譯
三、增長一個short類型的常量class
public class MyTest2 { public static void main(String[] args) { System.out.println(MyParent2.s); } } class MyParent2{ public static final String str = "hello world"; public static final short s = 8; static { System.out.println("MyParent2 static block"); } }
反編譯jdk
此時已經變爲bipush
四、助記符:
1)、ldc表示將int,float或是String類型的常量值從常量池中推送至棧頂。 (public static final String str = "hello world";)
2)、bipush 表示將單字節(-128 ~ 127)的常量推送至棧頂(public static final short s = 8;)
3)、sipush表示將一個短整型常量值(-32678 ~ 32676)推送至棧頂 (public static final int i = 128;)
4)、iconst_1 表示將int類型的1推送至棧頂(iconst_m1, iconst_0, iconst_1 ~ icont_5 -1到5)(public static final short m = 1)
五、助記符相關的類
每一個助記符都有相關的類
1)LDC
2) ICONST.java源碼
在包com.sun.org.apache.bcel.internal.generic;下
六、編譯期常量與運行期的常量的區別
建立MyParent3類,裏面有一個常量,但這個常量是UUID
public class MyTest3 { public static void main(String[] args) { System.out.println(MyParent3.str); } } class MyParent3{ public static final String str = UUID.randomUUID().toString(); static { System.out.println("MyParent3 static code"); } }
打印輸出:
MyParent3 static code a8be85e9-ef3c-4fd9-88aa-56b2c377a25c
總結: 當一個常量的值並不是編譯期間能夠肯定的,那麼其值就不會被放到調用類的常量池中,這時在程序運行時,會致使主動使用這個常量所在的類,顯然會致使這個類被初始化