Может ли внутренний класс Java иметь статическую инициализацию в байт-коде?

Это НЕ тот же вопрос, что и: Почему внутренний класс не может использовать статический инициализатор? или другие подобные, поскольку они не связаны с семантикой языка Java и относятся исключительно к байт-коду и формату файла класса/поведению JVM.

Я переписываю байт-код, включая добавление синтетических статических полей в классы. Мне было интересно, позволяет ли спецификация JVM/байт-кода добавлять статические поля и метод <clinit> во внутренний класс или нет? Пока ни на что не жаловался, но я не хочу полагаться на что-то, характеристики чего я не могу указать.

В противном случае это расстраивает, поскольку мне пришлось бы подойти к ближайшему родительскому классу, не являющемуся внутренним, и добавить туда поля (за исключением того, что я преобразую один файл класса за раз, так что это становится неловко).

Вы уверены, что можете. Ограничение на то, что внутренние классы не могут иметь статические инициализаторы, уже снято в современных версиях Java.

Sweeper 29.04.2024 14:10

"это не связано с семантикой языка Java" - согласен, но зачем тогда тег java? (из его описания: «Используйте этот тег, когда у вас возникают проблемы с использованием или пониманием самого языка». ||| и на этот вопрос в большинстве случаев лучше ответить путем тестирования (самого себя — вы знаете и, вероятно, имеете контекст/фреймворк/.. .)

user85421 29.04.2024 14:15

Честная оценка. Думаю, я просто ожидал, что тег Java соберет самую большую аудиторию опытных людей (большинство людей, знающих вещи JBC/JVM, тоже владеют языком Java, но это не наоборот, так что достаточно справедливо).

David 29.04.2024 14:24

@Sweeper Спасибо, приятно это знать. Я не думаю, что у вас где-нибудь есть ссылка на часть спецификации? Я тоже могу попробовать поискать еще раз (особенно теперь кажется, что это должно быть где-то явно указано).

David 29.04.2024 14:26

@David Вот ссылка на Спецификации Java Возможно, она не содержит того, что вы ищете, но это хорошая ссылка.

WJS 29.04.2024 14:31

@David Нет никакой «части спецификации», которая бы об этом говорила, потому что ограничение было снято. Вы можете сравнить раздел 8.1.3 новейшей спецификации с тем же разделом спецификации Java 7. Тем не менее, я не думаю, что это когда-либо было ограничением на уровне JVM.

Sweeper 29.04.2024 14:31

Да, я подозревал, что не смогу его найти просто потому, что (на уровне виртуальной машины) это никогда не было ограничением. Спасибо!

David 29.04.2024 14:39
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
7
71
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ: Почти наверняка да.

От @Sweeper:

Вы уверены, что можете. Ограничение, заключающееся в том, что внутренние классы не могут иметь статические инициализаторы уже удалены в современных версиях Java.

Хотя на данный момент мы не можем найти явного упоминания об этом в спецификации, но, вероятно, потому, что это никогда не было ограничением на уровне виртуальной машины.

Ответ принят как подходящий

Когда в Java 1.1 были представлены внутренние классы, формат байт-кода не был изменен. Другими словами, внутренние классы — это просто классы, подобные классам верхнего уровня, за исключением специального атрибута , описывающего отношения, который используется компиляторами и Reflection, но игнорируется JVM. Обратите внимание, что в связанном разделе спецификации даже прямо сказано:

Реализация виртуальной машины Java Oracle не проверяет согласованность атрибута InnerClasses с файлом class, представляющим класс или интерфейс, на который ссылается этот атрибут.

Таким образом, атрибут не только не влияет на фактическое выполнение, но и JVM даже не будет проверять достоверность содержащейся информации.

Возможность вложенных классов получать доступ к членам друг друга private была синтаксическим сахаром до Java 11, реализованная компилятором путем вставки синтетических вспомогательных методов. В Java 11 представлены новые атрибуты, обеспечивающие настоящий доступ без таких вспомогательных методов, однако эта функция отличается от внутренних классов уровня исходного кода Java.

Короче говоря, поскольку для внутренних классов на уровне байт-кода нет специальных правил, для внутренних классов разрешен метод <clinit>.

Другие вопросы по теме