參考博客:java
【解惑】Java動態綁定機制的內幕:http://blog.csdn.net/zero_295813128/article/details/52117737 程序員
--------------------------------------------------------------------------------------------------數組
下面是本身的理解總結:數據結構
首先得對兩個概念有理解方法區和常量池。這兩個都是Java虛擬在運行時的數據區域,常量池是方法區ide
的一部分。編碼
方法區spa
方法區與Java堆同樣,是各個線程共享的內存區域,用於存儲已經被虛擬機加載的類信息、常量、靜態變
.net
量、即便編譯器編譯後的代碼等數據。線程
常量池指針
常量池是方法區的一部分,用於存放編譯期所生成的各類字面量和符號引用。常量池中共有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()方法的直接地址,此時便最終肯定了。