从字节码层面分析Lambda

invokedynamic 指令

动态类型语言和静态类型语言的区别:
● 它俩的区别在于对类型的检查是在编译器还是在运行期,满足前者就是静态类型语言,反之是动态类型语言。
● 静态类型语言是判断变量自身的类型信息;动态类型语言是判断变量值的类型信息,变量没有类型信息,变量值才有类型信息,这是动态语言的一个重要特征。

invokedynamic 指令的出现:
● Java7 增加了一个 invokedynamic 指令,这是 Java 为了实现【动态类型语言】支持而做的一种改进,实际上Java是一种静态类型语言。
● 但是在 Java7 中并没有提供直接生成 invokedynamic 指令的方法,需要借助 ASM 这种底层字节码工具来产生 invokedynamic 指令。直到 Java8 的Lambda表达式的出现,invokedynamic 指令的生成, 在Java中才有了直接的生成方式。
● Lambda 表达式的底层实现使用 invokedynamic 指令,通过动态生成一个方法并绑定到函数式接口的实例来实现。调用函数式接口的抽象方法实际上会调用这个动态生成的方法。
测试代码:

public class InvokeDynamicTest {
    
    


    public static void main(String[] args) {
    
    
        FunctionTest test = x -> {
    
    
            System.out.println(x);
            return false;
        };
        boolean common = test.common(2);
        System.out.println("common->" + common);
    }

}

@FunctionalInterface
interface FunctionTest {
    
    

    boolean common(Integer x);

}

结果指令如下:
从这字节码解析后的数据可以看出呢,我们写的Lambda表达式最后成了一个局部方法,有自己的寄存器、局部变量表、操作数栈这也是为什么我们平时在方法中使用Lambda时访问不了方法定义的变量的原因,原因就是定义的变量在其本身的局部变量表里,而不是在我们写的Lambda的局部变量表里,每个栈帧之间是独立的,所以访问不了

回到 invokedynamic 指令,其实就是将我们写的Lambda方法和具体的接口方法进行动态绑定在一起,当调用接口中那个虚方法的时候,那么就会调用我们的Lambda方法,这也是 invokedynamic 指令的作用。

猜你喜欢

转载自blog.csdn.net/qq_63691275/article/details/134080635
今日推荐