【问题标题】:How to invoke constructor using LambdaMetaFactory?如何使用 LambdaMetaFactory 调用构造函数?
【发布时间】:2018-05-07 09:43:47
【问题描述】:

我想尝试避免反射调用构造函数,并尝试遵循本文中采用的 LamdaMetaFactory 方法 - Faster alternatives to Java's reflection

我要构建的类如下所示:

interface DBBroker {}

public class NativeBroker implements DBBroker {
    public NativeBroker(BrokerPool brokerPool, final Configuration configuration) {
    }
}

使用LambaMetaFactory 我正在尝试构造一个BiFunction<BrokerPool, Configuration, DBBroker> 来替换对构造函数的直接调用。

到目前为止,我的代码如下所示:

Class<? extends DBBroker> clazz =
    (Class<? extends DBBroker>) Class.forName("org.exist.storage.NativeBroker");

MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh =
    lookup.findConstructor(clazz, MethodType.methodType(void.class, new Class[] {BrokerPool.class, Configuration.class}));

BiFunction<BrokerPool, Configuration, DBBroker> constructor 
    (BiFunction<BrokerPool, Configuration, DBBroker>)
        LambdaMetafactory.metafactory(
                    lookup, "apply", MethodType.methodType(BiFunction.class),
                    mh.type(), mh, mh.type()).getTarget().invokeExact();

final DBBroker broker = constructor.apply(database, conf);

不幸的是,这会返回错误 -

AbstractMethodError: 方法 org/exist/storage/BrokerFactory$$Lambda$55.apply(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 是抽象的。

我已经尝试修改传递给LambdaMetafactory.metafactory 的各种类型,但我似乎不能完全正确,而且Javadoc 肯定不容易理解。

有人可以建议吗?

【问题讨论】:

    标签: java lambda java-8 invokedynamic


    【解决方案1】:

    您犯的错误在于您使用的 SAM 类型。 apply 方法的已擦除类型必须用于此,所以这将是

    methodType(Object.class, Object.class, Object.class)
    

    但您也可以使用 mh.type().generic() 来返回相同的内容:

    BiFunction<BrokerPool, Configuration, DBBroker> constructor =
    (BiFunction<BrokerPool, Configuration, DBBroker>)
        LambdaMetafactory.metafactory(
                    lookup, "apply", methodType(BiFunction.class),
                    mh.type().generic(), mh, mh.type()).getTarget().invokeExact();
    //              ^^^^^^^^^^^^^^^^^^^
    

    【讨论】:

    • 通常LambdaMetafactory生成的类比MethodHandleProxies提供的代理效率更高,所以不是你是否需要LambdaMetafactory的问题...
    • @Holger 嗯,是的,我只是想知道自己的实现并进行了查找。它只是在内部使用Proxy.newInstance:/ 我仍然认为它更简单,但由于目标是性能,我将删除该部分。
    • 在大多数情况下,erase() 更接近于 generic() 的意图。
    • @adamretter Afaik 如果您不知道确切的类型,则无法找到构造函数方法句柄,尽管您可以使用unreflectConstructorConstructor&lt;...&gt; 对象转换为方法句柄。但是如果你只调用一次然后丢弃它,你还不如直接调用newInstance
    • @adamretter 从paramClasses 派生构造函数类型将起作用,只要它们与构造函数参数类型完全匹配(并且不是子类型)。但是您仍然不知道用作包装器的接口。我想你可以直接使用方法句柄。
    猜你喜欢
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    • 1970-01-01
    • 2016-07-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多