为什么 lambda 翻译需要生成静态方法?
Lambda 翻译是一个两步过程,一个:将 lambda 脱糖成同一类中的静态方法.
公共类 Main {公共静态无效主要(字符串[]参数){可运行 r = () ->System.out.println("你好");System.out.println(Arrays.asList(Main.class.getDeclaredMethods()));}}
<块引用>
[private static void Main.lambda$main$0(), public static voidMain.main(java.lang.String[])]
二:生成实现功能接口的类.
System.out.println("已经生成了一个类:" + r.getClass());System.out.println("实现了一个功能接口:" + Arrays.asList(r.getClass().getInterfaces()));
<块引用>
已经生成了一个类:class Main$$Lambda$1/149928006
实现一个功能接口:[interface java.lang.Runnable]
问题:这个静态方法有什么需要?为什么不能直接把lambda body放到接口方法里面呢?类似的东西:
类 Main$$Lambda$1 {公共无效运行(){/* 这里是 Lambda 主体 */}}
解决方案除了这里给出的正确答案(因为现在的方案效率更高,减少lambdas的捕获/链接成本,减少代码重复),还有一个您的想法根本没有意义的其他几个原因.
- 字节码首先来自哪里?lambda 代理类是在运行时生成的,而不是在编译时生成的.如果我们要将字节码填充到代理类中,它必须来自某个地方.这意味着我们必须将它放入捕获类文件中然后将其复制到代理类中.在这里,它只存在于捕获类中,我们就完成了.
- 访问控制.如果 lambda 主体调用私有方法怎么办?通过将其脱糖到捕获类中,它会自动获取捕获类的访问控制上下文(它在逻辑上是其中的一部分).如果我们将字节码放在代理类中,我们必须做一些额外的魔法来赋予它正确的访问控制上下文.
Lambda translation is a two step process, One: desugaring the lambda into a static method in same class.
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[])]
Two: generation of a class that implements the Functional Interface.
System.out.println("A class has been generated: " + r.getClass());
System.out.println("That implements a Functional Interface: " + Arrays.asList(r.getClass().getInterfaces()));
A class has been generated: class Main$$Lambda$1/149928006
That implements a Functional Interface: [interface java.lang.Runnable]
Question: What is the need of this static method? Why can't the lambda body be put directly into the interface method? Something like:
class Main$$Lambda$1 {
public void run() {
/* Lambda body here */
}
}
解决方案
In addition to the correct answers given here (because the current scheme is more efficient, reducing capture/linkage costs for lambdas and reducing code duplication), there are a few other reasons why your idea simply doesn't make sense.
- Where would the bytecode come from in the first place? The lambda proxy class is generated at runtime, not compile time. If we were to stuff the bytecode into the proxy class, it would have to come from somewhere. That would mean we'd have to put it into the capturing class file and then copy it into the proxy class. Here, it just lives in the capturing class and we're done.
- Access control. What if the lambda body calls a private method? By desugaring it into the capturing class, it automatically acquires the access control context of the capturing class (which it is logically a part of.) If we put the bytecode in the proxy class, we'd have to do additional magic to give it the right access control context.
相关文章