Java中子類和父類相關方法的執行順序


無意中看到下面一個題目,大家一起來看看最后的輸出結果是什么。反正我看完之后,用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
View Code

你們答對了么?哈哈,現在來看一下代碼具體執行情況:

1、首先是main方法,new了一個B對象,然后就是調用該對象的getValue()方法

2、執行B類的構造方法

3、執行B類構造方法里面的super方法,即執行B的父類A的構造方法。

4、接下來就是執行setValue()方法了,但是此時A類和B類都有一個setValue()方法,到底執行哪一個呢,我一開始認為是A類的setValue()方法。

但在A類的構造方法中執行setValue()方法時,你是不是看到了,它執行的是子類B的setValue()方法。

顯然這需要鞏固一個知識點:當子類重寫了父類的函數,那么子類的對象如果調用該函數,一定調用的是重寫過后的函數。可以通過super關鍵字進行父類的重寫函數的調用。

因為現在正在執行的是B類的構造方法,所以默認先會調用B類中的方法,如果B類中沒有,才會調用其父類A中的方法

5、接下來到super.setValue(2 * value),即執行A類的setValue()方法,這時,A類的成員變量value應該就變成了10

 6、這時B類的構造方法中的super(5)就執行完了,然后就到了setValue(getValue() - 3)方法

7、接着執行getValue()方法,首先在B類中找,但B類沒有getValue()方法,所以就執行A類中的getValue()方法,A類中肯定是有的,要不然編譯就不會通過

8、然后就開始執行try、catch、finally這一塊,給A的成員變量value自增,從之前的10變為11,然后直接返回value,沒有捕獲異常,繼續到finally里面的this.setValue(value)

 

9、然后這個this指的到底是A類還是B類呢,答案是B類,因為現在是在執行B的構造方法,所以this指的應該是B類,即調用B類的setValue(int value)方法。

10、然后又super.setValue(2 * value);執行父類A的setValue(int value),把2 * 11作為參數傳遞,A類的setValue(int value)把傳進來的value值賦給了A的成員變量value,變成了22。

11、然后this.setValue(value)就執行完了,最后輸出value,22

12、到這兒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)

13、調用A類的setValue(int value)方法,同時將參數賦值給A類的成員變量value,此時value變為16

14、到這兒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。所以整個過程執行完后的輸出結果是22、34、17。。。。。。

這道題雖然饒了很多彎,但是我們做完后發現整體過程其實並不是很復雜,就是子類繼承父類,調用方法時先是調用子類中的方法,如果沒有就調用父類中的方法,還有一點就是try{ }、catch{ }、finally{ }返回值的問題,一旦try{ }中返回了某一個值,如果finally有返回值,finally中的返回值會覆蓋try的返回值,如果finally沒有返回值,就是try中的返回值。掌握了這些,這道題就顯得很簡單了。

 

Java初始化順序如圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM