靜態代碼塊
static可以修飾屬性、方法、內部類、代碼塊
靜態代碼塊在類加載時就調用, 而且只執行一次, 並且優先於各種代碼塊以及構造函數。
有一個地方的靜態代碼被使用,那麼所有的靜態代碼塊都會被調用
下面通過實例理解一下
父類
public class Human {
static {
System.out.println("2.父類中的靜態代碼塊");
}
public String name;
public Human() {
System.out.println("1.父類中的構造方法");
}
public static void test() {
System.out.println("6.父類中的靜態方法");
}
}
子類
public class Man extends Human {
static {
System.out.println("4.子類中的靜態代碼塊");
}
public Man() {
System.out.println("3.子類中的構造方法");
}
public static void doo() {
System.out.println("5.子類中的靜態方法");
}
}
主類
public class Main {
public static void main(String[] args) {
// Human human = new Man(); 輸出2 4 1 3
//父類的類名調用父類的方法
//Human.test(); 輸出2 6 在調用靜態代碼時,怕需要上面的靜態代碼塊的內容,所以將其鏈接到內存 與子類無關
//子類的類名調用子類的方法
//Man.doo(); 輸出2 4 5 在調用子類的靜態方法時,父類的靜態代碼塊執行,與父類的靜態代碼塊有關
//子類的類名調用父類的方法
//Man.test(); 輸出 2 6 注意這個能調test不是因爲繼承,test聲明在了human裏,子類可以調用父類的方法,但是父類不能調用子類的方法 所以在Main中不可直達Man中的的方法
//子類調用了父類的方法,在父類的方法裏又引用了子類裏的靜態方法
//Man.test(); 輸出 2 6 4 5
}
}
靜態代碼塊內容先執行(但只執行一次),接着執行父類構造方法,然後執行子類構造方法。
什麼時候加載類?
主動引用
1、使用new關鍵字實例化對象
2、調用一個類的靜態方法的時候
3、訪問某個類或者接口的靜態變量,或者對該靜態變量賦值
4、當初始化一個類時,發現其父類還沒有進行初始化,則需要先觸發其父類的類的初始化
5、JVM啓動時標明的啓動類,即文件名和類名相同的類
所有引用類的方式都不會觸發初始化,稱爲被動引用,如下:
1、通過子類引用父類的靜態字段,不會導致子類的初始化
2、通過數組來定義引用類,不會觸發此類的初始化
3、常量在編譯階段會存入調用類的常量池,本質上並沒有直接引用到定義常量的類
對於3舉個例子:
public class Woman {
public static final int a = 1;
static {
System.out.println("我是女人類的靜態代碼塊");
}
}
public class Main {
public static void main(String[] args) {
System.out.println(Woman.a); //只是輸出1,但如果a不定義爲常量,這裏調用a就會加載Women類的靜態代碼塊
}
}
雙親委派原則
類加載一般符合雙親委派原則
如果一個類收到了類加載的請求,不會自己先嚐試加載,先找父類加載器去完成。當頂層啓動類加載器表示無法加載這個類的時候,子類纔會嘗試自己去加載。當回到最開的發起者加載器還無法加載時,並不會向下找,而是拋出ClassNotFound異常。(如果類A中引用了類B,Java虛擬機將使用加載類A的類加載器來加載類B)
雙親委派原則是參考這兩個網址的內容:
https://blog.csdn.net/u014307117/article/details/47307225
https://blog.csdn.net/weixin_43784989/article/details/99312079