面試題:
如下兩個類的代碼
/*父類對象*/
public class Father{
private int i = test();
private static int j = method();
static{
System.out.print("(1)");
}
Father(){
System.out.print("(2)");
}
{
System.out.print("(3)");
}
public int test(){
System.out.print("(4)");
return 1;
}
public static int method(){
System.out.print("(5)");
return 1;
}
}
/*子類對象*/
public class Son extends Father{
private int i = test();
private static int j = method();
static{
System.out.print("(6)");
}
Son(){
System.out.print("(7)");
}
{
System.out.print("(8)");
}
public int test(){
System.out.print("(9)");
return 1;
}
public static int method(){
System.out.print("(10)");
return 1;
}
public static void main(String[] args) {
Son s1 = new Son();
System.out.println();
Son s2 = new Son();
}
}
問題:
- 執行Son類的main函數,控制檯打印的結果是什麼?
- 如果main方法什麼都不寫,控制檯打印的結果是什麼?
結果
第一題答案:
(5)(1)(10)(6)(9)(3)(2)(9)(8)(7)
(9)(3)(2)(9)(8)(7)
第二題答案:
(5)(1)(10)(6)
你是否答對了?
類的初始化過程
要使用到一個類對其進行實例化
就需要先對類進行初始化
,而且類的初始化只執行一次!這個特點可以做單例模式
類的初始化就是將靜態成員變量
和靜態代碼塊
進行初始化,靜態代碼塊和靜態成員變量的執行順序按照代碼的先後順序執行,誰在上面就誰先執行初始化!
注意:main方法所在的類先加載和初始化,該類的初始化又要先初始化父類
也就是說最先初始化的類是父類的靜態代碼塊或者靜態成員變量
,然後是子類的靜態代碼塊或者靜態成員變量
靜態代碼塊和靜態成員變量的先後順序由代碼先後順序影響
實例化的初始化過程
一個類要進行實例化,就需要先對類初始化
然後再實例化,實例化又需要先實例化父類,後實例化子類
實例化需要初始化非靜態成員變量
和非靜態代碼塊
,非static的成員變量和代碼塊的先後順序也是誰先聲明誰先執行。
最後執行構成方法
總結
整體的初始化排序
類初始化 > 實例化初始化
**父類**靜態成員變量 或 靜態代碼塊(順序由聲明先後順序定)
>
**子類**靜態成員變量 或 靜態代碼塊(順序由聲明先後順序定)
>
**父類**非靜態成員變量 或 非靜態代碼塊(順序由聲明先後順序定)
>
父類構造方法
>
**子類**非靜態成員變量 或 非靜態代碼塊(順序由聲明先後順序定)
>
子類構造方法
如果以16進制的方式去查看編譯後的class文件會發現有<clinit>、<init>等方法
而<clinit>()就是進行類初始化執行的指令,裏面由 靜態類成員變量顯示賦值 和 靜態代碼塊 組成,裏面的順序按照聲明順序先後執行
<init>()可能有多個,因爲有無參構造器和有參構造器,有幾個構造器就有幾個<init>()。是執行示例化初始化的指令,裏面由 非靜態類成員變量顯示賦值 和 非靜態代碼塊 組成,裏面的順序按照聲明順序先後執行,<init>()首行一定是super();構造器裏的代碼最後執行。每一次實例化都執行一次<init>()