Как правильно указывает @ Йоахим Зауэр : спецификация JVM налагает меньше ограничений на перегрузку методов в байт-коде, чем JLS на программы Java.
Из спецификации JVM(Раздел 4.6, Методы) :
Ни один из двух методов в одном файле класса не может иметь одинаковое имя и дескриптор (§4.3.3).
И дескриптор метода включает тип возвращаемого значения: ( 4.3.3 Дескрипторы метода )
MethodDescriptor:
( ParameterDescriptor* ) ReturnDescriptor
Методы, которые вы упомянули в вашем вопросе, имеют разные дескрипторы, поэтому они в порядке:
public final void a(ak aa) -> (Lsomepkg1/ak;)V
public final void a(cn ccn) -> (Lsomepkg2/ccn;)V
public final cN a() -> ()Lsomepkg3/cN;
public final void a() -> ()V
public final boolean a() -> ()Z
Это искусно используется обфускаторами.У действительной программы байт-кода больше нет «непосредственно соответствующей» Java-программы. ProGuard делает это, например.Вот фрагмент из их руководства:
-overloadaggressively
Указывает на применение агрессивной перегрузки при запутывании.Несколько полей и методов могут затем получить одинаковые имена, , если их аргументы и возвращаемые типы различны (не только их аргументы) .
Существуют и другие аналогичные методы, использующие дляНапример, инструкция байт-кода jsr
или использование идентификаторов переменных, которые являются зарезервированными словами в языке Java. Здесь - это веб-страница с перечнем нескольких методов.
Чтобы ответить на очевидный дополнительный вопрос: Как JVM узнает, какой метод вызывать на сайте вызова?
В инструкциях invoke вы должны указать ссылку на полную сигнатуру метода (включая возвращаемый тип метода), который должен быть вызван.