無心中看到下面一個題目,你們一塊兒來看看最後的輸出結果是什麼。反正我看完以後,用IDE測試後感受知識點獲得鞏固了。ide
1 /** 2 * 函數執行順序測試 3 * Created by 萌小Q on 2017/5/17 0017. 4 */ 5 public class ExeSeqTest { 6 7 public static void main(String [] args){ 8 System.out.println(new B().getValue()); 9 } 10 static class A{ 11 protected int value; 12 public A(int v) { 13 setValue(v); 14 } 15 public void setValue(int value){ 16 this.value = value; 17 } 18 public int getValue(){ 19 try{ 20 value++; 21 return value; 22 } catch(Exception e){ 23 System.out.println(e.toString()); 24 } finally { 25 this.setValue(value); 26 System.out.println(value); 27 } 28 return value; 29 } 30 } 31 static class B extends A{ 32 public B() { 33 super(5); 34 setValue(getValue() - 3); 35 } 36 public void setValue(int value){ 37 super.setValue(2 * value); 38 } 39 } 40 }
執行結果:函數
22 34 17
大家答對了麼?哈哈,如今來看一下代碼具體執行狀況:測試
一、首先是main方法,new了一個B對象,而後就是調用該對象的getValue()方法this
二、執行B類的構造方法spa
三、執行B類構造方法裏面的super方法,即執行B的父類A的構造方法。3d
四、接下來就是執行setValue()方法了,可是此時A類和B類都有一個setValue()方法,到底執行哪個呢,我一開始認爲是A類的setValue()方法。code
但在A類的構造方法中執行setValue()方法時,你是否是看到了,它執行的是子類B的setValue()方法。對象
顯然這須要鞏固一個知識點:當子類重寫了父類的函數,那麼子類的對象若是調用該函數,必定調用的是重寫事後的函數。能夠經過super關鍵字進行父類的重寫函數的調用。blog
由於如今正在執行的是B類的構造方法,因此默認先會調用B類中的方法,若是B類中沒有,纔會調用其父類A中的方法。繼承
五、接下來到super.setValue(2 * value),即執行A類的setValue()方法,這時,A類的成員變量value應該就變成了10
六、這時B類的構造方法中的super(5)就執行完了,而後就到了setValue(getValue() - 3)方法
七、接着執行getValue()方法,首先在B類中找,但B類沒有getValue()方法,因此就執行A類中的getValue()方法,A類中確定是有的,要否則編譯就不會經過
八、而後就開始執行try、catch、finally這一塊,給A的成員變量value自增,從以前的10變爲11,而後直接返回value,沒有捕獲異常,繼續到finally裏面的this.setValue(value)
九、而後這個this指的究竟是A類仍是B類呢,答案是B類,由於如今是在執行B的構造方法,因此this指的應該是B類,即調用B類的setValue(int value)方法。
十、而後又super.setValue(2 * value);執行父類A的setValue(int value),把2 * 11做爲參數傳遞,A類的setValue(int value)把傳進來的value值賦給了A的成員變量value,變成了22。
十一、而後this.setValue(value)就執行完了,最後輸出value,22
十二、到這兒getValue()方法就執行完了,可是有一點須要注意,此時的value爲22,可是getValue()的返回值確是11,由於在try{ }中已經return了,因此這個方法的返回值已經保存下來了,是11,即便finally{ }裏面又對value的值作出了改變,可是getValue()的返回值是不會變的(除了finally裏面也有return返回值,它會覆蓋前面try的返回值)。接着繼續執行B類構造方法中的setValue(getValue() - 3);getValue()是11,因此B的setValue(int value)方法的參數就爲8,接着又到了super.setValue(2 * value)
1三、調用A類的setValue(int value)方法,同時將參數賦值給A類的成員變量value,此時value變爲16
1四、到這兒B類的構造方法就所有執行完了,也就是new B(),而後又調用了該對象 的getValue()方法,B類沒有,可是父類A有,
繼續try{ }、catch{ }、finally{ },A類的成員變量value爲16,而後value++,再返回,這時getValue()的返回值已經肯定了,就是17,即便在finally中對value作出改變,其返回值不會變。而後到finally{ },又是this.setValue(value),前面已經說過了,這個this指的是B類的this,因此調用B類的setValue(int value)
接着又是super.setValue(2 * value),調用A類的setValue(),並把2 * 17做爲參數傳遞過去
把參數賦給A的成員變量value,這時this.setValue(value)就執行完了,此時的value爲34。最後輸出value。
須要注意的是,此時的getValue()方法的返回值是17,這個前面已經提到了,到這兒,整個new B().getValue()就執行完了,最後又輸出了getValue的返回值,也就是17。因此整個過程執行完後的輸出結果是2二、3四、17。。。。。。
這道題雖然饒了不少彎,可是咱們作完後發現總體過程其實並非很複雜,就是子類繼承父類,調用方法時先是調用子類中的方法,若是沒有就調用父類中的方法,還有一點就是try{ }、catch{ }、finally{ }返回值的問題,一旦try{ }中返回了某一個值,若是finally有返回值,finally中的返回值會覆蓋try的返回值,若是finally沒有返回值,就是try中的返回值。掌握了這些,這道題就顯得很簡單了。
Java初始化順序如圖: