虛擬機字節碼執行引擎隨記(三)動態類型語言支持

什麼是動態類型語言?

  類型檢查的主體過程是在運行期的語言就是動態類型語言。如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擁有動態類型語言的特性,在運行時才確定方法所在的具體類型。

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