Java 获取lambdas类的列表
在Java8中,类的lambda似乎保存在一个数组中。例如,假设我们有这个类:Java 获取lambdas类的列表,java,lambda,java-8,Java,Lambda,Java 8,在Java8中,类的lambda似乎保存在一个数组中。例如,假设我们有这个类: public class LambdaFactory { public Supplier<Integer> getOne(){ return () -> 42; } public Supplier<Integer> getTwo(){ return () -> 128; } public Supplier&
public class LambdaFactory {
public Supplier<Integer> getOne(){
return () -> 42;
}
public Supplier<Integer> getTwo(){
return () -> 128;
}
public Supplier<Integer> getThree(){
return () -> 3;
}
}
输出将类似于
examples.LambdaFactory$$Lambda$1@4e515669
examples.LambdaFactory$$Lambda$1@4e515669
examples.LambdaFactory$$Lambda$2@1b9e1916
examples.LambdaFactory$$Lambda$3@ba8a1dc
我们可以看到两件事。同一个lambda调用了两次,给了我们相同的lambda对象(这与我们每次都可以得到一个新的内部类的anon类不同)。我们还看到它们看起来像是被保存在类的某个“Lambda”结构中
我的问题是,我能在课堂上找到兰姆达斯吗?我没有任何理由这么做,我只是喜欢剖析事物lambda是由JRE创建的,它们的创建方式由JRE控制,在不同的JRE供应商之间可能会有所不同,在未来的版本中可能会发生变化 如果您想玩得开心,可以在运行时创建lambda,该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时发生的情况。但是对于编译时(“real”)lambda表达式,整个过程是由单个invokedynamic
字节码指令触发的。LambdaMetafactory.metafactory(…)
方法是在第一次执行invokedynamic
指令时调用的引导方法。返回的CallSite
对象与invokedynamic
指令永久关联。如果CallSite
是一个ConstantCallSite
并且它的MethodHandle
在每次执行时返回相同的lambda对象,那么invokedynamic
指令将永远“生成”相同的lambda实例。
在运行时,lambda表达式的计算类似于
在正常情况下,对类实例创建表达式的求值
完成生成对对象的引用。[……]
具有以下属性的类的新实例
已分配并初始化,或具有
下面的属性被引用
[……]
这些规则旨在为的实现提供灵活性
Java编程语言,在该语言中:
- 无需在每次评估时分配新对象。
- [……]
字符串、整数文本等。这些常量出现在.class
文件的常量池中。这些是对在运行时创建和存在的对象的引用。无法从类的常量池中引用实际对象
在lambda的情况下,它不会有任何帮助,因为它实际上可能不是同一个对象。是什么让你认为它们在一个数组中?我认为你在这里得出了错误的结论。匿名内部类的名称中通常包含$1
结构——通常在运行时构造带美元符号的类名,例如在使用动态代理
类时。我想我不知道它是数组还是什么,但lambda是一样的。如果我在getOne的两个供应商上执行jUnit Assert.assertSame,它将通过,但如果它是annon内部类,它将失败。请参阅更新以删除我对数组的假设。我希望看到lambda“两次调用的同一个lambda给我们提供了相同的lambda对象”——不总是这样。如果lamba表达式引用外部作用域中的变量,则每次使用lamba时都会创建一个新实例。
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");
}
}