還寫了個姊妹篇參考:Java 類加載機制(阿里)-何時初始化類
類加載
類加載的五個過程
eg: class Test{ static{ i = 4; //正常 System.out.println(i)//報錯,因為不能訪問,只能賦值 } static int i = 2; }
2、擴展類加載器,Extension ClassLoader,加載\lib\ext,或者被java.ext.dirs系統變量指定的類
3、應用程序類加載器,Application ClassLoader,加載ClassPath中的類庫
4、自定義類加載器,通過繼承ClassLoader實現,一般是加載我們的自定義類
Field c = cls.getDeclaredField("a"); c.setAccessible(true);//這里如果不設置的話,會拋出IllegalAccessException()異常 c.set(car, 888); ...
下面是代碼:
package com.ioc; public class Car { private String brant; private String color; private int maxSpeed; private int a; public String getBrant() { return brant; } public void setBrant(String brant) { this.brant = brant; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } public Car(){} public Car(String brant,String color,int max) { this.brant = brant; this.color = color; this.maxSpeed = max; } public String toString(){ String a = brant+color+maxSpeed; return a; } public void print(){ System.out.println(brant+color+maxSpeed+a); } }
反射調用的代碼:
驗證一下:
驗證:
1)當類被初始化時,其靜態代碼塊會執行。
class ClassLoadTime{ static{ System.out.println("ClassLoadTime類初始化時就會被執行!"); } public ClassLoadTime(){ System.out.println("ClassLoadTime構造函數!"); } } class ClassLoadDemo{ public static void main(String[] args){ ClassLoadTime clt = new ClassLoadTime(); } }
輸出結果:
ClassLoadTime類初始化時就會被執行!
ClassLoadTime構造函數!
2) 讀取一個類的靜態字段(被final修飾、已在編譯期把結果放在常量池的靜態字段除外)
class ClassLoadTime{ static{ System.out.println("ClassLoadTime類初始化時就會被執行!"); } public static int max = 200; (防止測試類和此類不在一個包,使用public修飾符) public ClassLoadTime(){ System.out.println("ClassLoadTime構造函數!"); } } class ClassLoadDemo{ public static void main(String[] args){ int value = ClassLoadTime.max; System.out.println(value); } }
輸出:
ClassLoadTime類初始化時就會被執行!
200
3)設置一個類的靜態字段(被final修飾、已在編譯期把結果放在常量池的靜態字段除外)
class ClassLoadTime{ static{ System.out.println("ClassLoadTime類初始化時就會被執行!"); } public static int max = 200; (防止測試類和此類不在一個包,使用public修飾符) public ClassLoadTime(){ System.out.println("ClassLoadTime構造函數!"); } } class ClassLoadDemo{ public static void main(String[] args){ ClassLoadTime.max = 100; } }
輸出:
ClassLoadTime類初始化時就會被執行!
4)調用一個類的靜態方法
class ClassLoadTime{ static{ System.out.println("ClassLoadTime類初始化時就會被執行!"); } public static int max = 200; (防止測試類和此類不在一個包,使用public修飾符) public ClassLoadTime(){ System.out.println("ClassLoadTime構造函數!"); } public static void method(){ System.out.println("靜態方法的調用!"); } } class ClassLoadDemo{ public static void main(String[] args){ ClassLoadTime.method(); } }
輸出:
ClassLoadTime類初始化時就會被執行!
靜態方法的調用!
被final修飾靜態字段在操作使用時,不會使類進行初始化,因為在編譯期已經將此常量放在常量池。
測試:
class ClassLoadTime{ static{ System.out.println("ClassLoadTime類初始化時就會被執行!"); } public static final int MIN = 10; (防止測試類和此類不在一個包,使用public修飾符) } class ClassLoadDemo{ public static void main(String[] args){ System.out.println(ClassLoadTime.MIN); } }
輸出:
10
子類調用或者設置父類的靜態字段或者調用父類的靜態方法時僅僅初始化父類,而不初始化子類。同樣讀取final修飾的常量不會進行類的初始化。
class Fu{ public static int value = 20; static{ System.out.println("父類進行了類的初始化!"); } } class Zi{ static{ System.out.println("子類進行了類的初始化!"); } } class LoadDemo{ public static void main(String[] args){ System.out.println(Zi.value); } }
輸出:
父類進行了類的初始化!
20
java類中各種成員的初始化時機,此處不一一測試:
類變量(靜態變量)、實例變量(非靜態變量)、靜態代碼塊、非靜態代碼塊 的初始化時機:
* 由 static 關鍵字修飾的(如:類變量[靜態變量]、靜態代碼塊)將在類被初始化創建實例對象之前被初始化,而且是按順序從上到下依次被執行;
public static int value =34; static{ System.out.println("靜態代碼塊!"); } public 類名(){ System.out.println("構造函數!"); }
一旦這樣寫,在類被初始化創建實例對象之前會先初始化靜態字段value,然后執行靜態代碼塊,當實例化對象時會執行構造方法中的代碼
* 沒有 static 關鍵字修飾的(如:實例變量[非靜態變量]、非靜態代碼塊)初始化實際上是會被提取到類的構造器中被執行的,但是會比類構造器中的
代碼塊優先執行到,其也是按順序從上到下依次被執行。
public int value =34; { System.out.println("非靜態代碼塊!"); } public 類名(){ System.out.println("構造函數!"); }
在使用構造函數實例化一個對象時,會先初始化value,然后執行非靜態代碼塊,最后執行構造方法里面的代碼。
*在存在父類的時候,調用子類的構造時,會先調用父類的默認構造(空參構造),進行父類的初始化。
參考:java中類加載時機