为什么lambda翻译需要生成静态方法?


问题内容

Lambda转换是一个两步过程, 一个是 :将lambda分解为同一类中的静态方法。

public class Main {
    public static void main(String[] args) {
        Runnable r = () -> System.out.println("Hello");
        System.out.println(Arrays.asList(Main.class.getDeclaredMethods()));
    }
}

[ private static void Main.lambda $ main $ 0() ,public static void
Main.main(java.lang.String [])]

:生成实现功能接口的类。

System.out.println("A class has been generated: " + r.getClass());
System.out.println("That implements a Functional Interface: " + Arrays.asList(r.getClass().getInterfaces()));

已生成一个类:类Main $$ Lambda $ 1/149928006

实现一个功能接口:[interface java.lang.Runnable]

问题此静态方法需要什么? 为什么不能将lambda主体直接放入接口方法中?就像是:

class Main$$Lambda$1 {
    public void run() {
        /* Lambda body here */
    }
}

问题答案:

除了此处给出的正确答案(因为当前方案更有效,减少lambda的捕获/链接成本并减少代码重复)之外,还有其他一些原因使您的想法根本没有意义。

  • 字节码首先从哪里来?lambda代理类是在运行时生成的,而不是在编译时生成的。如果我们将字节码填充到代理类中,则它必须来自某个地方。这意味着我们必须将其放入捕获类文件中 ,然后将复制 到代理类中。在这里,它只存在于捕获类中,我们就完成了。
  • 访问控制。如果lambda主体调用私有方法怎么办?通过将其分解为捕获类,它会自动获取捕获类的访问控制上下文(从逻辑上讲,它是其中的一部分。)如果将字节码放入代理类中,则必须做一些额外的魔术才能赋予它正确的访问控制上下文。