Mon*_*nad 7 java lambda java-8
使用MethodHandles.Lookup,MethodHandles,MethodTypes等手动创建lambda时,如何实现变量捕获?
例如,没有捕获:
public IntSupplier foo() {
return this::fortyTwo;
}
/**
* Would not normally be virtual, but oh well.
*/
public int fortyTwo() {
return 42;
}
Run Code Online (Sandbox Code Playgroud)
和它的笨拙形式,使用的东西java.lang.invoke:
public IntSupplier foo() {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(int.class),
lambdaType = MethodType.methodType(IntSupplier.class);
MethodHandle methodHandle = lookup.findVirtual(getClass(), "fortyTwo", methodType);
CallSite callSite = LambdaMetafactory.metafactory(lookup, "getAsInt", lambdaType, methodType, methodHandle, methodType);
return (IntSupplier) callSite.getTarget().invokeExact();
}
/**
* Would not normally be virtual, but oh well.
*/
public int fortyTwo() {
return 42;
}
Run Code Online (Sandbox Code Playgroud)
会返回一个简单的,无意义的IntSupplier,42在调用时返回,但如果有人想要捕获什么呢?
bootstrap 方法的第三个参数(您将其命名为lambdaType)是关联指令的调用类型invokedynamic(通常由 JVM 填充)。It\xe2\x80\x99s 语义由 bootstrap 方法定义,在 的情况下LambdaMetaFactory,它将函数接口指定为返回类型(要构造的对象的类型),并将要捕获的值指定为参数类型(构造 lambda 实例时要使用的值)。
因此,为了捕获this,您必须将 的类型添加this到调用的类型中,并this作为参数传递给调用invokeExact:
public class Test {\n public static void main(String... arg) throws Throwable {\n System.out.println(new Test().foo().getAsInt());\n }\n public IntSupplier foo() throws Throwable {\n MethodHandles.Lookup lookup = MethodHandles.lookup();\n MethodType methodType = MethodType.methodType(int.class),\n invokedType = MethodType.methodType(IntSupplier.class, Test.class);\n MethodHandle methodHandle = lookup.findVirtual(getClass(), "fortyTwo", methodType);\n CallSite callSite = LambdaMetafactory.metafactory(lookup, "getAsInt",\n invokedType, methodType, methodHandle, methodType);\n return (IntSupplier) callSite.getTarget().invokeExact(this);\n }\n public int fortyTwo() {\n return 42;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n如果您想捕获更多值,则必须以正确的顺序将它们添加到签名中。例如,要捕获另一个int值:
public class Test {\n public static void main(String... arg) throws Throwable {\n System.out.println(new Test().foo(100).getAsInt());\n }\n public IntSupplier foo(int capture) throws Throwable {\n MethodHandles.Lookup lookup = MethodHandles.lookup();\n MethodType methodType = MethodType.methodType(int.class, int.class),\n functionType = MethodType.methodType(int.class),\n invokedType = MethodType.methodType(IntSupplier.class, Test.class, int.class);\n MethodHandle methodHandle=lookup.findVirtual(getClass(),"addFortyTwo",methodType);\n CallSite callSite = LambdaMetafactory.metafactory(lookup, "getAsInt",\n invokedType, functionType, methodHandle, functionType);\n return (IntSupplier) callSite.getTarget().invokeExact(this, capture);\n }\n public int addFortyTwo(int valueToAdd) {\n return 42+valueToAdd;\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\nthis目标方法将具有由类型(如果不是)组成的签名static,后跟所有参数类型。捕获值将从左到右映射到此签名\xe2\x80\x99s类型,其余参数类型(如果有)有助于功能签名,因此必须匹配方法\ interfacexe2\x80\x99s参数类型。
这意味着当没有捕获的值并且目标方法不是 时static,方法接收者类型可能会与函数签名的第一种类型相关联,如 中所示ToIntFunction<String> f=String::length;。
| 归档时间: |
|
| 查看次数: |
555 次 |
| 最近记录: |