一、第一個例子:
class Insect
{
int i=9;
int j;
Insect()
{
prt("i="+i+",j="+j);
j=39;
}
static int x1=prt("static Insect.x1 initialized");
static int prt(String s)
{
System.out.println(s);
return 47;
}
}
public class Beetle extends Insect{
int k=prt("Beetle.k initialized");
Beetle()
{
prt("k="+k);
prt("j="+j);
}
static int x2=prt("static beetle.x2 initialized");
static int prt(String s)
{
System.out.println(s);
return 63;
}
public static void main(String[] args)
{
prt("Beetle Constructor");
Beetle b=new Beetle();
}
}
1.析一段java代碼執行後的結果,我們得先找到程序的入口,也就是mian()方法,才能着手分析。2.發現mian()方法在類Beetle中,那麼首先要將Beetle類加載到內存中,但立即發現Beetle類繼承與Insect類,於是要先將Insect類加載到內存中。
3.在將類加載到內存時,會發生static初始化(static就是在類被第一次加載的時候執行,以後就不在執行)。那麼此時先初始化Insect 的靜態變量x1。
4.接下來,加載Beetle類到內存中,並執行Beetle類的static初始化,即x2。
5.類被加載完成之後。轉入main()方法當中順序執行main()方法體內的代碼。
6.實例化Beetle的一個類時,執行Beetle類的構造方法,那麼首先要執行其基類Insect的構造方法。
7.在執行Insect的構造方法之前,按順序初始化Insect的非static變量。
8. 接着執行Insect的構造方法。
9.執行子類Beetle 的構造方法之前同理先按順序初始化Beetle 的非static變量。
10.接着執行Beetle 的構造方法。完成對Beetle類的實例化過程,即執行Beetle b=new Beetle();
所以以上代碼輸出結果爲:
static Insect.x1 initialized
static beetle.x2 initialized
Beetle Constructor
i=9,j=0
Beetle.k initialized
k=63
j=39
通過以上總結:
在有類繼承時,會從父類到子類依次執行static初始化。主類中的static初始化會在main()方法之前執行。所以初始化順序:
先初始化父類的靜態代碼-->初始化子類的靜態代碼-->
(創建實例時,如果不創建實例,則後面的不用的執行)初始化父類非靜態代碼-->初始化父類構造函數-->
初始化子類非靜態代碼-->初始化子類構造函數
二、再看一個例子:
package extend;
public class X {
Y y=new Y();
static{
System.out.println("tttt");
}
X(){
System.out.println("X");
}
public static void main(String[] args) {
new Z();
}
}
class Y{
Y(){
System.out.println("Y");
}
}
class Z extends X{
Y y=new Y();
static{
System.out.println("tt");
}
Z(){
System.out.println("Z");
}
}
執行順序:
1、由於main()方法在類X中,從main()方法入口執行程序時,首先將類X加載到內存中,加載的時候執行類X 的static初始化。
2、加載完畢,執行main()方法中的語句,實例化一個Z 的對象。
3、由於要實例化Z 的對象,所以要將Z類加載到內存中,由於類Z繼承與類X,所以先要加載類X,但是發現類X已被加載。
4、加載類Z時,執行類Z 的static初始化。
5、類Z加載完畢。準備執行類Z 的構造方法。
6、先轉去執行其父類X 的構造方法。
7、在執行類X 的構造方法之前先初始化X 的非靜態變量(包括句柄),按順序執行。
8、執行類X 的構造方法
9、按順序初始化類 Z 的非靜態變量。
10、初始化類Z 的構造方法,至此,類Z 的實例對象創建完畢,程序執行結束。
所以,執行結果爲:
tttt
tt
Y
X
Y
Z