public class test { public static int a = 1; ... }
例如上面的代碼,是先將 0
賦值給 a,而後在初始化的時候將 1
賦值給 a;java
將類的 .class 文件二進制數據讀入到內存中,將其放置在運行時數據區的方法區內,而後在內存中建立一個java.lang.Class對象,用來封裝類在方法區內的數據結構;
加載方式:數據庫
System.exit()
方法;java.lang.invoke.MethodHandle
實例的解析結果REF_getStatic,REF_putStatic,REF_invokeStatic句柄對應的類沒有初始化,則初始化;/** * 1. 對於靜態字段來講,只有直接定義了該字段的類纔會被初始化 * 2. 當一個類初始化時,要求其父類已經所有初始化完成 * +XX:TraceClassLoading:用於追蹤類的加載信息並打印出來 */ public class MyTest1 { public static void main(String[] args) { /** * MyParent1 static block * hello world */ System.out.println(MyChild1.str); /** * MyParent1 static block * MyChild1 static block * welcome */ // System.out.println(MyChild1.str2); } } class MyParent1 { public static String str = "hello world"; static { System.out.println("MyParent1 static block"); } } class MyChild1 extends MyParent1 { public static String str2 = "welcome"; static { System.out.println("MyChild1 static block"); } }
控制檯輸出信息網絡
[Loaded com.godfunc.jvm.classloader.MyParent1 from file:/Users/godfunc/WorkSpace/IdeaSpace/learn-java/jvm/build/classes/java/main/] [Loaded com.godfunc.jvm.classloader.MyChild1 from file:/Users/godfunc/WorkSpace/IdeaSpace/learn-java/jvm/build/classes/java/main/] MyParent1 static block hello world
JVM規範容許類加載器在預料某個類將要被使用時就預先加載它,若是在預先加載中遇到了.class文件缺失或者存在錯誤,類加載器必須在程序「首次主動使用」該類時才報告錯誤(LinkageError錯誤),若是這個類一直沒有被主動使用,那麼類加載器就不會報告這個錯誤。數據結構
/** * 常量在編譯階段會被存入到調用這個常量的方法所在的類的常量池當中,本質上,調用類並無直接引用到定義常量的類, * 所以並不會觸發定義常量的類的初始化 * 注意:這裏的指的是將常量放到了MyTest2的常量池中,以後MyTest2和MyParent2就沒有任何關係了 * 甚至能夠刪除MyParent2的class文件 * 助記符: * ldc表示將int, float, 或者String的常量值從常量池推送至棧頂。 * bipush表示將單字節(-128 ~ 127)的常量推送至至棧頂 * sipush表示將將一個整型(-32768 ~ 32767)常量值推送至棧頂 * iconst_1表示將int型的1推送至棧頂。-1到5 (iconst_m1 ~ iconst_5) */ 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"); } }
/** * 當一個常量的值並不是編譯器能夠肯定的,那麼其值就不會被放到調用類的常量池中, * 這時程序運行時,會致使主動使用這個常量所在的類,顯然會致使這個類被初始化。 */ public class MyTest3 { public static void main(String[] args) { /** * MyParent3 static block * 59ddfbea-ed41-4ab9-a945-88466d6a5ead */ System.out.println(MyParent3.str); } } class MyParent3 { public static final String str = UUID.randomUUID().toString(); static { System.out.println("MyParent3 static block"); } }
/** * 在準備階段,counter1=0 counter=0,而後進入初始化階段時counter1初始化爲1,執行new Singleton(),counter1 + 1 = 2,counter2 + 1 = 1 * 而後初始化counter2,counter2的值被初始化爲0,最後輸出的結果爲 2 0 */ public class MyTest6 { public static void main(String[] args) { Singleton signleton = Singleton.getSingleton(); // 2 1 System.out.println(Singleton.counter1 + " " + Singleton.counter2); } } class Singleton { public static int counter1 = 1; private static Singleton singleton = new Singleton(); private Singleton() { counter1 += 1; counter2 += 1; System.out.println(counter1); System.out.println(counter2); } public static int counter2 = 0; public static Singleton getSingleton() { return singleton; } }
/** * 當一個類被初始化的時候,它所實現的接口是不會被初始化的 */ public class MyTest5 { public static void main(String[] args) { // 6 System.out.println(MyChild5.b); } } interface MyParent5 { public static Thread thread = new Thread() { { System.out.println("MyParent5 invoked"); } }; } class MyChild5 implements MyParent5 { public static int b = 6; }
根類(啓動類)加載器 -> 擴展類加載器 -> 系統類加載器 -> 用戶自定義類加載器dom