Некоторое изучение истории на Gitlab показывает, что рассматриваемый код был добавлен в this commit , с сообщением commit Added support for invokespecial and invokestatic on interfaces.
В Java 8 появилась возможность определять неабстрактные методы в интерфейсах, известные как методы по умолчанию. На уровне байт-кода эффект изменения состоит в том, что теперь вы можете использовать методы интерфейса, а также методы класса с инструкциями invokespecial
и invokestatic
.
До Java 8 при генерации байт-кода вы могли определить тип записи постоянного пула просто по инструкции: если код операции равен invokeinterface
, сгенерируйте запись InterfaceMethod
, в противном случае сгенерируйте запись Method
. В Java 8 это больше невозможно, поскольку invokespecial
и invokestatic
неоднозначны, что означает, что пользователь должен иметь возможность явно передавать, является ли метод интерфейсным методом или нет. Это означает, что им пришлось добавить дополнительный параметр практически ко всем методам apis.
Однако они не хотели нарушать обратную совместимость, а это значит, что им нужно сохранять методы со старой подписью (т. Е. Без параметра itf). Эти методы переадресовывают на новые, с itf
по умолчанию true
для invokeinterface
инструкций и false
в противном случае, что кажется разумным значением по умолчанию. Это то, что делает суперзвезда, которую вы видите выше. Я не уверен, почему здесь есть переключатель API <5, но я подозреваю, что это либо для обеспечения обратной совместимости, либо для прерывания бесконечного цикла в их схеме диспетчеризации методов. </p>
В дополнение к этому, MethodNode
был удален около 8 месяцев назад как часть крупной реорганизации кода, поэтому вы не увидите его в самой последней версии ASM.
Редактировать: Я вижу, что вы не уверены в делегировании метода. Это довольно сложно, поскольку здесь задействованы четыре различных метода.
Для справки приведен код:
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));
}
А потом в суперклассе есть
@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);
}
}
До изменения существовали только методы без параметра itf
. Перегруженные версии новые.
Если вы посмотрите внимательно, вы увидите, что эффект от всего делегирования заключается в том, что, когда API <5, он в конечном итоге вызывает старый метод, независимо от того, какой из двух вы вызываете. Если вы вызовете новый метод, он проверит параметр <code>itf перед делегированием. Когда API> = 5, он будет вызывать новый метод, независимо от того, какой из двух вы вызываете. Если вы вызовете старый метод, он будет выбирать значение по умолчанию для itf
перед делегированием.
Так что это не игнорирование вызова метода, это просто делегирование правильной реализации.