0

我目前正在使用 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 case 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 也许有一种方法可以使用 varags 创建动态 @functionalinterface?

谢谢你的帮助...

4

1 回答 1

1

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

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.invoke比较的性能MethodHandle.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);
    }
}
于 2018-02-16T18:15:54.750 回答