如果我没有弄错,在某些情况下,Java中的lambda将作为匿名类实例生成。例如,在此代码中,lambda需要从外部捕获变量:
final int local = 123456;
list.forEach(x -> System.out.println(x + local));
这是否意味着垃圾收集器会将lambda声明为对象?
答案 0 :(得分:11)
是的,表示lambda表达式的实例就像任何其他对象一样被垃圾收集。如果包含lambda表达式的类符合收集条件,即使是实现功能接口的类也可以收集。
没有收集上述lambda的原因是lambda bootstrap方法优化的结果。通常,bootstrap方法将静态工厂方法绑定到invokedynamic调用站点。如果需要,该工厂将获取封闭方法的所有必需变量以及对声明实例的引用。然后工厂创建表示lambda的类的实例,并将所有值存储在此实例的字段中。
但是,如果lambda表达式没有任何状态,则bootstrap方法会创建一个单例,然后直接绑定到lambda表达式的调用站点。当然,在封闭类之前不能收集这个单例。
如果您想了解有关invokedynamic和lambda表达式如何工作的更多信息,我最近写了一个摘要:http://mydailyjava.blogspot.no/2015/03/dismantling-invokedynamic.html?m=1
这是HotSpot的当前实现,引导程序将来可能会发生变化。
答案 1 :(得分:6)
是的,生成了一个类实例;不,它不会淡出。
lambda是一个使用invokedynamic
链接的呼叫网站;在初始链接完成后,JIT可以自由启动,例如,可以内联代码。所以,你的“班级实例”在开始时才真正是一个班级。
例如,如果lambda是方法引用,则最终JIT会根据此方法引用将lambda内联到invoke {static,virtual,interface,special}。然而,JIT所做的工作依赖于供应商。