专栏原创出处:github-源笔记文件 (opens new window)github-源码 (opens new window),欢迎 Star,转载请附上原文出处链接和本声明。

Java JVM-虚拟机专栏系列笔记,系统性学习可访问个人复盘笔记-技术博客 Java JVM-虚拟机 (opens new window)

# 一、前言

对于 invokedynamic 指令的实现需要方法句柄作为前提知识点。可参考 Java JVM 动态方法调用之方法句柄 MethodHandle (opens new window)

本文以 Lambda 表达式中运用 invokedynamic 的实现分析。

# 二、通过简单的代码分析

class InvokeDynamicExample {
    public void lambda1() {
        Runnable runnable = () -> {
            int i = 1;
        };
        runnable.run();
    }
}

转为字节码后,关键字节码如下:

{
  public void lambda1();
    Code:
      stack=1, locals=2, args_size=1
         0: invokedynamic #2,  0     // 生成动态调用站点
         5: astore_1
         6: aload_1
         7: invokeinterface #3,  1  // 调用 lambda 表达式
        12: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  this   LInvokeDynamicExample;
            6       7     1 runnable   Ljava/lang/Runnable;

  private static void lambda$lambda1$0(); // Runnable lambda 表达式默认生成的方法
    Code:
      stack=1, locals=1, args_size=0
         0: iconst_1
         1: istore_0
         2: return
}
BootstrapMethods:  // 引导方法
  0: #23 invokestatic   // 调用静态方法 LambdaMetafactory.metafactory() 返回 CallSite 对象
    Method arguments: // 静态方法关联参数
      #24 ()V
      #25 invokestatic InvokeDynamicExample.lambda$lambda1$0:()V
      #24 ()V

大体流程:

  • javac 编译期间将 Lambda 表达式内容编译为一个新的方法,如果表达式与外部成员变量没有关联,编译为静态方法,否则编译为非静态方法。

    上述示例被编译为 private static void lambda$lambda1$0 静态方法。

  • 代码执行 invokedynamic 指令时,将调用常量池对应的 BootstrapMethods(引导方法) ,引导方法返回一个动态调用站点对象 CallSite,该对象绑定了要执行的方法句柄。

    上述示例引导方法为 #23 LambdaMetafactory.metafactory ,该方法返回一个动态调用站点对象 CallSite

  • 动态调用站点对象 CallSite 上绑定了 lambda$lambda1$0 方法相关的信息(参考字节码 #25)。

  • 之后执行 runnable.run(); 代码时,虚拟机则直接调用已经绑定了调用点所链接的 lambda$lambda1$0 方法。

# 参考

# 本专栏更多相关笔记

最后修改时间: 2/17/2020, 4:43:04 AM