invokedynamic指令
在前面java動態(tài)類型語言支持(一)(二)中我們有提到invokedynamic指令和java.lang.invoke包中的MethodHandle機制,在某種程度上他們的作用是一樣的,都是為了解決原有4條invoke*指令方法分派規(guī)則固話在虛擬機之中的問題,把如何查找目標(biāo)方法的決定權(quán)從虛擬機轉(zhuǎn)嫁到具體用戶代碼中,讓yoghurt有更高的自由度。
每一處含有invokedynamic指令的位置都稱作“動態(tài)調(diào)用點”,這條指令的第一個參數(shù)不再是代表方法符號引用的CONSTANT_Method_info常量,而是變?yōu)镴DK新加入的CONSTANT_InvokeDynamic_info常量,從這個新常量中可以得到三項信息:引導(dǎo)方法(Bootstrap Method,此方法存放在新增的BootstrapMethods屬性中)、方法類型(MethodType)和名稱。引導(dǎo)方法是固有的參數(shù),并且返回值是java.lang.invoke.Callsite對象,這個代表真正要執(zhí)行的目標(biāo)方法調(diào)用。根據(jù)CONSTANT_InvokeDynamic_info常量中提供的信息,虛擬機可以找到并執(zhí)行應(yīng)到方法,從而獲得一個Callsite對象,最終調(diào)用要執(zhí)行的目標(biāo)方法。
掌控方法分派規(guī)則
invokedynamic指令與前面4條“invoke*”指令最大差別就是他的分派邏輯不是由虛擬機決定的,而是與程序員決定的。我們看如下代碼:

我們思考在TODO處填入適當(dāng)代碼(不能修改其他地方的代碼)實現(xiàn)調(diào)用祖父類的thinking方法。。
在java中我們可以通過super關(guān)鍵字很方便的調(diào)用到父類中的方法,如果要訪問祖父類的方法在JDK1.7以前我們使用純粹的java語言很難實現(xiàn)這個問題,原因在于Son類的thinking()方法中無法獲取一個實際類型是GrandFather的對象引用,而invokevirtual指令的分派邏輯就是按照方法接收者的實際類型進行分派,這個邏輯是固化在虛擬機中的,程序員無法改變。在JDK1.7以后我們可以使用如下方式解決這個問題,代碼如下:
