Java 字节码调用接口指令

Java Bytecode invokeinterface instruction

查看此 Java 字节码(来自 Eclipse 类文件查看器),我注意到 invokeinterface 指令有些奇怪:它有一个 nargs(参数数量)'attribute' 占用2个字节:

35  aload_2 [map]
36  ldc <String "a"> [15]
38  invokeinterface java.util.Map.get(java.lang.Object) : java.lang.Object [33] [nargs: 2]
43  checkcast java.lang.String [35]
46  invokevirtual java.io.PrintStream.println(java.lang.Object) : void [47]
49  getstatic java.lang.System.out : java.io.PrintStream [41]

为什么会这样? invokeinterfaceinvokevirtual 有什么区别? JVM 不应该能够从给定的方法签名中推断出参数的数量(因此从堆栈中弹出的值的数量)吗?

你是对的,参数的数量可以从签名中推断出来。 JVM spec 对此有话要说:

"The count operand of the invokeinterface instruction records a measure of the number of argument values, where an argument value of type long or type double contributes two units to the count value and an argument of any other type contributes one unit. This information can also be derived from the descriptor of the selected method. The redundancy is historical."