获取lambdas类的列表

在Java 8中,看起来类的lambda保存在数组中。 例如,假设我们有这个类:

public class LambdaFactory { public Supplier getOne(){ return () -> 42; } public Supplier getTwo(){ return () -> 128; } public Supplier getThree(){ return () -> 3; } } 

然后我这样打印出来:

  System.out.println(factory.getOne()); System.out.println(factory.getOne()); System.out.println(factory.getTwo()); System.out.println(factory.getThree()); 

输出将是这样的

 examples.LambdaFactory$$Lambda$1@4e515669 examples.LambdaFactory$$Lambda$1@4e515669 examples.LambdaFactory$$Lambda$2@1b9e1916 examples.LambdaFactory$$Lambda$3@ba8a1dc 

所以我们在这里可以看到两件事。 调用两次的同一个lambda给了我们相同的lambda对象(这与我们每次都可以得到一个新的内部类不同)。 我们也看到它们看起来像是被保留在某种类型的“Lambda”结构中

我的问题是,我可以在课堂上看到lambdas吗? 我没有任何理由这样做,我只是喜欢解剖一些东西

lambdas由JRE创建,它们的创建方式由JRE控制,并且可能因不同的JRE供应商而异,并且可能在将来的版本中有所变化。

如果你想玩得开心,你可以在运行时创建一个lambda,它在类文件中没有相应的信息:

 import java.lang.invoke.*; public class ManualLambda { public static void main(String[] args) throws Throwable { MethodHandles.Lookup me=MethodHandles.lookup(); MethodType t=MethodType.methodType(void.class); MethodType rt=MethodType.methodType(Runnable.class); CallSite site = LambdaMetafactory.metafactory( me, "run", rt, t, me.findStatic(ManualLambda.class, "sayHello", t), t); MethodHandle factory=site.getTarget(); Runnable r=(Runnable)factory.invoke(); System.out.println("created lambda: "+r); r.run(); } private static void sayHello() { System.out.println("hello world"); } } 

上面的代码回顾了创建lambda时发生的事情。 但对于编译时(“实际”)lambda表达式,整个事物由单个invokedynamic字节代码指令触发。 LambdaMetafactory.metafactory(…)方法是bootstrap方法,当第一次执行invokedynamic指令时调用该方法。 返回的CallSite对象与invokedynamic指令永久关联。 如果CallSiteConstantCallSite并且其MethodHandle在每次执行时返回相同的lambda对象,则invokedynamic指令将永久“生成”相同的lambda实例。

Java语言规范说明

在运行时,lambda表达式的计算类似于类实例创建表达式的计算,只要正常完成产生对对象的引用即可。 […]

将分配并初始化具有以下属性的类的新实例,或者引用具有以下属性的类的现有实例。

[…]

这些规则旨在为Java编程语言的实现提供灵活性,其中:

  • 不需要在每次评估时分配新对象。
  • […]

因此,由编译器或运行时环境决定在评估lambda表达式时应返回的内容。

我的问题是,我可以在课堂上看到lambdas吗? 我没有任何理由这样做,我只是喜欢解剖一些东西

您可以将lambda表达式视为任何其他类常量, String ,整数文字等。这些是出现在.class文件的常量池中的常量。 这些是对在运行时创建和存在的对象的引用。 无法从类的常量池中引用实际对象。

在lambda的情况下,无论如何它都没有用,因为它实际上可能不是同一个对象。