虚拟机字节码执行引擎随记(三)动态类型语言支持

什么是动态类型语言?

  类型检查的主体过程是在运行期的语言就是动态类型语言。如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拥有动态类型语言的特性,在运行时才确定方法所在的具体类型。

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