Это НЕ тот же вопрос, что и: Почему внутренний класс не может использовать статический инициализатор? или другие подобные, поскольку они не связаны с семантикой языка Java и относятся исключительно к байт-коду и формату файла класса/поведению JVM.
Я переписываю байт-код, включая добавление синтетических статических полей в классы. Мне было интересно, позволяет ли спецификация JVM/байт-кода добавлять статические поля и метод <clinit>
во внутренний класс или нет? Пока ни на что не жаловался, но я не хочу полагаться на что-то, характеристики чего я не могу указать.
В противном случае это расстраивает, поскольку мне пришлось бы подойти к ближайшему родительскому классу, не являющемуся внутренним, и добавить туда поля (за исключением того, что я преобразую один файл класса за раз, так что это становится неловко).
"это не связано с семантикой языка Java" - согласен, но зачем тогда тег java? (из его описания: «Используйте этот тег, когда у вас возникают проблемы с использованием или пониманием самого языка». ||| и на этот вопрос в большинстве случаев лучше ответить путем тестирования (самого себя — вы знаете и, вероятно, имеете контекст/фреймворк/.. .)
Честная оценка. Думаю, я просто ожидал, что тег Java соберет самую большую аудиторию опытных людей (большинство людей, знающих вещи JBC/JVM, тоже владеют языком Java, но это не наоборот, так что достаточно справедливо).
@Sweeper Спасибо, приятно это знать. Я не думаю, что у вас где-нибудь есть ссылка на часть спецификации? Я тоже могу попробовать поискать еще раз (особенно теперь кажется, что это должно быть где-то явно указано).
@David Вот ссылка на Спецификации Java Возможно, она не содержит того, что вы ищете, но это хорошая ссылка.
@David Нет никакой «части спецификации», которая бы об этом говорила, потому что ограничение было снято. Вы можете сравнить раздел 8.1.3 новейшей спецификации с тем же разделом спецификации Java 7. Тем не менее, я не думаю, что это когда-либо было ограничением на уровне JVM.
Да, я подозревал, что не смогу его найти просто потому, что (на уровне виртуальной машины) это никогда не было ограничением. Спасибо!
Ответ: Почти наверняка да.
От @Sweeper:
Вы уверены, что можете. Ограничение, заключающееся в том, что внутренние классы не могут иметь статические инициализаторы уже удалены в современных версиях Java.
Хотя на данный момент мы не можем найти явного упоминания об этом в спецификации, но, вероятно, потому, что это никогда не было ограничением на уровне виртуальной машины.
Когда в Java 1.1 были представлены внутренние классы, формат байт-кода не был изменен. Другими словами, внутренние классы — это просто классы, подобные классам верхнего уровня, за исключением специального атрибута , описывающего отношения, который используется компиляторами и Reflection, но игнорируется JVM. Обратите внимание, что в связанном разделе спецификации даже прямо сказано:
Реализация виртуальной машины Java Oracle не проверяет согласованность атрибута
InnerClasses
с файломclass
, представляющим класс или интерфейс, на который ссылается этот атрибут.
Таким образом, атрибут не только не влияет на фактическое выполнение, но и JVM даже не будет проверять достоверность содержащейся информации.
Возможность вложенных классов получать доступ к членам друг друга private
была синтаксическим сахаром до Java 11, реализованная компилятором путем вставки синтетических вспомогательных методов. В Java 11 представлены новые атрибуты, обеспечивающие настоящий доступ без таких вспомогательных методов, однако эта функция отличается от внутренних классов уровня исходного кода Java.
Короче говоря, поскольку для внутренних классов на уровне байт-кода нет специальных правил, для внутренних классов разрешен метод <clinit>
.
Вы уверены, что можете. Ограничение на то, что внутренние классы не могут иметь статические инициализаторы, уже снято в современных версиях Java.