Java 多態的底層實現


參考:

多態的底層實現

Java是用過方法表來實現的,C++是通過虛表來實現的。
Java 對於方法調用動態綁定的實現主要依賴於方法表,但通過類引用調用和接口引用調用的實現則有所不同。總體而言,當某個方法被調用時,JVM 首先要查找相應的常量池,得到方法的符號引用,並查找調用類的方法表以確定該方法的直接引用,最后才真正調用該方法。
在類被加載到內存后,實際上以class字節碼文件的形式存在於JVM的方法區(現在叫元空間)中,class字節碼文件包含了該類的所有類型信息並且對外提供了訪問該類的接口。

Java 的方法調用方式

Java 的方法調用有兩類,動態方法調用與靜態方法調用。靜態方法調用是指對於類的靜態方法的調用方式,是靜態綁定的;而動態方法調用需要有方法調用所作用的對象,是動態綁定的。類調用 (invokestatic) 是在編譯時刻就已經確定好具體調用方法的情況,而實例調用 (invokevirtual) 則是在調用的時候才確定具體的調用方法,這就是動態綁定,也是多態要解決的核心問題。

JVM 的方法調用指令有四個,分別是 invokestatic,invokespecial,invokesvirtual 和 invokeinterface。前兩個是靜態綁定,后兩個是動態綁定的。本文也可以說是對於 JVM 后兩種調用實現的考察。

實現原理

類調用方法使用的是invokesvirtual 指令。

父類和子類相同的方法的符號引用在各自方法表中偏移量是一樣的,比如父類的toString()方法的符號引用在父類的方法表中的偏移量是10,那子類的toString()方法的符號引號在子類方法表中的偏移量也是10,那么調用方法時,JVM根據方法簽名在字符串常量池中確定符號引用,然后先找對象的符號引用類型(也就是父類類型)方法表中該符號引用的偏移量,然后執行對象的實際類型的(也就是子類類型)方法表中相同偏移量的方法。

類調用方法使用的是invokeinterface指令。

但是接口和類的是實現有點不一樣,因為類是單繼承,所以可以讓子類和父類保持相同的方法的符號引用在各自方法表中的偏移量一樣,但是因為接口是多實現,可以同時實現多個接口,所以不能保證相同的方法的符號引用在各自方法表中的偏移量一樣,所以在查找到接口的符號引用的偏移量之后,需要根據根據得到的符號引用去子類的方法表中查詢,找到等價的符號引用,然后執行子類的方法。因為多一個查找的步驟,所以接口的多態調用一般比類的多態調用慢一些。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM