1. 程式人生 > >子類重寫父類方法後的呼叫規則

子類重寫父類方法後的呼叫規則

例題:

(單選題) 下面程式碼的輸出是什麼?
  1. publicclass Base {  
  2.     private String baseName= "base";  
  3.     public Base(){  
  4.         callName();  
  5.     }  
  6.     publicvoid callName(){  
  7.         System.out.println(baseName);  
  8.     }  
  9.     staticclass Sub extends Base{  
  10.         private String baseName = "sub";  
  11.         public
    void callName(){  
  12.             System.out.println(baseName);  
  13.         }  
  14.     }  
  15.     publicstaticvoid main(String[] args){  
  16.         Base b = new Sub();  
  17.     }  
  18. }  


A.null

B.sub

C.base

答案:A

為了能更好的分析程式碼執行過程, 做原有程式碼做一些變動如下:

  1. publicclass Base {  
  2.     private String baseName= "base";  
  3.     public
     Base(){  
  4.         System.out.println("Constructor Base : " + baseName);  
  5.         System.out.println("before Base callName() -----" );  
  6.         callName();  
  7.         System.out.println("after Base callName() -----" );  
  8.     }  
  9.     publicvoid callName(){  
  10.         System.out.println("& " + baseName);  
  11.     }  
  12.     staticclass Sub extends Base{  
  13.         private String baseName = "sub";  
  14.         public Sub(){  
  15.             System.out.println("Constructor Sub : " + baseName);  
  16.         }  
  17.         @Override
  18.         publicvoid callName(){  
  19.             System.out.println("# " + baseName);  
  20.         }  
  21.     }  
  22.     publicstaticvoid main(String[] args){  
  23.         new Sub();  
  24.     }  
  25. }  
此時 main 方法內 new Sub();

輸出結果:

  1. Constructor Base : base  
  2. before Base callName() -----  
  3. # null  
  4. after Base callName() -----  
  5. Constructor Sub : sub  

再將main方法做如下變動:

  1. publicstaticvoid main(String[] args){  
  2.     Base b = new Sub();  
  3.     b.callName();  
  4. }  

輸出結果

  1. Constructor Base : base  
  2. before Base callName() -----  
  3. # null  
  4. after Base callName() -----  
  5. Constructor Sub : sub  
  6. # sub   


綜上所述, 此時執行的是子類Sub的callName() 方法, 

new Sub();在創造派生類的過程中首先建立基類物件,然後才能建立派生類。 建立基類即預設呼叫Base()方法,在方法中呼叫callName()方法,由於派生類中存在此方法,則被呼叫的callName()方法是派生類中的方法,此時派生類還未構造,所以變數baseName的值為null 先成員變數再構造方法,先父類再子類 多型表現:有同名方法執行子類的 執行 Base b = new Sub();時,由於多型 b編譯時表現為Base類特性,執行時表現為Sub類特性 Base b = new Sub();不管是哪種狀態都會呼叫Base構造器執行callName()方法; 執行方法時,由於多型表現為子類特性,所以會先在子類是否有 callName(); 而此時子類尚未初始化(執行完父類構造器後才會開始執行子類),如果有 就 執行(此時, 因為還沒有呼叫子類建構函式, 所以子類的 baseName 輸出為 null),沒有再去父類尋找。