Lambda 表达式在运行时创建内部类

RBS*_*RBS 2 java lambda java-8

为了探索 lambda 及其工作原理,我编写了下面的代码。

public class Foo { // enclose class

public static void main(String[] args) {
    System.out.println(new Foo().new InnerFoo());
    IntSupplier intSupplier = () -> 42;
    System.out.println(intSupplier);
}

class InnerFoo{} // inner class

}
Run Code Online (Sandbox Code Playgroud)

执行代码后,我看到以下输出。

Foo$InnerFoo@3af49f1c
Foo$$Lambda$15/0x0000000840064c40@13221655
Run Code Online (Sandbox Code Playgroud)

我基本上有两个基于输出的问题。

  1. 据我所知,当每个内部类被实例化时,它可以表示为EnendingClass$InnerClass@hashcode as toString()(如果我们不重写 toString())。那么这是否意味着我的Foo$$Lambda$15/0x0000000840064c40@13221655是内部类的定义?如果是这样,那么加载的内部类在 JVM 中保留多长时间?
  2. $$Lambda的含义是什么。JVM将如何解释它?

Swe*_*per 6

这是JEP 371中提议的隐藏类的名称。从 Java 15 开始,这就是 lambda 的实现方式。

这些是在运行时生成的类,使用Lookup.defineHiddenClass,而不是ClassLoader.defineClass。因此,它们不是由类加载器加载的。

至于代码的输出,@像往常一样,后面的部分是对象的身份哈希码。前面的部分是隐藏类的名称Foo$$Lambda$15/0x0000000840064c40。它可以分为两部分:Foo$$Lambda$15是类定义中使用的名称(字节,以传递给 的类文件格式defineHiddenClass),并且0x0000000840064c40是 JVM 生成的非限定名称。并$$没有什么特别的意思。$是在类名中使用的有效字符。

在 JEP 的末尾,它讨论了隐藏类的生命周期。其要点是,一旦不再存在该类的任何活动实例,就可以卸载隐藏类。例如,当 lambda 表达式创建的对象被垃圾收集时。