本文重點關注靜態塊、非靜態塊、構造函數的加載順序
直接上代碼:
- package test.staticblock;
- public class A {
- /*父類構造方法*/
- public A(){
- System.out.println("A constructor");
- }
- /*父類靜態塊*/
- static
- {
- System.out.println("A static Block");
- }
- /*父類非靜態塊*/
- {
- System.out.println("A non-static Block");
- }
- /*父類靜態方法*/
- public static void printStaticMethod(){
- System.out.println("A print Static Method");
- }
- /*父類普通方法*/
- public void printNormalMethod(){
- System.out.println("A print Normal Method");
- }
- }
- class B extends A{
- /*子類1構造方法*/
- public B(){
- System.out.println("B constructor");
- }
- /*子類1靜態塊*/
- static{
- System.out.println("B static Block");
- }
- /*子類1非靜態塊*/
- {
- System.out.println("B non-static Block");
- }
- /*子類1靜態方法*/
- public static void printStaticMethod(){
- System.out.println("B print Static Method");
- }
- /*子類1普通方法*/
- public void printNormalMethod(){
- System.out.println("B print Normal Method");
- }
- }
- class C extends A{
- /*子類2構造方法*/
- public C(){
- System.out.println("C constructor");
- }
- /*子類2靜態塊*/
- static{
- System.out.println("C static Block");
- }
- /*子類2非靜態塊*/
- {
- System.out.println("C non-static Block");
- }
- /*子類2靜態方法*/
- public static void printStaticMethod(){
- System.out.println("C print Static Method");
- }
- /*子類2沒有override父類的普通方法*/
- }
- package test.staticblock;
- public class Test {
- public static void main(String[] args){
- A a1 = new B();
- A a2 = new C();
- a1.printStaticMethod();
- a1.printNormalMethod();
- a2.printStaticMethod();
- a2.printNormalMethod();
- }
- }
運行結果:
- A static Block
- B static Block
- A non-static Block
- A constructor
- B non-static Block
- B constructor
- C static Block
- A non-static Block
- A constructor
- C non-static Block
- C constructor
- A print Static Method
- B print Normal Method
- A print Static Method
- A print Normal Method
根據結果分析:
順序應該是這樣的:父類Static->子類static->父類缺省{}->父類構造函數->子類缺省{}->子類構造函數
A static Block |
父類靜態塊 |
B static Block |
子類1靜態塊 |
A non-static Block |
父類非靜態塊,缺省塊 |
A constructor |
父類構造函數 |
B non-static Block |
子類1非靜態塊,缺省塊 |
B constructor |
子類1構造函數 |
C static Block |
子類2靜態塊,由此可以看出static塊僅在類加載時執行且僅執行一遍,因爲A的靜態塊已經執行過了,這裏不會再執行。 |
A non-static Block |
父類非靜態塊,缺省塊 |
A constructor |
父類構造函數 |
C non-static Block |
子類2非靜態塊,缺省塊 |
C constructor |
子類2構造函數 |
B print Static Method B print Vitural Method C print Static Method A print Vitural Method |
|
分析:當執行new
B()和new C()時,它首先去看父類裏面有沒有靜態代碼塊,如果有,它先去執行父類裏面靜態代碼塊裏面的內容,當父類的靜態代碼塊裏面的內容執行完畢之後,接着去執行子類(自己這個類)裏
面的靜態代碼塊,當子類的靜態代碼塊執行完畢之後,它接着又去看父類有沒有非靜態代碼塊,如果有就執行父類的非靜態代碼塊,父類的非靜態代碼塊執行完畢, 接着執行父類的構造方法;父類的構造方法執行完畢之後,它接着去看子類有沒有非靜態代碼塊,如果有就執行子類的非靜態代碼塊。子類的非靜態代碼塊執行完畢 再去執行子類的構造方法,這個就是一個對象的初始化順序。
總結:對象的初始化順序:首
先執行父類靜態的內容,父類靜態的內容執行完畢後,接着去執行子類的靜態的內容,當子類的靜態內容執行完畢之後,再去看父類有沒有非靜態代碼塊,如果有就 執行父類的非靜態代碼塊,父類的非靜態代碼塊執行完畢,接着執行父類的構造方法;父類的構造方法執行完畢之後,它接着去看子類有沒有非靜態代碼塊,如果有 就執行子類的非靜態代碼塊。子類的非靜態代碼塊執行完畢再去執行子類的構造方法。總之一句話,靜態代碼塊內容先執行,接着執行父類非靜態代碼塊和構造方 法,然後執行子類非靜態代碼塊和構造方法。
注意:子類的構造方法,不管這個構造方法帶不帶參數,默認的它都會先去尋找父類的不帶參數的構造方法。如果父類沒有不帶參數的構造方法,那麼子類必須用supper關鍵子來調用父類帶參數的構造方法,否則編譯不能通過。
重要一點:
static 塊僅在類加載時,並非實例化時,被執行一遍,且在整個過程中只可能被執行一遍,這也就是在實例化C時
A a2 = new C();
A的static塊沒有被執行的原因。
但非靜態塊在實例化對象時總會被執行。
靜態塊一般用於初始化類中的靜態成員;而非靜態塊一般用於初始化類中的非靜態成員;
另外,非靜態塊是在創建對象時自動執行的代碼。
部分參考:
http://blog.sina.com.cn/s/blog_499b09000100d9rj.html