java父類調用被子類重寫的方法


[轉]【 原文】 

1.如果父類構造器調用了被子類重寫的方法,且通過子類構造函數創建子類對象,調用了這個父類構造器(無論顯示還是隱式),就會導致父類在構造時實際上調用的是子類覆蓋的方法(你需要了解java繼承中的初始化機制)。

例子:
[java]  view plain  copy
  1. public abstract class Father {  
  2.     public Father() {  
  3.         display();  
  4.     }  
  5.   
  6.     public void display() {  
  7.         System.out.println("Father's display");  
  8.     }     
  9. }  
[java]  view plain  copy
  1. public class Son extends Father {  
  2.   
  3.     public Son() {  
  4.     }  
  5.   
  6.     public void display() {  
  7.         System.out.println("Son's display");  
  8.     }  
  9.       
  10.     public static void main(String[] args) {  
  11.         new Son();  
  12.     }  
  13.   
  14. }  


輸出為:
Son's display
這種機制有優點,不過有時也存在問題。

優點:通過繼承相同的父類,初始化子類時,父類會調用不同子類的不同復寫方法,從而實現多態性。
舉一個Spring中的例子:
Spring中可以通過為每個DAO注入一個已經用DataSource初始化的JdbcTemplate,來執行SQL語句。但是每個DAO都通過編碼實現這個注入就產生了大量代碼冗余,於是Spring提供了一個JdbcDaoSupport類,DAO只需繼承這個類,就會自動注入已初始化好的JdbcTemplate,那么是如何做到的呢?查看源碼:
JdbcDaoSupport繼承了DaoSupport:
[java]  view plain  copy
  1. public abstract class JdbcDaoSupport extends DaoSupport  
DaoSupport實現了InitializingBean接口,該接口只有一個 void  afterPropertiesSet ()  throws  Exception;
方法,Spring會在初始化Bean的屬相后查看這個Bean是否實現了InitializingBean接口,如果繼承了就會自動調用afterPropertiesSet方法。
那么看一下DaoSupport中的afterPropertiesSet是如何實現的:
[java]  view plain  copy
  1. public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {  
  2.         // Let abstract subclasses check their configuration.  
  3.         checkDaoConfig();  
  4.   
  5.         // Let concrete implementations initialize themselves.  
  6.         try {  
  7.             initDao();  
  8.         }  
  9.         catch (Exception ex) {  
  10.             throw new BeanInitializationException("Initialization of DAO failed", ex);  
  11.         }  
  12.     }  
他這里調用了checkDaoConfig方法,此方法是抽象方法,真正運行時會去調用子類重寫過的該方法。
查看JdbcDaoSupport如何重寫checkDaoConfig():
[java]  view plain  copy
  1. @Override  
  2.     protected void checkDaoConfig() {  
  3.         if (this.jdbcTemplate == null) {  
  4.             throw new IllegalArgumentException("'dataSource' or 'jdbcTemplate' is required");  
  5.         }  
  6.     }  

JdbcDaoSupport會檢查jdbcTemplate是否注入,沒注入會拋出異常!這就完成了注入檢測,通過子類實現具體檢測的過程!這也就是當你的DAO繼承了JdbcDaoSupport,但是在XML配置DAO時沒有配置DataSource屬性會拋出異常的原因。
那么JdbcTemplate是何時注入的呢?觀察JdbcDaoSupport源碼,發現setDataSource()方法,框架根據XML配置初始化DAO時,會調用屬性的set方法注入,如果DAO沒有該set方法,則調用父類的。也就是調用JdbcDaoSupport的setDataSource方法,此時便創建了DAO執行SQL語句需要的jdbcTemplate。
[java]  view plain  copy
  1. /** 
  2.      * Set the JDBC DataSource to be used by this DAO. 
  3.      */  
  4.     public final void setDataSource(DataSource dataSource) {  
  5.         if (this.jdbcTemplate == null || dataSource != this.jdbcTemplate.getDataSource()) {  
  6.             this.jdbcTemplate = createJdbcTemplate(dataSource);  
  7.             initTemplateConfig();  
  8.         }  
  9.     }  


缺點:如果在父類構造函數中調用被子類重寫的方法,會導致子類重寫的方法在子類構造器的所有代碼之前執行,從而導致子類重寫的方法訪問不到子類實例變量的值,因為此時這些變量還沒有被初始化。


免責聲明!

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



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