Java LambdaMetaFactory 使用多个变量调用方法以避免反射

Java LambdaMetaFactory Method call with multiple vargs to avoid Reflection

我目前正在使用 Java 反射

我使用反射没有任何问题。我了解到 LambdaMetaFactory 的性能比反射更好。有关于 getter 和 setter 的示例 .. 但是没有像 doSomethig(String a, String b, int c) 这样的多参数化方法的示例;

这是我正在做的反思

@Override
public  T invokeReturn(final Object instance, final Object... args) throws Exception {

    try {
        final Method mtd = this.getMethod();
        mtd.setAccessible(getModifierAccessType() != ModifierAccessType.PUBLIC);
        final Object result = mtd.invoke(instance, args);
        if (getModifierAccessType() != ModifierAccessType.PUBLIC) {
            mtd.setAccessible(false);
        }
        return (T) result;
    } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
        logger.error("Error while Invoking Method", ex);
        throw new Exception(ex.getCause());
    }

}

我想在这里添加另一个支持 LambdaMetaFactory 的方法,我正在尝试

@Override
public <T> T callReturn(Object instance, Object... args) throws Exception {
    try {
        if (returnMethod == null) {
            final MethodHandles.Lookup lookup = MethodHandles.lookup();
            MethodHandle methodHandle = lookup.unreflect(method);
            MethodType fncType = this.mtdType();
            MethodType type = this.callMethodType();
            this.returnMethod = LambdaMetafactory.metafactory(lookup, "call", fncType, type, methodHandle, methodHandle.type()).getTarget();
        }

        switch (this.fncType()) {
            case Function: {
                MethodFunction<T> result = (MethodFunction<T>) this.returnMethod.invoke();
                return result.call(instance);
            }
            case FunctionArgs: {
                MethodFunctionArgs<T> result =  (MethodFunctionArgs<T>) this.returnMethod.invoke();
                 Object[] invokeParams = this.getInvokeParams(instance, args);
                return result.call(invokeParams);
            }
            case Void: {
                final VoidFunction result = (VoidFunction) this.returnMethod.invoke();
                result.call(instance);
                return null;
            }
            default: {
                final VoidFunctionArgs result = (VoidFunctionArgs) this.returnMethod.invoke();
                result.call(instance);
                return null;
            }
        }

    } catch (Throwable ex) {
        throw new Exception(ex);
    }
}

没有参数我对 switch cases default 和 Function 没有任何问题,但是有参数我不能 运行 这是我的 MethodFunctionArgs @FunctionalInterfaces

@FunctionalInterface
public interface MethodFunctionArgs<T> {

    T call(Object... params) ;
    ///tried too no success
    //T call(Object instance, Object... params) ;
    //VoidFunctionArgs  
    ///void call(Object instance, Object... params);
}

无论如何都要这样做?示例或教程不多,只有 getter 和 setter 也许有一种方法可以使用可变参数创建动态的@functionalinterface?

感谢帮助...

您不能将具有可变参数方法的接口绑定到任意目标方法,因为那样的话,接口将承诺处理任意数量的参数,而实际实现方法只接受固定数量的参数。因此,以下不会编译:

public interface MethodFunctionArgs<T> {
    T call(Object... params);
    static String someMethod(String arg1, int arg2) { return ""; }
    // does not work
    MethodFunctionArgs<String> func = MethodFunctionArgs::someMethod;
}

你可以做的是,反过来,一个可以处理任意数量参数的实现方法也可以处理带有特定参数的请求:

public interface MethodFunctionArgs<T> {
    T call(String arg1, int arg2);
    static String someMethod(Object... params) { return ""; }
    // no problem
    MethodFunctionArgs<String> func = MethodFunctionArgs::someMethod;
}

但必须提到的是 LambdaMetaFactory 无法处理可变参数处理。编译器通过插入一个合成辅助方法来帮助这里,所以编译后的代码相当于

public interface MethodFunctionArgs<T> {
    T call(String arg1, int arg2);
    static String someMethod(Object... params) { return ""; }
    // no problem
    MethodFunctionArgs<String> func = (arg1,arg2) -> someMethod(new Object[]{arg1, arg2});
}

但是当你有一个带有可变参数的功能接口时,你甚至在调用接口方法之前就已经付出了很多典型的反射成本(装箱、创建和填充数组)。您仍然可以测试 Method.invokeMethodHandle.invoke 相比的性能:

private MethodHandle handle;
public Object callReturn(Object... args) throws Exception {
    try {
        if(handle == null) {
            final MethodHandles.Lookup lookup = MethodHandles.lookup();
            MethodHandle h = lookup.unreflect(this.getMethod());
            handle = h.asType(h.type().generic())
                      .asSpreader(Object[].class, h.type().parameterCount());
        }
        return handle.invokeExact(args);
    } catch (Throwable ex) {
        throw new Exception(ex);
    }
}

要从 LambdaMetaFactory 获得性能优势,您需要具有匹配功能签名的特定接口。

interface SpecialFunction {
    Map<String,SpecialFunction> PREDEFINED = getMap();

    String call(int i, double d, String s);

    static String method1(int i, double d, String s) {
        return "method1("+i+", "+d+", "+s+')';
    }
    static String method2(int i, double d, String s) {
        return "method2("+i+", "+d+", "+s+')';
    }
    static String method3(int i, double d, String s) {
        return "method3("+i+", "+d+", "+s+')';
    }
    /* private  (with Java 9) */ static Map<String,SpecialFunction> getMap() {
        Map<String,SpecialFunction> map = new HashMap<>();
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodType invoked = MethodType.methodType(SpecialFunction.class);
        MethodType func = MethodType.methodType(String.class,
                                                int.class, double.class, String.class);
        final int mod = Modifier.PUBLIC|Modifier.STATIC;
        for(Method m: SpecialFunction.class.getDeclaredMethods()) try {
            MethodHandle target = lookup.unreflect(m);
            if((m.getModifiers()&mod) == mod && target.type().equals(func))
                map.put(m.getName(), (SpecialFunction)LambdaMetafactory.metafactory(
                    lookup, "call", invoked, func, target, func).getTarget().invoke());
        } catch(Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
        return Collections.unmodifiableMap(map);
    }
}