Java动态绑定机制

更新时间:2021-07-14 14:12:40点击次数:271次
一、简单回顾下Java多态:
方法的多态:重载和重写
对象的多态:编译看左,运行看右
例:Animal animal = new Dog();
编译类型:Animal
运行类型:Dog
向上转型:父类引用指向子类对象
父类类型 引用名 = new 子类类型()
可以调用父类成员,需遵守访问权限(无法直接访问父类中private修饰成员)
向上转型后,不能调用子类特有成员,因为编译类型是父类,调用子类特有成员无法通过编译
向下转型:调用子类特有的成员
子类类型 引用名 = (子类类型) 父类引用
向下转型后,编译类型和运行类型都是子类,因此可以调用子类所有成员
父类引用必须指向的是当前目标类型的对象
// Cat Dog 分别继承 Animal
Animal animal = new Cat();  // 向上转型
Cat cat = (Cat) animal;     // 向下转型
Dog dog = (Dog) animal;     // 编译成功,但运行报错,类转换异常
二、动态绑定机制——简要版
当调用对象方法时,该方法会和该对象的内存地址/运行类型绑定
当调用对象成员变量时,没有动态绑定机制,哪里声明,那里使用
三、动态绑定机制——详解
1a. 父类、子类定义如下
class Father {
    public int num = 10;
    public int sum1() {
        return getNum() + 10;
    }
    public int sum2() {
        return num + 10;
    }
    public int getNum() {
        return num;
    }
}
class Son extends Father {
    public int num = 20;

    public int sum1() {
        return num + 20;
    }
    public int sum2() {
        return num + 10;
    }
    public int getNum() {
        return num;
    }
}
1b. main方法
public static void main(String[] args) {
    Father father = new Son();
    System.out.println(father.sum1());  // 40
    System.out.println(father.sum2());  // 30
}
1c. 最终输出40, 30。解析如下:
对象father,编译类型Father,运行类型Son
father.sum1():调用子类Son的sum1()方法,返回Son中成员变量num+20。此时,在调用Son的成员变量num时,没有动态绑定机制,哪里声明就那里使用,Son中声明了num=20,所以最终返回 20 + 20 = 40。
father.sum2():调用子类Son的sum2()方法,返回Son中成员变量num+10。完全同上,返回 20 + 10 = 30。
2a. 父类不变
class Father {
    public int num = 10;
  public int sum1() {
        return getNum() + 10;
    }
    public int sum2() {
        return num + 10;
    }
    public int getNum() {
        return num;
    }
}
2b. 子类修改,取消sum1()方法
class Son extends Father {
    public int num = 20;
//    public int sum1() {
//        return num + 20;
//    }
   public int sum2() {
        return num + 10;
    }
    public int getNum() {
        return num;
    }
}
2c. main方法
public static void main(String[] args) {
    Father father = new Son();
    System.out.println(father.sum1());  // 30
}
2d. 最终输出30。解析如下:对象father,编译类型Father,运行类型Son
father.sum1():①试图调用子类Son的sum1()方法,但已被注释掉,不存在sum1()方法。②借助继承机制,试图调用父类Father的sum1()方法,顺利调用,开始执行。③return语句中的方法名为getNum(),子类与父类同时存在。④调用对象方法时,存在动态绑定机制,该方法和该对象的运行类型绑定,因此优先调用运行类型Son的getNum()方法。⑤执行子类Son的getNum(),试图得到成员变量num,这里成员变量num没有动态绑定机制,哪里声明,那里使用,Son类中num=20。⑥执行子类Son的getNum()方法得到20,所以执行父类Father的sum1()方法得到20+10=30。
3a. 父类依旧不变
class Father {
    public int num = 10;
    public int sum1() {
        return getNum() + 10;
    }
    public int sum2() {
        return num + 10;
    }
    public int getNum() {
        return num;
    }
}
3b. 子类修改,取消sum1()和sum2()方法
class Son extends Father {
    public int num = 20;
//    public int sum1() {
//        return num + 20;
//    }
//    public int sum2() {
//        return num + 10;
//    }
    public int getNum() {
        return num;
    }
}
3c. main方法
public static void main(String[] args) {
    Father father = new Son();
    System.out.println(father.sum2());  // 20
}
3d. 最终输出20。解析如下:
对象father,编译类型Father,运行类型Son
father.sum2():①试图调用子类Son的sum2()方法,但已被注释掉,不存在sum2()方法。②借助继承机制,试图调用父类Father的sum2()方法,顺利调用,开始执行。③return语句中试图得到成员变量num,这里成员变量num没有动态绑定机制,哪里声明,那里使用,Father类中num=10。⑥执行完父类Father的sum2()方法得到10+10=20。

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

  • 项目经理 点击这里给我发消息
  • 项目经理 点击这里给我发消息
  • 项目经理 点击这里给我发消息
  • 项目经理 点击这里给我发消息