JAVA調用對象方法的執行過程:
①.編譯器查看對象的聲明類型和方法名。假設調用x.f(parameter), ?且隱式參數x聲明為C類型的對象,有可能在C對象中存在多個參數類型和參數個數不同的f的方法{例如:f(int)、f(int,String)和f(String)},編譯器會一一列舉C類中的f方法和C的超類中聲明為public所有的f方法。
至此,編譯器已經獲得所有可能被調用的候選方法。
②.接下來,編譯器將查看調用方法時所提供的參數類型和參數個數。如果所有名為f的方法中存在這樣一個與提供方法的參數類型和參數個數完全匹配的方法,就選擇這個方法,這個過程也稱重載解析。例如:對于調用f(“This is my java”)來說,編譯器會尋找f(String)這個方法。如果編譯器沒有找到與參數類型和參數個數匹配的方法,或者經過類型轉換后有多個方法于此匹配,就會報告一個錯誤。
至此,已經尋找到需要調用的方法和參數類型
③.如果是此方法是被private、static、final修飾或則是構造器,那么編譯器可以準確的知道應該調用哪個方法,于是便調用這個的方法。這種調用方式叫著靜態綁定。靜態綁定方式于此結束。
而與此對應是,調用方法依賴于隱式參數的實際類型,并且在運行時實現動態綁定,編譯器采用動態綁定的方式會生成一條調用f(String)的指令(其原因請查看下面的動態綁定解析)。
④.當程序運行,并且采用動態綁定調用方法時,虛擬機一定調用與x所引用的對象的實際類型最適合的那個方法。假設x的實際類型是D,D是C的子類,如果D類定了方法f(String),編譯器就直接調用它,否則就在D類的超類C中尋找f(String)方法,如果C類型中不存在這個方法,則又到尋找C的超類中尋找這個方法,以此類推。這個過程就稱為動態綁定。
動態綁定解析:
每次調用方法時都要進行搜索,這樣一來,時間開銷相當大。因此,虛擬機預先為每一個類創建了一個方法表,其中列舉出了類中的所有方法簽名和實際調用的方法。而在真正調用方法的時候,虛擬機僅僅查找這個表就行了。在前面的列子中,虛擬機搜索D類的方法表。以便尋找與調用f(String)相匹配的方法。這個方法既可能是D.f(String),也可能是C.f(String),還有可能是*.f(String),這里的*是指D的超類。
----參考于《Core Java》
下面我們就舉一個簡單的例子:
新建一個Father類,并且讓Son類繼承Father基類:
package com.bin.bind;
public class TestBind {
public static void main(String[] args) {
String name = "TOM";
String hobby = "~~~sleep~~~";
int age = 19;
Father father = new Son(name, hobby, age);
String result = father.getAllInfo();
System.out.println(result);
}
}
class Father {
public Father(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getAllInfo() {
return "姓名是:"+this.name+"\t年齡是:"+this.age;
}
private String name = null;
private int age = 0;
}
class Son extends Father {
public Son(String name, String hobby, int age) {
super(name, age);
setHobby(hobby);
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public String getAllInfo() {
return "姓名是:"+super.getName()+"\t年齡是:"+
super.getName()+"\t愛好是:"+hobby;
}
private String hobby = null;
}
在Father和Son類中都存在getAllInfo()這個方法,因為getAllInfo()不是static、final、private、構造方法,所以此方法將采用動態綁定。
在程序執行的時候虛擬機會為這個兩個類生成方法表
Father類:
Father(String,int)->Father(String,int)
setAge(int)->Father.setAge(int)
getAge()->Father.getAge()
setName(String)->Father.setName(String)
getName()->Father.getName()
getAllInfo()->Father.getAllInfo()
Son類:
Father(String,int)->Father(String,int)
setAge(int)->Father.setAge(int)
getAge()->Father.getAge()
setName(String)->Father.setName(String)
getName()->Father.getName()
getAllInfo()->Father.getAllInfo()
Son(String,String,age)->Son(String,String,age)
setHobby(String)->Son.setHobby(String)
getHobby()->Son.getHobby()
getAllInfo()->Son.getAllInfo()
注意:上面列舉的方法并不完整,因為他們還都默認繼承了一個Object超類。
下面分析這條語句:
String result = father.getAllInfo();
father.getAllInfo()的解析過程如下:
①:虛擬機提取father類的實際類型的方法表。既可能是Father類也可能是Son類。(因為這里father引用所指向的是Son類的實例對象,所以實際類型必定是Son)
②:接下來,虛擬機搜索定義getAllInfo簽名的類,此時,虛擬機已經知道調用哪個方法。(Son中只有一個getAllInfo方法,且與此匹配,所以被調用) ③:虛擬機執行調用方法。(最后將返回結果賦值給result)