Lambda Metafactory变量捕获 [英] Lambda Metafactory Variable Capture

查看:138
本文介绍了Lambda Metafactory变量捕获的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 MethodHandles.Lookup 手动创建lambda时, MethodHandle s, MethodType s等,如何实现变量捕获?

When creating a lambda manually using MethodHandles.Lookup, MethodHandles, MethodTypes, etc, how might one implement variable capture?

例如,没有捕获:

public IntSupplier foo() {
    return this::fortyTwo;
}
/**
 *  Would not normally be virtual, but oh well.
 */
public int fortyTwo() {
    return 42;
}

及其笨重形式,使用 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;
}

会返回一个简单,毫无意义的 IntSupplier 在调用时返回 42 ,但是如果想要捕获某些内容会怎样?

would return a simple, pointless IntSupplier that returns 42 when invoked, but what if one would like to capture something?

推荐答案

引导方法的第三个参数,你命名为 lambdaType ,是关联的<$>的调用类型 c $ c> invokedynamic 指令(通常由JVM填写)。它的语义是由bootstrap方法定义的,在 LambdaMetaFactory 的情况下,它将函数接口指定为返回类型(要构造的对象的类型)和值捕获为参数类型(构造lambda实例时要使用的值的类型)。

The third argument to the bootstrap method, which you named lambdaType, is the invoked type of the associated invokedynamic instruction (normally filled in by the JVM). It’s semantic is defined by the bootstrap method and in the case of the LambdaMetaFactory, it specifies the functional interface as return type (the type of the object to construct) and the values to capture as parameter type (the type of the values to consume when constructing a lambda instance).

所以为了捕获这个,您必须将的类型添加到您调用的类型,并将作为参数传递给 invokeExact call:

So in order to capture this, you have to add the type of this to your invoked type and pass this as an argument to the invokeExact call:

public class Test {
    public static void main(String... arg) throws Throwable {
        System.out.println(new Test().foo().getAsInt());
    }
    public IntSupplier foo() throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType methodType  = MethodType.methodType(int.class),
                   invokedType = MethodType.methodType(IntSupplier.class, Test.class);
        MethodHandle methodHandle = lookup.findVirtual(getClass(), "fortyTwo", methodType);
        CallSite callSite = LambdaMetafactory.metafactory(lookup, "getAsInt",
            invokedType, methodType, methodHandle, methodType);
        return (IntSupplier) callSite.getTarget().invokeExact(this);
    }
    public int fortyTwo() {
        return 42;
    }
}

如果你想捕获更多的值,你必须按正确的顺序将它们添加到签名中。例如,要捕获另一个 int 值:

If you want to capture more values, you have to add them to the signature in the right order. E.g., to capture another int value:

public class Test {
    public static void main(String... arg) throws Throwable {
        System.out.println(new Test().foo(100).getAsInt());
    }
    public IntSupplier foo(int capture) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType methodType = MethodType.methodType(int.class, int.class),
            functionType = MethodType.methodType(int.class),
            invokedType = MethodType.methodType(IntSupplier.class, Test.class, int.class);
        MethodHandle methodHandle=lookup.findVirtual(getClass(),"addFortyTwo",methodType);
        CallSite callSite = LambdaMetafactory.metafactory(lookup, "getAsInt",
            invokedType, functionType, methodHandle, functionType);
        return (IntSupplier) callSite.getTarget().invokeExact(this, capture);
    }
    public int addFortyTwo(int valueToAdd) {
        return 42+valueToAdd;
    }
}

目标方法的签名由类型,如果不是 static ,则后跟所有参数类型。捕获值将从左到右映射到此签名的类型,其余参数类型(如果有)对功能签名有贡献,因此必须匹配接口方法参数类型。

The target method will have a signature consisting of the this type, if not static, followed by all parameter types. The capture values will map in order to this signature’s types from left to right and the remaining parameter types, if any, contribute to the functional signature, hence have to match the interface method’s parameter types.

这意味着当没有捕获的值且目标方法不是 static 时,方法接收器类型可能与第一种类型的功能签名相关联,如 ToIntFunction< String> f = String :: length;

This implies that when there are no captured values and the target method is not static, the method receiver type might become associated with the first type of the functional signature, as in ToIntFunction<String> f=String::length;.

这篇关于Lambda Metafactory变量捕获的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆