2
import java.lang.invoke.*;

public class InvokeDynamicDemo {            
    public static double doubleIt(double d){
        System.out.print("Doubling it");
        return d*2;
    }

    public static void main(String[] args) throws Throwable {    
        MethodHandles.Lookup lookUp  = MethodHandles.lookup();
        MethodHandle doubleIt = lookUp.findStatic(InvokeDynamicDemo.class, "doubleIt", MethodType.methodType(double.class,double.class));
        doubleIt.invokeExact(2.0D); // Exception 
       //doubleIt.invoke(2.0D); // No exception thrown          
    }
}

线程“主”java.lang.invoke.WrongMethodTypeException 中的异常:预期 (double)double 但在 java.lang.invoke.Invokers 的 java.lang.invoke.Invokers.newWrongMethodTypeException(Invokers.java:340) 发现 (double)void .checkExactType(Invokers.java:351) 在 InvokeDynamicDemo.main(InvokeDynamicDemo.java:32)

这段代码有什么问题,我想不通。请帮忙。

4

2 回答 2

12

问题是您没有使用该invokeExact方法的结果。我以前没有见过这种方法,但看起来 Java 编译器必须以一种非常特殊的方式来处理它。从MethodHandle文档中:

与虚拟方法一样,invokeExact 和invoke 的源级调用编译为invokevirtual 指令。更不寻常的是,编译器必须记录实际的参数类型,并且可能不对参数执行方法调用转换。相反,它必须生成指令,根据它们自己未转换的类型将它们压入堆栈。方法句柄对象本身在参数之前被压入堆栈。然后编译器生成一条invokevirtual指令,该指令使用描述参数和返回类型的符号类型描述符调用方法句柄。

要发出完整的符号类型描述符,编译器还必须确定返回类型。这基于对方法调用表达式的强制转换,如果有的话,或者Object如果调用是表达式,或者void如果调用是语句。强制转换可能是原始类型(但不是void)。

目前您在不使用结果的情况下调用该方法,因此编译器推断您希望它是一个void方法 - 因此(double)void是异常的一部分。

如果您将呼叫更改为:

double result = (double) doubleIt.invokeExact(2.0);

...然后编译器知道您期望的返回类型,并可以创建适当的符号类型描述符。

于 2017-12-16T07:48:42.777 回答
0

Oracle 文档中,它说invokeExact方法调用方法句柄,允许任何调用者类型描述符,但需要精确的类型匹配。invokeExact 调用点的符号类型描述符必须与此方法句柄的类型完全匹配。不允许对参数或返回值进行转换。

但是,invoke方法调用方法句柄,允许任何调用者类型描述符,并可选择对参数和返回值执行转换。

于 2017-12-16T07:55:38.517 回答