父类调用子类重写方法---------多态

1.如果父类构造器调用了被子类重写的方法,且通过子类构造函数创建子类对象,调用了这个父类构造器(无论显示还是隐式),就会导致父类在构造时实际上调用的是子类覆盖的方法(你需要了解java继承中的初始化机制)。

Java代码 

 收藏代码

  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代码 

 收藏代码

  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代码 

 收藏代码

  1. public abstract class JdbcDaoSupport extends DaoSupport  

DaoSupport实现了InitializingBean接口,该接口只有一个void afterPropertiesSet() throws Exception;
方法,Spring会在初始化Bean的属相后查看这个Bean是否实现了InitializingBean接口,如果继承了就会自动调用afterPropertiesSet方法。

 

那么看一下DaoSupport中的afterPropertiesSet是如何实现的:

Java代码 

 收藏代码

  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代码 

 收藏代码

  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代码 

 收藏代码

  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. }   

 

缺点:如果在父类构造函数中调用被子类重写的方法,会导致子类重写的方法在子类构造器的所有代码之前执行,从而导致子类重写的方法访问不到子类实例变量的值,因为此时这些变量还没有被初始化。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值