jvm 字節碼執行 (二)動態類型語言支持
動態類型語言
動態類型語言的關鍵特征是它的類型檢查的主體過程是在運行期而不是編譯期。
舉例子解釋“類型檢查”,例如代碼:
obj.println("hello world");
假如這行代碼是在Java語言中,並且變量obj的靜態類型為java.io.PrintStream,那麽變量obj的實際類型就必須是PrintStream的子類才是合法。否則,obj屬於一個確實
有println(String)方法,單與PrintStream接口沒有繼承關系,代碼依然不可能運行——因為類型檢查不合法。是相同的代碼在ECMAScript中情況不一樣,無論obj是何種類型
只要這種類型的定義中確實包含有println(String)方法,那方法調用便可成功。
這種差別產生的原因是Java語言在編譯期已將println(String)方法完整的符號引用生成出來,作為方法調用指令參數存儲到Class文件中,例如下面這段代碼:
invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
這個符號引用包含了此方法定義在哪個具體類型之中、方法的名字以及參數順序、參數類型和方法返回值等信息,通過這個符號引用,虛擬機可以翻譯出這個方法的
直接引用。而在ECMAScript等動態類型語言中,變量obj本身是沒有類型的,變量obj的值才是具有類型,編譯時最多只能確定方法名稱、參數、返回值這些信息,而不會
去確認方法所在的具體類型。“變量無類型而變量值才有類型”這個特點也是動態類型語言的一個重要特征。
靜態類型語言在編譯期確定類型,最顯著的好處是編譯期可以提供嚴謹的類型檢查,這樣與類型相關的問題能在編碼的時候就及時發現,利於穩定性及代碼達到最大規模。
而動態類型語言在運行期確定類型,這可以為開發人員提供更大的靈活性,某些在靜態類型語言中需要大量“臃腫”代碼來實現的功能,由動態類型語言來實現可能會更加清晰
簡潔,清晰和簡潔通常也意味著開發效率的提升。
java.lang.invoke包
JDK1.7以前的字節碼命令指令集中,4條方法調用指令(invokevirtual、invokespecial、invokestatic、invokeinterface)的第一個參數都是被調用的方法的符號引用,而
方法的符號引用在編譯時產生,而動態類型語言只有在運行期。這樣在Java虛擬機上實現的動態語言類型語言就不得不使用其他方式來實現。
java.lang.invoke包的主要目的是在之前單純依靠符號引用來確定調用的目標方法這種方式以外,提供一種新的動態確定目標方法的機制,稱為MethodHandle。
在擁有了Method Handle之後,Java語言也可以擁有類似函數指針或者委托的方法別名的工具了。
jvm 字節碼執行 (二)動態類型語言支持