實例代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/** * Created by fei on 2017/5/31. */ public class SonClass extends ParentClass{ public SonClass(){ System.out.println( "SonClass's constructor" ); } { System.out.println( "SonClass's block" );} static { System.out.println( "SonClass's static block " ); } public static void main(String[] args) { System.out.println( "------ main start ------ " ); new SonClass(); System.out.println( "------ main end ------ " ); } } class ParentClass{ public ParentClass(){ System.out.println( "ParentClass's constructor" ); } { System.out.println( "ParentClass's block" );} static { System.out.println( "ParentClass's static block " ); } } |
運行結(jié)果:
1
2
3
4
5
6
7
8
|
ParentClass's static block SonClass's static block ------ main start ------ ParentClass's block ParentClass's constructor SonClass's block SonClass's constructor ------ main end ------ |
根據(jù)運行結(jié)果,一目了然,在執(zhí)行 main 方法中 new SonClass() 之前,就在類加載之后執(zhí)行了類中 static 代碼塊。然后再進(jìn)入main方法,執(zhí)行new操作,當(dāng)然顯而易見,在執(zhí)行new子類操作的時候,是要先進(jìn)行其父類的構(gòu)造,即先執(zhí)行父類的構(gòu)造代碼塊(代碼中只用大括號包裹的那段代碼)以及構(gòu)造函數(shù) ,然后再執(zhí)行子類的構(gòu)造代碼塊以及構(gòu)造函數(shù)。
修改一下代碼,再來看看運行的結(jié)果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/** * Created by fei on 2017/5/31. */ public class SonClass extends ParentClass{ ParentClass parentClass; public SonClass(){ System.out.println( "1" ); } public SonClass(String name){ System.out.println( "2" ); this .name = name; parentClass = new ParentClass( "FEI" ); } public static void main(String[] args) { System.out.println( "------ main start ------ " ); new SonClass( "fei" ); System.out.println( "------ main end ------ " ); } } class ParentClass{ String name ; public ParentClass(){ System.out.println( "3" ); } public ParentClass(String name){ System.out.println( "4" ); this .name = name ; } } |
運行的順序是:
1
2
3
4
5
|
------ main start ------ 3 2 4 ------ main end ------ |
第一個規(guī)則:子類的構(gòu)造過程中,必須調(diào)用其父類的構(gòu)造方法。一個類,如果我們不寫構(gòu)造方法,那么編譯器會幫我們加上一個默認(rèn)的構(gòu)造方法(就是沒有參數(shù)的構(gòu)造方法),但是如果你自己寫了構(gòu)造方法,那么編譯器就不會給你添加了,所以有時候當(dāng)你new一個子類對象的時候,肯定調(diào)用了子類的構(gòu)造方法,但是如果在子類構(gòu)造方法中我們并沒有顯示的調(diào)用基類的構(gòu)造方法,如:super(); 這樣就會調(diào)用父類沒有參數(shù)的構(gòu)造方法。
第二個規(guī)則:如果子類的構(gòu)造方法中既沒有顯示的調(diào)用基類構(gòu)造方法,而基類中又沒有無參的構(gòu)造方法,則編譯出錯,所以,通常我們需要顯示的:super(參數(shù)列表),來調(diào)用父類有參數(shù)的構(gòu)造函數(shù),此時無參的構(gòu)造函數(shù)就不會被調(diào)用。
總之,一句話:子類沒有顯示調(diào)用父類構(gòu)造函數(shù),不管子類構(gòu)造函數(shù)是否帶參數(shù)都默認(rèn)調(diào)用父類無參的構(gòu)造函數(shù),若父類沒有則編譯出錯。
還是兩個類,我們再更改一下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
/** * Created by fei on 2017/5/31. */ public class SonClass extends ParentClass{ private String name = "SonClass" ; public SonClass() { printName(); } public void printName() { System.out.println( "SonClass print name: " + name); } public static void main(String[] args){ new SonClass(); } } class ParentClass{ private String name = "ParentClass" ; public ParentClass() { //System.out.println(this.getClass()); printName(); } public void printName() { System.out.println( "ParentClass print name: " + name); } } |
看了上面的兩個例子,最后這個例子就很容易被迷惑,可能有人會覺得運行結(jié)果是類似這樣的:
1
2
|
ParentClass print name: ParentClass SonClass print name: SonClass |
或者是:
1
2
|
ParentClass print name: SonClass SonClass print name: SonClass |
但真正的結(jié)果是這樣的:
1
2
|
SonClass print name: null SonClass print name: SonClass |
為什么會這樣,其實只要打開代碼中父類構(gòu)造器中的這句注釋,就很容易理解了:System.out.println(this.getClass())
結(jié)果是:
1
|
class SonClass |
沒錯,父類中的this引用是子類實例對象,所以在父類構(gòu)造函數(shù)里調(diào)用的還是子類的printName()方法。具體原因也并我能十分肯定,我個人淺見,是因為雖然我們調(diào)用了父類的構(gòu)造方法,但是我們并沒有實例化出父類的實例對象,所以this還是指向的是子類的引用。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
原文鏈接:http://blog.csdn.net/zhangjunfei12103323/article/details/72821071