什麼是動態類型語言?
類型檢查的主體過程是在運行期的語言就是動態類型語言。如JavaScript。
相對的,類型檢查的主體過程在編譯期的語言是靜態類型語言。如Java。
從定義中可以看出決定一個語言是不是動態語言有關鍵兩點:
1、類型檢查;
2、進行類型檢查的時期,在運行期的是動態類型語言,反之在編譯期檢查的是靜態類型語言。
爲了更形象的理解這個概念,我們不妨來看下面這段代碼:
abstract class Animal{
public abstract void run();
}
class Dog extends Animal{
@Override
public void run() {
System.out.println("Dog run.");
}
}
class Man{
public void run(){
System.out.println("Man run.");
}
}
public void executeRun(Animal animal){
animal.run();
}
相信基本所有讀者都能看出這段代碼只會執行Animal子類的run()方法,絕不會執行到Man類的run()方法。
造成這個現象的原因就是編譯期的類型檢查,Java在編譯期間就把run()方法的完整符號引用生成了出來,作爲方法的調用指令存儲到class文件中,生成的符號引用就包含了方法定義在哪個具體類型中,因此,在運行時,就只能執行該種類型的run()方法(動態類型語言可以在運行時執行任意一個類型的run()方法)。
Java在1.7中,在之前的單純依靠符號引用來確定調用的目標方法之外,提供了一種新的動態確定目標方法的機制,稱爲MethodHandle。來看下面這一段代碼:
static class PrintlnA {
public void println(String s) {
System.out.println("A print:" + s);
}
}
static class PrintlnB {
public void println(String s) {
System.out.println("B print:" + s);
}
}
public static MethodHandle findMethodHandle(Class clazz) throws
NoSuchMethodException, IllegalAccessException, InstantiationException {
MethodType methodType = MethodType.methodType(void.class, String.class);
return MethodHandles.lookup().findVirtual(clazz, "println",
methodType).bindTo(clazz.newInstance());
}
public static void main(String[] args) throws Throwable {
Class clazz = System.currentTimeMillis() % 2 == 0 ? PrintlnA.class :
PrintlnB.class;
findMethodHandle(clazz).invokeExact("afdsafdsafafads");
}
通過MethodHandle就可以讓Java擁有動態類型語言的特性,在運行時才確定方法所在的具體類型。