У меня есть два примера файлов классов, один из примера приложения 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.




Кажется, это нестандартное заявление, которое javap не учел. Обычно инициализаторы static компилируются в методы байт-кода с именем <clinit>, имеющие модификатор static. Очевидно, javap декодирует их, просто распечатав удобочитаемую форму модификатора и опуская имя <clinit>.
Здесь он обнаружил метод с именем <clinit>, имеющий модификатор public (без модификатора static), и сделал то же самое, что и обычно, распечатав модификатор и опустив имя <clinit>.
Код, сгенерированный LLJVM, похоже, полагается на старая диковинка:
In a
classfile whose version number is 51.0 or above, the method must additionally have itsACC_STATICflag (§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 itsACC_STATICflag.
Для меня было действительно удивительно узнать, что в предыдущих версиях модификатор ACC_STATIC не был обязательным, и я не вижу причин использовать эту странность. Кажется очень естественным, что инициализатор класса (который объявлен в Java как static {}) должен иметь флаг ACC_STATIC, и я даже не могу представить предполагаемую семантику пропущенного флага ACC_STATIC. Это означает, что должно произойти одно из двух странных событий: а) он вызывается без экземпляра, несмотря на то, что у него нет флага ACC_STATIC (вызывается, как если бы он был), или б) он вызывается с экземпляром, который должен быть создан «волшебным образом». ».
Технические характеристики говорит следующее о любом нестандартном методе <clinit>:
Other methods named
<clinit>in aclassfile 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.
Спасибо за подробное объяснение. На будущее: способ решить эту проблему - скомпилировать приложение C в файл jasmin вместо байт-кода. Затем файл Jasmin можно отредактировать, заменив приведенный выше public {} на static {}. Когда Jasmin затем преобразуется в байт-код, он, похоже, дает стандартный, обнаруживаемый метод клиницизма.
Не могли бы вы привести более конкретные примеры? Мне сложно понять, почему в вашем коде есть пустые блоки инициализатора статического класса.