java類初始化順序

[b][/b]
[/code]class Depend
{
int i = 10;
public Depend()
{
print();
i = 20;
}

void print()
{
System.out.println("Depend=> " + i);
}
}


public class Qdb extends Depend
{
int i = 30;
public Qdb()
{
print();
super.print();
i = 40;
}

void print()
{
System.out.println("Target=> " + i);
}

public static void main(String[] args)
{
new Qdb();
}
}
其結果是:

Target=> 0
Target=> 30
Depend=> 20



爲什麼呢?

我們順着初始化的順序來說
首先程序從main方法開始執行,new Qdb(),這句話就是要new一個Qdb的對象,根據對象初始化的順序,初始化子類之前必須要初始化父類,所以此時一系列的調用開始了
1,調用Qdb的父類Depend類的構造函數,在調用構造函數之前,成員變量是先於構造函數初始化的,這個時候Depend裏面的i已經有值了,它的值就是10,在Depend構造函數裏面,我們看到的第一句是:print方法,這個print方法我們要注意,它在Depend的子類也定義了,並且此次初始化是由子類Qdb發起的,所以實際上這個print方法調用的是Qdb裏面定義的print,而這個時候有意思的事情就出現了,此時子類還沒有出生呢,因爲這個時候父類才正在構造之中,所以子類中此時的i還是0,而print正好打印出的是子類的i,所以第一次輸出是0;
2,父類調用完子類的print後,把父類的i賦了值20,此時父類已經完全被構造出來了,馬上就要開始構造子類了.
3,同理,在調用子類的構造函數之前,子類的i被賦了初值30,然後進入子類的構造函數,此時調用的也是print,這個就非常好理解了,這個print肯定是子類自己的print方法了,此時i已經構造好,當然,此時輸出的值是30;
4,下一句super.print(),這句話顯示的調用了父類的print方法,而此時父類的i已經在父類的構造函數裏面改爲20了,所以此次調用輸出20.
5,然後再把子類的i的值設爲50.

在以上過程中,如果掌握好了類的初始化順序,是比較容易知道輸出結果的.還有一點要記住,JAVA裏面的方法是動態綁定的,而成員卻是靜態綁定的.父類裏面調用的print之所以會輸出0,就是因爲print實際上調用的是子類的print,因爲整個這場調用都是由new Qdb()這句話產生的.



接着再看下面的:
[code="java"]

class A {
int i = 10;
static {
System.out.print("1");
}

public A() {
System.out.print("2");
}


}

class B extends A {
int i = 20;
static {
System.out.print("a");
}

public B() {
System.out.print("b");
}


}

public class Heloo {
public static void main(String[] arge) {
System.out.println(" ");
A ab = new B();
System.out.println(" ");
ab = new B();
}
}

class A {
int i = 10;
static {
System.out.print("1");
}

public A() {
System.out.print("2");
}


}

class B extends A {
int i = 20;
static {
System.out.print("a");
}

public B() {
System.out.print("b");
}


}

public class Heloo {
public static void main(String[] arge) {
System.out.println(" ");
A ab = new B();
System.out.println(" ");
ab = new B();
}
} 結果是:

1a2b
2b


原因:

這個是類的初始化順序問題
1、類只有在使用New調用創建的時候纔會被JAVA類裝載器裝入
2、JAVA類首次裝入時,會對靜態成員變量或方法進行一次初始化,但方法不被調用是不會執行的,靜態成員變量和靜態初始化塊級別相同,非靜態成員變量和非靜態初始化塊級別相同。
先初始化父類的靜態代碼--->初始化子類的靜態代碼-->
初始化父類的非靜態代碼--->初始化父類構造函數--->
初始化子類非靜態代碼--->初始化子類構造函數
3、創建類實例時,首先按照父子繼承關係進行初始化
4、類實例創建時候,首先初始化塊部分先執行,然後是構造方法;然後從
本類繼承的子類的初始化塊執行,最後是子類的構造方法
上例中類A類B都有靜態代碼static


從main函數開始:
System.out.println(" ");
輸出空格
A ab = new B();
聲明爲類A但初始化爲類B
因爲編譯器是從左向右進行的,所以先是A ab;
執行System.out.print("1"); 因爲沒有new A();
所以不執行類A的構造函數.那爲什麼會輸出2呢?
是因爲B類是繼承A類的,所是在執行new B();
的時候,執行順序是初始化System.out.print("a");
然後先父類後子類,static代碼只執行一次(已執行過);
執行System.out.print("2");
執行System.out.print("b");
執行System.out.println(" ");
之後是ab = new B(); A,B中的static都已被執行過,
所以只執行構造函數,因B類有父類A,所以先執行A 類的構
造函數System.out.print("2");
再執行B類的構造函數
System.out.print("b");
發佈了18 篇原創文章 · 獲贊 0 · 訪問量 813
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章