这是visitMethodInsn
类的MethodNode
方法的正文:
@Override
public void visitMethodInsn(
final int opcode,
final @InternalForm String owner,
final @Identifier String name,
final @MethodDescriptor String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
instructions.add(new MethodInsnNode(opcode, owner, name, descriptor, isInterface));
}
如您所见,如果asm api版本小于instructions list
,则不会将字节码添加到5
中。背后的原因是什么?
答案 0 :(得分:1)
在Gitlab上的一些历史调查显示,有问题的代码已添加到this commit中,并带有提交消息Added support for invokespecial and invokestatic on interfaces.
Java 8引入了在接口中定义非抽象方法的功能,称为默认方法。在字节码级别,更改的结果是您现在可以使用带有invokespecial
和invokestatic
指令的接口方法以及类方法。
在Java 8之前,生成字节码时,您可以仅通过以下指令确定常量池条目的类型:如果操作码为invokeinterface
,则生成InterfaceMethod
条目,否则生成{ {1}}个条目。在Java 8中,这不再可能,因为Method
和invokespecial
含糊不清,这意味着用户需要能够显式传递该方法是否为接口方法。这意味着他们必须在几乎所有方法api上添加一个额外的参数。
但是,他们不想破坏向后兼容性,这意味着他们需要使用旧签名(即没有itf参数)保留方法。这些方法将转发给新方法,其中invokestatic
的{{1}}指令默认为itf
,否则为true
,这似乎是一个合理的默认值。这就是您在上面看到的超级调用的作用。我不确定为什么要使用API <5开关,但是我怀疑这是为了确保向后兼容性,还是要打破他们方法分配方案中的无限循环。
在旁注中,invokeinterface
在大约8个月前被作为重大代码重组的一部分而删除,因此您不会在ASM的最新版本中看到它。
编辑:我看到您对方法委托感到困惑。这很棘手,因为涉及四种不同的方法。
作为参考,以下是相关代码:
false
:
MethodNode
然后在超类中,就有
MethodNode
在进行更改之前,仅存在没有@Deprecated
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
return;
}
instructions.add(new MethodInsnNode(opcode, owner, name, desc));
}
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
instructions.add(new MethodInsnNode(opcode, owner, name, desc, itf));
}
参数的方法。重载的版本是新的。
如果仔细观察,您会发现所有委托的结果是,当API <5时,无论您调用的是哪种方法,它都会最终调用旧方法。如果调用新方法,它将在委派之前验证@Deprecated
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
if (api >= Opcodes.ASM5) {
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
}
public void visitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
if (api < Opcodes.ASM5) {
if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
throw new IllegalArgumentException(
"INVOKESPECIAL/STATIC on interfaces require ASM 5");
}
visitMethodInsn(opcode, owner, name, desc);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
参数。当API> = 5时,无论您调用的是哪种方法,它都会最终调用新方法。如果您调用旧方法,则它将在委派之前为itf
选择默认值。
因此,它不会忽略方法调用,而只是委托给正确的实现。