一、綁定
一個方法與類/對象聯系起來。
二、靜態綁定
如果是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簽名的類。調用該方法。