Java多態的實現原理

參考博客:

【解惑】Java動態綁定機制的內幕http://blog.csdn.net/zero_295813128/article/details/52117737

Java 虛擬機體系結構:http://hxraid.iteye.com/blog/676235

--------------------------------------------------------------------------------------------------

下面是自己的理解總結:

    首先得對兩個概念有理解方法區和常量池。這兩個都是Java虛擬在運行時的數據區域,常量池是方法區

的一部分。

方法區

    方法區與Java堆一樣,是各個線程共享的內存區域,用於存儲已經被虛擬機加載的類信息、常量、靜態變

量、即使編譯器編譯後的代碼等數據。

常量池

    常量池是方法區的一部分,用於存放編譯期所生成的各種字面量和符號引用。常量池中共有11個常量表。

    常量表類型 標誌值(佔1 byte) 描述

    CONSTANT_Utf8     1 UTF-8編碼的Unicode字符串

    CONSTANT_Integer 3 int類型的字面值

    CONSTANT_Float     4 float類型的字面值

    CONSTANT_Long     5 long類型的字面值

    CONSTANT_Double     6 double類型的字面值

    CONSTANT_Class     7 對一個類或接口的符號引用

    CONSTANT_String     8 String類型字面值的引用

    CONSTANT_Fieldref 9 對一個字段的符號引用

    CONSTANT_Methodref 10 對一個類中方法的符號引用

  CONSTANT_InterfaceMethodref 11 對一個接口中方法的符號引用

    CONSTANT_NameAndType 12 對一個字段或方法的部分符號引用

---------------------------------------------------------------------------------------------------

對於多態的原理主要研究方法區。在Java中多態指的是它允許基類的指針或引用指向派生類的對象,而在具體訪

問時實現方法的動態綁定。java中的方法調用有靜態綁定和動態綁定之分,靜態綁定指的是我們在編譯期就已經

確定了會執行那個方法的字節碼,而動態綁定只有在運行時才能知曉。

靜態綁定

    Java中的靜態方法、私有方法以及final修飾的方法的調用,都屬於靜態綁定,對於重載的實例方法的

調用,也是採用靜態綁定。靜態綁定的原理主要是一個常量池解析的過程,下面來詳解其過程:

    假如有兩個類A、B,在A類中我們調用了B類中的一個靜態方法,在編譯期,這個調用的動作會被編譯成一

條靜態調用指令,該指令就對應常量池中的CONSTANT_Methodref表中所存儲的該方法的符號引用,通過這個符號引用

可以得到靜態方法的全類名B,JVM加載B類,便會得到B類中方法的直接地址,該地址會被存儲到A類常量池中對應的

常量表中,這便是常量池解析過程,再次發起調用時,就會直接根據這個直接地址調用對應方法。

    以上過程可以看出,在編譯階段我們就已經確定了應該執行哪一個字節碼代碼。

動態綁定

    動態綁定講解之前需要了解JVM管理的一個重要的數據結構--方法表。它以數組的形式記錄了當前類及其所有

超類的可見方法字節碼在內存中的直接地址 。

    動態綁定前面的流程與靜態綁定類似,假如此處有兩個類A,B繼承了A類,B類中重寫了A類中的f1()方法,我們採用

向上轉型的方式用指向B實例的A類型引用調用f1()方法,編譯器會生成一條字節碼指令,該指令會去常量表中找到f1()方法信

息的符號引用,通過該引用確定調用該方法的類型全名,即A類的全名稱,根據名稱加載到A類的字節碼,去A類所對應的方法

表中找到f1()方法,將它的直接地址記錄到調用f1()方法的類的對應的常量表中,常量池解析結束,可以思考,我們此時是否能

確定調用f1()方法時執行的是哪一塊的字節碼,答案是不能,因爲截至此時我們f1()方法指定執行的是父類中的方法,引用雖然

父類類型,但他指向的是父類對象還是子類對象是不知道的(確切地說是此時的程序不知道,程序員肯定是知道的),假如指向父類

那就是父類中的f1()方法,如果指向子類的實例,子類沒有重寫,依然執行父類f1()方法,如果子類重寫了就應該是子類的f1()

方法。此時動態綁定就登場了,確定f1()換需要拿到B類實例在堆中的引用,通過引用找到堆中B的對象,根據對象進一步獲取它的

方法表,找到方法表的f1()方法的直接地址,此時便最終確定了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章