首页 > 解决方案 > 如何使用 LambdaMetaFactory 调用构造函数?

问题描述

我想尝试避免反射调用构造函数,并尝试遵循本文中采用的 LamdaMetaFactory 方法 - Java 反射的更快替代方案

我要构建的课程如下所示:

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 肯定不容易理解。

有人可以建议吗?

标签: javalambdajava-8invokedynamic

解决方案


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

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

但你也可以使用mh.type().generic()which 返回相同的东西:

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

推荐阅读