public final native @PolymorphicSignature Object invokeExact(Object... args)
throws Throwable;
public final native @PolymorphicSignature Object invoke(Object... args)
throws Throwable;
/**
* Internal marker interface which distinguishes (to the Java compiler)
* those methods which are <a href="MethodHandle.html#sigpoly">signature polymorphic</a>.
*/
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@interface PolymorphicSignature { }
PolymorphicSignature是个内部使用的标记接口,Javac用来区分那些签名多态的方法。
The unusual compilation and linkage behavior of invokeExact and plain
invoke is referenced by the term signature polymorphism. As defined in
the Java Language Specification, a signature polymorphic method is
one which can operate with any of a wide range of call signatures and
return types.
invokeExact和invoke方法被标记为@PolymorphicSignature
In source code, a call to a signature polymorphic method will compile,
regardless of the requested symbolic type descriptor. As usual, the Java
compiler emits an invokevirtual instruction with the given symbolic type
descriptor against the named method. The unusual part is that the
symbolic type descriptor is derived from the actual argument and return
types, not from the method declaration.
像往常一样,Java编译器使用给定的符号类型描述符针对命名方法生成invokevirtual指令。
不同的是符号类型描述符是从实际的参数和返回类型派生的,而不是从方法声明派生的。
When the JVM processes bytecode containing signature polymorphic
calls, it will successfully link any such call, regardless of its symbolic
type descriptor. (In order to retain type safety, the JVM will guard such
calls with suitable dynamic type checks, as described elsewhere.)
当JVM处理包含签名多态调用的字节码时,无论其符号类型描述符如何,它都将成功链接任何此类调用。 (为了保持类型安全性,JVM将使用适当的动态类型检查来保护此类调用,如其他地方所述。)
Bytecode generators, including the compiler back end, are required to
emit untransformed symbolic type descriptors for these methods. Tools
which determine symbolic linkage are required to accept such
untransformed descriptors, without reporting linkage errors.
字节码生成器(包括后端编译器)需要为这些方法生成未转换的符号类型描述符。确定符号链接的工具需要接受这种未转换的描述符,而不报告链接错误。
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class PolymorphicSignatureTest {
public int calculate(int num) {
return num + 1;
}
public double calculate(double num) {
return num + 1;
}
public double calculate(Integer num) {
return num + 1;
}
public static void main(String[] args) throws Throwable{
MethodType mt = MethodType.methodType(int.class, int.class);
MethodHandle mh = MethodHandles.lookup()
.findVirtual(PolymorphicSignatureTest.class, "calculate", mt)
.bindTo(new PolymorphicSignatureTest());
int result1 = (int)mh.invoke(1);
double result2 = (double)mh.invoke(1);
double result3 = (double)mh.invoke(Integer.valueOf(1));
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
}
}
针对其中三个invoke调用,编译出来的字节码根据 参数和返回值,生成了不同的符号类型描述符:
31: astore_2
32: aload_2
33: iconst_1
34: invokevirtual #11 // Method java/lang/invoke/MethodHandle.invoke:(I)I
37: istore_3
38: aload_2
39: iconst_1
40: invokevirtual #12 // Method java/lang/invoke/MethodHandle.invoke:(I)D
43: dstore 4
45: aload_2
46: iconst_1
47: invokestatic #13 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
50: invokevirtual #14 // Method java/lang/invoke/MethodHandle.invoke:(Ljava/lang/Integer;)D
也即
int result1 = (int)mh.invoke(1);
double result2 = (double)mh.invoke(1);
double result3 = (double)mh.invoke(Integer.valueOf(1));
对应
Method java/lang/invoke/MethodHandle.invoke:(I)I
Method java/lang/invoke/MethodHandle.invoke:(I)D
Method java/lang/invoke/MethodHandle.invoke:(Ljava/lang/Integer;)D