提问人:Ekaterina 提问时间:12/22/2019 更新时间:12/22/2019 访问量:143
Java 中的闭包
Closures in Java
问:
这个例子是JavaScript中闭包的模拟(我不知道JS):
public class Lambda {
public static void main(String[] args) {
Supplier generator = Lambda.generator();
System.out.println(generator.get());
System.out.println(generator.get());
System.out.println(generator.get());
}
static Supplier<Integer> generator() {
Integer arr[] = {0};
return () -> ++arr[0];
}
}
输出为 1 2 3。
通常,局部方法变量的寿命受方法执行时间的限制。但在这种情况下,对的引用存储在某个地方。那么它存储在哪里,引擎盖下有什么?arr[]
答:
4赞
kaya3
12/22/2019
#1
Java 语言规范 (§15.27.4) 说:
lambda 表达式的值是对具有以下属性的类实例的引用:
- 该类实现目标函数接口类型...
因此,lambda 定义了一个类,就像匿名类声明一样,lambda 表达式会生成对该类实例的引用。引用由属于该实例的合成字段保存。arr
final
下面是一个在 JShell REPL 中使用反射的示例,用于演示具有合成字段的 lambda:
> class A { static Runnable a(int x) { return () -> System.out.println(x); } }
| created class A
> Runnable r = A.a(5);
r ==> A$$Lambda$15/1476394199@31ef45e3
> import java.lang.reflect.Field;
> Field f = r.getClass().getDeclaredFields()[0];
f ==> private final int A$$Lambda$15/1476394199.arg$1
> f.setAccessible(true);
> f.get(r)
$6 ==> 5
评论
0赞
Ekaterina
12/22/2019
谢谢,您能参考一下“合成最终场”吗?
1赞
kaya3
12/22/2019
很难获得权威的,因为它更像是一个实现细节,而不是一个特定的行为。JVMS定义了“合成”的含义,但没有指定它适用的所有情况:docs.oracle.com/javase/specs/jvms/se7/html/......本文展示了一个反编译的 lambda,其合成字段名为 : doanduyhai.com/blog/?p=1353 Robert Fischer (2015) 所著的《Java Closures and Lambda》一书在第 152 页讨论了 lambda 的合成字段。cap$0
1赞
kaya3
12/22/2019
如果有帮助的话,我添加了一个示例,通过 REPL 中的反射显示合成场。
评论