Я думаю, что он должен делать с this part из Jvm спецификации:
Каждый кадр (§2.6) содержит ссылку на время выполнения постоянного пула (§2.5.5) для типа текущий метод поддержки динамической компоновки кода метода. Код файла класса для метода относится к методам, которые должны быть вызваны, и к переменным, к которым можно получить доступ через символические ссылки. Динамическое связывание переводит эти ссылки на символические методы в конкретные ссылки на методы, загружает классы по мере необходимости, чтобы разрешить неопределенные символы, и переводит обращения переменных в соответствующие смещения в структурах хранения, связанных с местоположением этих переменных во время выполнения.
Эта поздняя привязка методов и переменных делает изменения в других классах, которые метод использует менее вероятно, чтобы разбить этот код.
В chapter 5 в Jvm спецификации они также упомянуть: класс или интерфейс C может быть инициализирован, среди прочего, в результате:
исполнения любого одного из Java Virtual Машинные инструкции новые, getstatic, putstatic или invokestatic, которые ссылаются на C (§ новый, §getstatic, §putatic, §invokestatic). Эти инструкции относятся к классу или интерфейсу прямо или косвенно через ссылку на поле или ссылку на метод.
...
При выполнении getstatic, putstatic или invokestatic инструкции, класс или интерфейс, который объявил разрешенное поле или метод инициализации, если он не был инициализирован уже.
Мне кажется, что в первой части документации указано, что любая символическая ссылка просто разрешена и вызывается без учета того, откуда она появилась. Это documentation about method resolution имеет следующие сказать о том, что:
[M] разрешение еню пытается найти ссылочный метод в C и его суперкласса:
Если C декларирует ровно один метод с именем, указанным методом ссылка, а декларация является полиморфным методом подписи (§2.9), затем поиск метода преуспевает. Все имена классов, упомянутые в дескрипторе, разрешаются (§5.4.3.1).
Разрешенный метод - это объявление полиморфного метода подписи. C не нужно объявлять метод с дескриптором, указанным ссылкой на метод.
В противном случае, если C объявляет метод с именем и дескриптором, указанным в ссылке метода, поиск метода преуспевает.
В противном случае, если C имеет суперкласса, шаг 2 разрешения метода рекурсивно вызывается прямой суперкласс C.
Поэтому тот факт, что он вызывается из подкласса, кажется, просто игнорируются. Почему так? В документации, которую вы указали, говорится:
Цель состоит в том, что класс или тип интерфейса имеет набор инициализаторов, которые помещают его в согласованное состояние и что это состояние является первым состоянием, которое наблюдается другими классами ,
В вашем примере вы изменяете состояние Super, когда Sub статически инициализируется. Если инициализация произошла, когда вы вызвали Sub.staticMethod, вы получили бы другое поведение за то, что jvm считает одним и тем же методом. Это может быть несогласованность, которую они говорили об избежании.
Кроме того, вот некоторые из декомпилируемой кода файла класса, который выполняет STATICMETHOD, показывающий использование invokestatic:
Constant pool:
...
#2 = Methodref #18.#19 // Sub.staticMethod:()V
...
Code:
stack=0, locals=1, args_size=1
0: invokestatic #2 // Method Sub.staticMethod:()V
3: return
Вы проверили байт-код? Я предполагаю, что тот же самый байт-код будет сгенерирован, если 'method' вызывает' Sub.staticMethod() 'или' Super.staticMethod() '[если он был общедоступным], что затруднит задачу во время выполнения, статический инициализатор. Впрочем, я не очень хорошо смотрю на байт-код. – ajb
@ajb: Я тоже, но это должно произойти, иначе это не скомпилируется. – Dici
@ajb Байт-код читает '0 invokestatic igb.Sub.staticMethod(): void [22]' или '0 invokestatic igb.Super.staticMethod(): void [22]'. В зависимости от того, какой класс вызывается. –