24.黑马程序员-多态

来源:互联网 发布:ssh的默认端口号 编辑:程序博客网 时间:2024/05/17 01:19

------- android培训、java培训、期待与您交流! ----------

    1.多态概念
  • 某一些事物存在的多种表现的形态。
  • 例如,人分为男人、女人。动物分为猫、狗。
    • 猫 x = new 猫();
    • 动物  d = new 猫();
    • 发现d引用的实体即具有猫的特征也有动物的特征。
  • 例如,重载和覆盖就是函数中多态的体现:同一个事物、函数名,父类和子类都拥有,但是体现形态不同。
  • 父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,它是无可奈何的;    同时,父类中的一个方法只有在在父类中定义而在子类中没有重写的情况下,才可以被父类类型的引用调用;   对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法,这就是动态连接。 

         

    2.多态的表现形式
  • 父类的引用指向了自己的子类对象。
    • 猫 extends 动物;
    • 动物 d =new 猫();
  • 多态的步骤
      • 1、使用父类类型的引用指向子类的对象;      
      • 2、该引用只能调用父类中定义的方法和变量;      
      • 3、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)      
      • 4、变量不能被重写(覆盖)重写的概念只针对方法,如果在子类中重写了父类中的变量,那么在编译时会报错。  
    3.多态的前提
  • 必须是类与类之间有关系,要么继承,要么实现。
  • 子类必须覆盖父类。
    4.多态的优点
  • 好处是代码完成以后出现了动物的新子类时,不用修改代码,使用反射就可以。而不用重新写子类,然后再继承父类等。
  • 提高了程序的扩展性。
  • 使用父类的引用可以访问父类中存在的成员。
    5.多态的缺点
  • 只能使用父类的引用,访问父类中的成员,子类特有的成员不允许访问。
    6.多态的实现过程
  • class Cat extends Animal{}//1.继承,Cat 继承 Animal。
  • Animal a = new Cat();//2.类型提升,Cat提升(向上转型)为Animal。
  • Cat c = (Cat) a ;3.如果想要调用猫的特有方法时,强制将父类的应用转为子类类型(向下转型)。
  • c.catchMouse;4.c调用a强制转型后的c的方法,是可以的。
    7.多态的应用:
  • 将对象调用简单化,以前是指挥对象一件一件做事情,现在是指挥一批对象做一批事情,前提是把多个对象的共性抽取出来统一操作。
    • 先建立工具类,里面包括操作扩展类的方法,接受的是扩展类的对象,类型是扩展类的父类类型
    • 主函数调用工具类错作扩展类对象的一批方法。
    • 扩展类可以后来添加,提高了扩展性。扩展类对象作为参数传给工具类就可以了。
  • 总结:
    • .首先定义一个工具类,里面存放的是扩展类的各种共性方法,参数是扩展类对象 ,类型是扩展类的父类类型。父类引用指向子类对象使得新增加的子类对象也可以当作参数传递给工具类,提高了扩展性。
    •  然后定义主函数,主函数把扩展类对象作为参数传给 工具类的相关方法 ,这样后来新增加类也不需要更改工具类代码,只需要在主函数添加上少量代码,在扩展类中增加上新增加的类代码就可以。
    • 主函数只需要找工具类就可以,对类型进行抽取,导致了多台的产生,使用多态操作同一个大类型,多大类型的多个小类型都能进行操作。这样才提高了扩展性。
    8.多态中成员的特点
  • 成员函数(非静态)
    • 编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
    • 运行时期:参阅所属的类中是否有调阅的方法。
    • 总结:成员函数在多态调用时,编译看左边,执行看右边。 局部没有看成员,成员没有看父类。 类似于子类访问父类,子类没有看父类。子类非静态函数会覆盖父类的非静态函数。
  • 成员函数(静态)
    • 无论编译还是运行都参考左边的引用变量所属的类
    • 子类非静态函数会覆盖父类的非静态函数。
    • 总结:静态函数是不需要对象的,只要父类引用还在,找的就是父类引用所属的类中的静态方法。
  • 成员变量、 成员变量(静态)
    • 父类指向子类对象和子类指向子类对象,无论编译还是运行,都参考左边 (引用型变量所属的类)。当父类与子类出现同名变量的时候,都只看左边的引用变量所属的类。
    9.注意:
  • 1,千万不要出现父类对象转为子类类型。
  • 2,我们能转换的是父类引用指向子类对象时,该引用可以提升为父类,也可以被强制转换为子类。
  • 3,多态自始至终都是子类对象在发生着变化。
  • 4,可以使用 "对象引用  instanceof  类"这种格式来判断该对象是那种类型。

    10.面试题成员变量
  • 成员变量
    • 无论编译还是运行,都参考左边(引用型变量所属的类)。
      • 例如父类成员变量x=5,子类成员变量x=8,
      • fu f = new zi();
      • sop(f.x); //结果是5
      • zi z = new zi( );
      • sop(zi.x); 结果是8
   11.多态的主板示例
  • 需求:模拟一个主板上加载扩展卡的例子,需要添加网卡、声卡,以后需要添加显卡等。
    • 分析一:
      • 程序一运行,主板就运行:添加一个主板类,实现主板自己的run方法。
      • 现在需要上网功能:添加一个网卡类,实现open、close方法。主板再添加一个useNetCard功能调用网卡的open、close功能。
      • 这样的主板类遇到一个扩展性问题:
        • 1:与网卡类耦合性太高,相当于在主板上留了一个网卡类专用插口。
        • 2:不利于扩展,新添加板卡类需要修改主板类。
    • 分析二
      • 为了解决主板类和板卡类的扩展性,考虑使用多态的思想解决这个问题。
        • 板卡类实现一种通用规则( PCI接口 ),主板预留这种规则的插口,也就是接收实现规则的子类,主板类使用这种接口(中间接口、中间类?)间接操作板卡类,这是一种多态思想的体现。
      • 添加一个PCI接口,所有的板卡类都实现这个接口。
        • interface PCI{public void open();public void close();}
      • 主板添加一个方法,接受实现PCI接口的板卡类(PCI的子类)。
        • public void usePCI(PCI p){p.open();p.close();}//接口型引用指向自己的子类对象。多态。
      • 主函数中实现过程:建立主板对象,主板运行,主板添加板卡类。
    12.多态的扩展示例
  • 需求:数据库的操作。:
    • 1.连接数据库。JDBC、Hibernate
    • 2.操作数据库。(CRUD)
    • 3.关闭数据库连接。
  • 分析一:
    • 对JDBC的数据库的操作:连接、操作(CRUD)、关闭。
    • 当需要改为效率高的新数据库时,如Hibernate,这时原来代码的扩展性差问题出现,需要修改的代码太多,牵一发动全身。
  • 分析二:
    • 解决耦合性高、扩展性差,就需要使用多态的思想(解决这个问题的万金油吗?!)...
    • 在主程序和两种数据库操作直接添加一个规则(中间接口),数据库只要照着这个规则实现,主函数就能使用数据库。
      • 添加一个接口:UserInfoDao,里面包含CRUD方法。
        • interface  UserInfoDao
        • {
          • public void add(User user);
          • public void delete(User user);
        • }
      • 数据库类只要实现 UserInfoDao 接口,就可以被主函数使用。
        • class UserinfoByJDBC implement  UserInfoDao
        • {
          • CRUD
        • }
        • class UserinfoByHibernate implement  UserInfoDao
        • {
          • CRUD
        • }
      • 主函数里面调用实现了中间接口的数据库对象。
        • UserInfoDao ui = new  UserInfoByHibernate
        • ui.add(user);//user是操作的数据
        • ui.delete(user);
  • 多态会添加少量代码,不会大批量修改代码,如果想一点也不懂源代码,可以使用反射。
    13.学习多态的总结:
  • 多态的思想体现在使用类操作某些未来可能需要扩展的功能类对象中,也可以说是使用者和多个(未来可能有多个)被使用者之间。当增加一个被使用者,使用者的内部代码会为操作新对象改变,使用者和被使用者的耦合性太强。为了不修改使用者的代码,减少出错和提高效率,我们在使用者和被使用者之间添加一个中间接口(或中间类),只要被使用者实现这个中间接口,接可以被使用者使用。