简体   繁体   English

Java LambdaMetaFactory方法调用带有多个vargs以避免反射

[英]Java LambdaMetaFactory Method call with multiple vargs to avoid Reflection

I am currently using Java reflection 我目前正在使用Java反射

I don't have any problem doing it with reflection . 我用反射做它没有任何问题。 I learned about LambdaMetaFactory has better performance than reflection .. There is examples about getter and setter .. but there is no example for multiple parameterized method like doSomethig(String a, String b, int c) ; 我了解到LambdaMetaFactory具有比反射更好的性能。.有关于getter和setter的示例..但是没有像doSomethig(String a,String b,int c)这样的多参数化方法的示例;

here is what i am doing on reflection 这就是我在思考的过程

 @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()); } } 

i want to add another method which supports LambdaMetaFactory here what iam trying 我想在这里添加另一种支持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);
    }
}

without arguments I dont have any problem on switch cases default and Function, but with arguments i can't run it Here is My MethodFunctionArgs @FunctionalInterfaces 没有参数我在开关盒默认值和功能上没有任何问题,但是带有参数我无法运行它是我的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);
}

Anyway to do that? 无论如何要这样做? there is not a lot of example or tutorial all is only getter and setter maybe there is a way to create dynamic @functionalinterface with varags? 没有太多的示例或教程,仅是getter和setter,也许有一种方法可以用varags创建动态@functionalinterface?

thanx for help... 感谢帮助...

You can't bind an interface with a varargs method to an arbitrary target method, as then, the interface would promise to handle an arbitrary number of arguments while the actual implementation method only accepts a fixed number of arguments. 您不能将具有varargs方法的接口绑定到任意目标方法,因为那样,该接口将承诺处理任意数量的参数,而实际的实现方法仅接受固定数量的参数。 Hence, the following does not compile: 因此,以下内容无法编译:

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

What you can do, is the other way round, an implementation method that can handle an arbitrary number of arguments can also handle a request with specific arguments: 相反,您可以做的是,可以处理任意数量参数的实现方法也可以处理带有特定参数的请求:

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

But it must be mentioned that the LambdaMetaFactory is not capable of handling the varargs processing. 但是必须指出的是, LambdaMetaFactory无法处理varargs处理。 The compiler helps here by inserting a synthetic helper method, so the compiled code is equivalent to 编译器通过插入合成辅助方法来提供帮助,因此编译后的代码等效于

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});
}

But when you have a functional interface with varargs, you are already paying a lot of the typical Reflection costs (boxing, and creating and filling an array) before even invoking the interface method. 但是,当您具有使用varargs的功能接口时,甚至在调用接口方法之前,您已经已经支付了很多典型的反射成本(装箱,创建和填充数组)。 You may still test the performance of Method.invoke compared to MethodHandle.invoke : MethodHandle.invoke相比,您仍然可以测试Method.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);
    }
}

To get a performance benefit from the LambdaMetaFactory , you need a specific interface with a matching functional signature. 为了从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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM