类继承(多态+动态绑定)

打印 上一主题 下一主题

主题 805|帖子 805|积分 2415

类继承(多态+动态绑定)

韩顺平 Java P307-P318
继承

以Object类为基类(Base) 向下继承 使用关键字 extends
  1. class Father {}
  2. class Child extends Father {}
复制代码
子类继承父类所有可公开的属性、方法,规则属性、方法的修饰关键字
访问级别关键字同类同包子类不同包公开public√√√√受保护protected√√√×默认√√××私有private√×××属性、类的查询原则

在继承的逻辑下,访问属性、方法时,遵循查询原则
从当前类查找同名的属性、方法,如果找到,则访问、使用
md 流程图 flowchat 案例
http://flowchart.js.org/
  1. st=>start: Start
  2. e=>end
  3. init=>operation: 在当前(运行)类查找方法/属性
  4. findInRun=>condition: 当前类中找到了?
  5. findInFather=>condition: 当父类中找到了?
  6. isReadable=>condition: 可访问?
  7. isObject=>condition: 查找到Object?
  8. useIt=>operation: 访问/使用
  9. notUseIt=>operation: 不可访问/使用 抛异常
  10. findGrand=>operation: 继续向上级父类查找
  11. st->init->findInRun
  12. findInRun(yes)->useIt->e
  13. findInRun(no)->findInFather
  14. findInFather(yes, bottom)->isReadable
  15. findInFather(no,right)->findGrand(right)->isObject
  16. isObject(no,top)->findInFather
  17. isObject(yes,bottom)->notUseIt
  18. isReadable(yes,left)->useIt
  19. isReadable(no,bottom)->notUseIt(left)->e
复制代码

多态

编译类型为父类,运行类型为子类
  1. Father father = new Child child();
  2. // = 为分隔符
  3. // 左侧为编译类型
  4. //                   右侧为运行类型
复制代码
向上转型


  • 本质: 父类的引用指向子类的对象
  • 语法 父类类型 引用名 = new 子类类型()
  • 特点:

    • 编译类型看左边,运行类型看右边
    • 可以调用父类中的所有成员(遵循访问权限)
    • 不能调用子类中的特有成员
    • 最终运行效果看子类的具体实现(理解为有重写的使用重写,没有则向上查找)

向下转型


  • 语法: 子类类型 引用名 = (子类类型) 父类引用
  • 只能转换引用,对象不发生改变
  • 父类的引用必须指向要转化的对象

    • 也即,向上转型中,左右类型互相调换,不可替换为继承树中间的类
    • 例如 Father obj = new Child()
    • 那么只能转为 Child obj_trans = (Child) obj

  • 向下转型后,可以调用子类类型中的所有成员
多态案例

类定义
  1. class Animal {
  2.     public void cry() {
  3.         System.out.println("Animal cry() 动物在叫....");
  4.     }
  5. }
  6. class Cat extends Animal {
  7.     public void cry() {
  8.         System.out.println("Cat cry() 小猫喵喵叫...");
  9.     }
  10.     public void eatMouse() {
  11.         System.out.println("Cat eatMouse() 小猫吃老鼠...");
  12.     }
  13. }
  14. class Dog extends Animal {}
复制代码
测试用例
  1.     public static void main(String[] args) {
  2.         /*animal 编译类型就是 Animal , 运行类型 Dog */
  3.         Animal animal = new Dog();
  4.         /*animal 运行类型是 Dog
  5.         遵循查询原则, 从Dog向上逐级查找 cry() 方法
  6.         Dog 中没有 cry() 则向上 找到 Animal.cry() */
  7.         animal.cry(); // Animal cry() 动物在叫....
  8.         animal = new Cat(); //animal 编译类型 Animal,运行类型就是 Cat
  9.         animal.cry(); // Cat cry() 小猫喵喵叫...
  10.         /* 在编译阶段(写代码时),能调用哪些成员,是由编译类型来决定的 */
  11.         animal.eatMouse(); // 报错,无法编译
  12.         /* 如果希望在多态中使用子类的方法,则向下转型 */
  13.         ((Cat)animal).eatMouse;// Cat eatMouse() 小猫吃老鼠...
  14.     }
复制代码
动态绑定

在使用多态时,将使用动态绑定原则,该原则与上文的查询原则不冲突

  • 当调用对象方法时,该方法会和该对象的内存地址/运行类型绑定
  • 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
总结:
默认使用向上转型 父类类型 引用名 = new 子类类型()

  • 对于方法

    • 遵循向上转型规则,不可使用子类的特有方法
    • 当使用父类子类都有的方法时,可以使用,按子类的重写去执行
    • 当子类无此方法时,沿继承树向上查找

  • 对于属性

    • 遵循向上转型规则,不可使用子类的特有属性(重名属性也不使用,但内存中存在)
    • 方法所在的类使用所在类的属性值,与编译类型无关

案例
  1. class A {
  2.     public int i = 10;
  3.     //动态绑定机制:
  4.     public int sum() {
  5.         return getI() + 10;//20(子类有getI 按重写处理) + 10
  6.     }
  7.     public int sum1() {
  8.         return i + 10;//10(获取的是当前类的i = 10) + 10
  9.     }
  10.     public int sum2() {
  11.         return -1;
  12.     }
  13.     public int getI() {
  14.         return i;
  15.     }
  16. }
  17. class B extends A {
  18.     public int i = 20;
  19.     public int sum2() {
  20.         return i + 1;
  21.     }
  22.     public int getI() {
  23.         return i; // 获取的是当前类的 i = 20
  24.     }
  25. }
复制代码
umlPlant 类图画法 https://plantuml.com/zh/class-diagram
  1. @startuml
  2. Title "绑定案例"
  3. class A {
  4.     + int i = 10
  5.     + int sum()
  6.     + int sum1()
  7.     + int sum2()
  8.     + int getT()
  9. }
  10. class B extends A {
  11.     + int i = 20
  12.     + int sum2()
  13.     + int getT()
  14. }
  15. @endumlenduml
复制代码

测试
  1.     public static void main(String[] args) {
  2.         A obj = new B();
  3.         // 方法
  4.         int res1 = obj.sum();  // 30
  5.         int res2 = obj.sum1(); // 20
  6.         int res3 = obj.sum2(); // 21 不是特有方法, 按重写处理
  7.         // 属性
  8.         int res4 = obj.i;      // 10 多态, 不访问子类的独有
  9.         int res5 = ((B)obj).i; // 20 想要访问子类的属性/独有方法, 向下转型
  10.     }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

天空闲话

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表