前提:动态绑定和多态是息息相关的,动态的意思是在运行期间决定调用哪个函数,同时也可以不用重新编译就能够感知程序的变化
先说一下静态绑定吧
一些用static,final,private修饰的方式,在调用的时候就是使用的静态绑定方法,比如private修饰的方法,我们调用一个对象的私有方法,其实在逻辑上是肯定只有一个方法与之对应的(私有方法不能继承,没有任何的歧义),因此在编译的时候就可以确定运行哪一个方法。也可以想一下重载也是一样,没有继承关系的重载也是静态绑定。
接下来是动态绑定
先看一个例子,有一个Employee类,继承出Manager类。
public class Employee {
private double salary;
Employee(double salary){
this.salary=salary;
}
public double getSalary(){
return this.salary;
}
public static void main(String[] args) {
Employee e=new Manager(10000,10000);
e.getSalary();
}
}
class Manager extends Employee{
private double bonus;
Manager(double salary,double bonus){
super(salary);
this.bonus=bonus;
}
public double getSalary(){
double baseSalary=super.getSalary();
return baseSalary+this.bonus;
}
public void setBonus(double bonus){
this.bonus=bonus;
}
public double getBonus(){
return this.bonus;
}
}
这段代码就体现出了面向对象语言的多态性质,main函数里的Employee e变量可以指向任何它的子类(比如Manager类的对象,或者任何它的子类,代码中没有体现),此时如果调用了重写父类的方法,那么光靠编译器就不能知道调用哪一个子类的方法(是经理(Manager)的方法还是秘书(代码没体现)的方法),这时就需要在运行的时候通过虚拟机,判断当前的引用(即变量e)指向的对象的具体类型,在调用对应的方法(即动态绑定)。
同时,动态绑定还有一个好处,那就是如果最开始程序只有两个子类:经理和秘书,然后后来程序变动,新增程序员子类,那么不需要改变e.getSalary()这里,也不需要重新编译,就能感知到程序的变化(需要做的就是虚拟机发现没有加载这个类,将类的字节码文件加载到虚拟机即可)