Вывод Javap: разница статическая {} и общедоступная {}

У меня есть два примера файлов классов, один из примера приложения Java и один из примера приложения C (скомпилированный в байт-код с использованием LLJVM).

Глядя на их результаты, я вижу через javap -c -p, что для инициализации (статических) полей приложение Java показывает следующий блок:

static {};
Code: 
0: sipush 1339
3: putstatic   #7     //Field SRV_ID
etc

Если я понимаю, это в основном метод <clinit>. Или обнаружен как таковой на виртуальной машине, которую я использую.

Однако в C-приложении есть следующее:

public {};
Code: 
0: sipush 1339
3: putstatic   #7     //Field SRV_ID
etc

Что это? Моя виртуальная машина его не обнаруживает.

Примеры файлов классов. Первый - из приложения Java, которое печатает сообщение и ждет 20 секунд, повторите. Второе - приложение C, которое делает примерно то же самое.

http://www.fast-files.com/getfile.aspx?file=156962

http://www.fast-files.com/getfile.aspx?file=156961

Приношу свои извинения за то, что сделал это таким образом - я не сразу знаю, как прикреплять файлы или эффективно отображать файлы .class.

Не могли бы вы привести более конкретные примеры? Мне сложно понять, почему в вашем коде есть пустые блоки инициализатора статического класса.

M. Prokhorov 13.03.2018 16:32
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
8
1
344
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Кажется, это нестандартное заявление, которое javap не учел. Обычно инициализаторы static компилируются в методы байт-кода с именем <clinit>, имеющие модификатор static. Очевидно, javap декодирует их, просто распечатав удобочитаемую форму модификатора и опуская имя <clinit>.

Здесь он обнаружил метод с именем <clinit>, имеющий модификатор public (без модификатора static), и сделал то же самое, что и обычно, распечатав модификатор и опустив имя <clinit>.

Код, сгенерированный LLJVM, похоже, полагается на старая диковинка:

In a class file whose version number is 51.0 or above, the method must additionally have its ACC_STATIC flag (§4.6) set in order to be the class or interface initialization method.

This requirement was introduced in Java SE 7. In a class file whose version number is 50.0 or below, a method named <clinit> that is void and takes no arguments is considered the class or interface initialization method regardless of the setting of its ACC_STATIC flag.

Для меня было действительно удивительно узнать, что в предыдущих версиях модификатор ACC_STATIC не был обязательным, и я не вижу причин использовать эту странность. Кажется очень естественным, что инициализатор класса (который объявлен в Java как static {}) должен иметь флаг ACC_STATIC, и я даже не могу представить предполагаемую семантику пропущенного флага ACC_STATIC. Это означает, что должно произойти одно из двух странных событий: а) он вызывается без экземпляра, несмотря на то, что у него нет флага ACC_STATIC (вызывается, как если бы он был), или б) он вызывается с экземпляром, который должен быть создан «волшебным образом». ».

Технические характеристики говорит следующее о любом нестандартном методе <clinit>:

Other methods named <clinit> in a class file are of no consequence. They are not class or interface initialization methods. They cannot be invoked by any Java Virtual Machine instruction and are never invoked by the Java Virtual Machine itself.

Это была ошибка JVM JDK-6845426, исправленная в JDK 7. Я не думаю, что lljvm использовал ее намеренно, вероятно, они просто забыли добавить ACC_STATIC, и проблема не была замечена, пока JVM принимала такие классы. Похоже, что разработка lljvm прекратилась в 2010 году, еще до выпуска Java 7.

apangin 14.03.2018 12:56

Спасибо за подробное объяснение. На будущее: способ решить эту проблему - скомпилировать приложение C в файл jasmin вместо байт-кода. Затем файл Jasmin можно отредактировать, заменив приведенный выше public {} на static {}. Когда Jasmin затем преобразуется в байт-код, он, похоже, дает стандартный, обнаруживаемый метод клиницизма.

Sven 14.03.2018 13:31

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