一、绑定
一个方法与类/对象联系起来。
二、静态绑定
如果是private、static、final方法,编译器可以准确的指导应该调用哪些方法,因为子类是不能重写这些方法的,这种调用方法称为静态绑定(static binding)。
三、动态绑定
调用的方法依赖于隐式参数的实际类型,并且在运行时实现动态绑定。
四、动态绑定过程
虚拟机先在该对象的类中寻找是否有该方法,如果有直接调用,如果没有则在超类中寻找。但如果每次调用方法都要进行搜索,时间开销会相当大。因此虚拟机为每个类预先创建了一个方法表,其中列出了所有方法的签名和实际调用的方法。
Employee.java
1 package test; 2 import java.time.*; 3 public class Employee { 4 private String name; 5 private double salary; 6 private LocalDate hireDay; 7 8 public Employee(String name, double salary, int year, int month, int day){ 9 this.name = name; 10 this.salary = salary; 11 this.hireDay = LocalDate.of(year,month,day); 12 } 13 14 public Employee(){ 15 16 } 17 public String getName() { 18 return name; 19 } 20 21 public double getSalary() { 22 return salary; 23 } 24 25 public LocalDate getHireDay() { 26 return hireDay; 27 } 28 29 public void raiseSalary(double byPercent) { 30 double raise = salary * byPercent / 100; 31 salary += raise; 32 } 33 34 35 36 }
Manager.java:
1 package test; 2 3 public class Manager extends Employee { 4 private double bonus; 5 public Manager(String name,double salary, int year, int month, int day){ 6 super(name,salary,year,month,day); 7 bonus = 0; 8 } 9 10 public Manager(){ 11 } 12 13 @Override 14 public double getSalary() { 15 double baseSalary = super.getSalary(); 16 return baseSalary +bonus; 17 } 18 19 public void setBonus(double b){ 20 bonus = b; 21 } 22 }
main.java
1 package test; 2 3 public class Main { 4 public static void main(String[] args) { 5 Manager boss = new Manager("Carl",8000,1987,12,15); 6 boss.setBonus(5000); 7 Employee[] staff = new Employee[3]; 8 9 staff[0] = boss; 10 staff[1] = new Employee("Harry", 5000, 1989, 10, 1); 11 staff[2] = new Employee("Harry", 4000, 1990, 3, 15); 12 13 for(Employee e : staff) 14 System.out.println("name="+e.getName()+",salary="+e.getSalary()); 15 } 16 17 18 }
在main.java第14行调用e.getSalary()的过程:
- 由于getSalary不是private、static或final方法,所以将采用动态绑定。
- 虚拟机预先为Employee何Manager两个类生成方法表。
Employee:
getName() -> Employee.getName()
getSalary() -> Employee.getSalary()
getHireDay() -> Employee.getHireDay()
raiseSalary(double) -> Employee.raiseSalary(double)
Manager:
getName() -> Employee.getName() (Manager没有,从父类继承)
getSalary() -> Manager.getSalary() (重写了)
getHireDay() -> Employee.getHireDay()
raiseSalary(double) -> Employee.raiseSalary(double)
setBonus(double) -> Manager.setBonus(double) (Manager的方法)
注意:这里的方法表省略了Object类的方法,所有的类都继承自Object类 - 首先虚拟机提取e的实际类型的方法表。既可能是Employee、Manager的方法表,也可能是Employee类的其他子类的方法表(本例中staff[0]是Manager,staff[1]、staff[2]是Employee)。
- 接下来,虚拟机搜索定义getSalary签名的类。调用该方法。