天天看點

Java - 靜态綁定與動态綁定講解(向上轉型的運作機制詳解)一:綁定二:靜态綁定三:動态綁定四:區分

一:綁定

把一個方法與其所在的類/對象 關聯起來叫做方法的綁定。綁定分為靜态綁定(前期綁定)和動态綁定(後期綁定)。

二:靜态綁定

靜态綁定(前期綁定)是指:在程式運作前就已經知道方法是屬于那個類的,在編譯的時候就可以連接配接到類的中,定位到這個方法。

在Java中,final、private、static修飾的方法以及構造函數都是靜态綁定的,不需程式運作,不需具體的執行個體對象就可以知道這個方法的具體内容。

三:動态綁定

 動态綁定(後期綁定)是指:在程式運作過程中,根據具體的執行個體對象才能具體确定是哪個方法。

動态綁定是多态性得以實作的重要因素,它通過方法表來實作:每個類被加載到虛拟機時,在方法區儲存中繼資料,其中,包括一個叫做 方法表(method table)的東西,表中記錄了這個類定義的方法的指針,每個表項指向一個具體的方法代碼。如果這個類重寫了父類中的某個方法,則對應表項指向新的代碼實作處。從父類繼承來的方法位于子類定義的方法的前面。

動态綁定語句的編譯、運作原理:我們假設 Father ft=new Son();  ft.say();  Son繼承自Father,重寫了say()。

1:編譯:我們知道,向上轉型時,用父類引用執行子類對象,并可以用父類引用調用子類中重寫了的同名方法。但是不能調用子類中新增的方法,為什麼呢?

因為在代碼的編譯階段,編譯器通過 聲明對象的類型(即引用本身的類型) 在方法區中該類型的方法表中查找比對的方法(最佳比對法:參數類型最接近的被調用),如果有則編譯通過。(這裡是根據聲明的對象類型來查找的,是以此處是查找 Father類的方法表,而Father類方法表中是沒有子類新增的方法的,是以不能調用。)

編譯階段是確定方法的存在性,保證程式能順利、安全運作。

2:運作:我們又知道,ft.say()調用的是Son中的say(),這不就與上面說的,查找Father類的方法表的比對方法沖突了嗎?不,這裡就是動态綁定機制的真正展現。

上面編譯階段在 聲明對象類型 的方法表中查找方法,隻是為了安全地通過編譯(也為了檢驗方法是否是存在的)。而在實際運作這條語句時,在執行 Father ft=new Son(); 這一句時建立了一個Son執行個體對象,然後在 ft.say() 調用方法時,JVM會把剛才的son對象壓入操作數棧,用它來進行調用。而用執行個體對象進行方法調用的過程就是動态綁定:根據執行個體對象所屬的類型去查找它的方法表,找到比對的方法進行調用。我們知道,子類中如果重寫了父類的方法,則方法表中同名表項會指向子類的方法代碼;若無重寫,則按照父類中的方法表順序儲存在子類方法表中。故此:動态綁定根據對象的類型的方法表查找方法是一定會比對(因為編譯時在父類方法表中以及查找并比對成功了,說明方法是存在的。這也解釋了為何向上轉型時父類引用不能調用子類新增的方法:在父類方法表中必須先對這個方法的存在性進行檢驗,如果在運作時才檢驗就容易出危險——可能子類中也沒有這個方法)。

四:區分

程式在JVM運作過程中,會把類的類型資訊、static屬性和方法、final常量等中繼資料加載到方法區,這些在類被加載時就已經知道,不需對象的建立就能通路的,就是靜态綁定的内容;需要等對象建立出來,使用時根據堆中的執行個體對象的類型才進行取用的就是動态綁定的内容。