java方法呼叫流程
1.編譯器檢視物件的型別和方法名
例如,我們有一個類:
public class Father {
public void fun1(int a)
{
System.out.println("這是Father的fun1(int a)方法");
}
public void fun1(float a)
{
System.out.println("這是Father的fun1(float a)方法");
}
}
public class Son extends Father{
public void fun1(int a)
{
System.out.println ("這是Son的fun1(int a)方法");
}
public void fun1(float a)
{
System.out.println("這是Son的fun1(float a)方法");
}
public void fun1(String a)
{
System.out.println("這是Son的fun1(String a)方法");
}
}
現在我們例項化Son類,
Son son = new Son();
然後呼叫son物件的fun1方法,編譯器會一一列舉所有Son類中方法名為fun1的不同引數的方法,同時列舉這個物件的父類中是public的fun1方法(父類中的私有方法不可訪問)
至此,編譯器已經獲得所有可能被呼叫的候選方法
2.編譯器檢視呼叫方法時的引數型別
假設我們現在呼叫son物件的fun1(int a)方法
son.fun1(10);
那麼,當到了這一步的時候,編譯器就會去剛才的方法表中找到引數是一個並且引數型別為int的fun1方法。這個過程被稱作“過載解析”。由於允許型別轉換(例如int可以轉換為double,float),因此這個過程可能會變得比較複雜。如果編譯器沒有找到與引數型別匹配的方法,或者發現經過型別轉換後有多個方法與之匹配,就會報錯。
3.靜態繫結和動態繫結
如果方法是private,final或者static修飾的,那麼這種方法的呼叫方式被稱為靜態繫結
private:私有方法不能被子類繼承,則不能通過子類物件呼叫,而只能通過類例項化完成的物件進行呼叫,所以可以說private方法和方法所屬的類繫結;
final:final方法雖然可以被繼承,但是不能被重寫(覆蓋),雖然子類物件可以呼叫,但是呼叫的都是父類中的final方法(因此可以看出當類中的方法宣告為final的時候,一是為了防止方法被覆蓋,二是為了有效關閉java的動態繫結);
static:static方法可以被子類繼承,但是不能被子類重寫(覆蓋),但是可以被子類隱藏。(這裡意思是說如果父類裡有一個static方法,它的子類裡如果沒有對應的方法,那麼當子類物件呼叫這個方法時就會使用父類中的方法。而如果子類中定義了相同的方法,則會呼叫子類的中定義的方法。唯一的不同就是,當子類物件上轉型為父類物件時,不論子類中有沒有定義這個靜態方法,該物件都會使用父類中的靜態方法。因此這裡說靜態方法可以被隱藏而不能被覆蓋。這與子類隱藏父類中的成員變數是一樣的。隱藏和覆蓋的區別在於,子類物件轉換成父類物件後,能夠訪問父類被隱藏的變數和方法,而不能訪問父類被覆蓋的方法)。
除了這幾種靜態繫結以外,剩下的都為動態繫結。
當程式採用動態繫結呼叫方法時,虛擬機器一定會呼叫與所引用物件實際型別最合適的那個類的方法
例如,用Son類繼承了Father類,然後呼叫fun1(String a)方法,那麼會先在Son類中尋找是否有這個方法,如果有,直接呼叫,如果沒有,就去Son類的父類Father類中去尋找,發現存在,則呼叫父類中的fun1(String a)方法。
public class Father {
public void fun1(int a)
{
System.out.println("這是Father的fun1(int a)方法");
}
public void fun1(float a)
{
System.out.println("這是Father的fun1(float a)方法");
}
public void fun1(String a)
{
System.out.println("這是Son的fun1(String a)方法");
}
}
public class Son extends Father{
public void fun1(int a)
{
System.out.println("這是Son的fun1(int a)方法");
}
public void fun1(float a)
{
System.out.println("這是Son的fun1(float a)方法");
}
}
4.方法表
每次呼叫方法的時候都要進行搜尋,時間開銷非常的大,因此,虛擬機器預先為每個類建立了方法表,其中列出了所有方法的名字、引數型別還有實際呼叫的方法。然後,在真正呼叫的時候,虛擬機器只要查詢這個表就可以了。