我有两个示例类文件,一个来自示例Java应用程序,另一个来自示例C app(使用LLJVM编译为字节码)。
查看他们的输出,我可以通过javap -c -p看到,为了初始化(静态)字段,Java应用程序显示以下块:
static {};
Code:
0: sipush 1339
3: putstatic #7 //Field SRV_ID
etc
如果我理解的话,基本上是<clinit>
方法。或者由我正在使用的VM检测到。
然而,C-app有这个:
public {};
Code:
0: sipush 1339
3: putstatic #7 //Field SRV_ID
etc
这是什么?我的VM没有检测到它。
示例类文件。 第一个来自Java应用程序打印消息并等待20秒,重复。 第二个是大致相同的C应用程序。
http://www.fast-files.com/getfile.aspx?file=156962
http://www.fast-files.com/getfile.aspx?file=156961
这样做的道歉 - 我不会立即知道如何附加文件或有效地显示.class文件。
答案 0 :(得分:5)
这似乎是javap
未考虑的非标准声明。通常,static
初始值设定项将编译为名为<clinit>
且具有static
修饰符的字节码方法。显然,javap
只需打印修饰符的人类可读形式并省略<clinit>
名称即可对其进行解码。
在这里,它遇到了一个名为<clinit>
且具有public
修饰符(无static
修饰符)的方法,并且只是像往常一样,打印修饰符并省略{{1名字。
LLJVM生成的代码似乎依赖于old oddity:
在版本号为51.0或更高版本的
<clinit>
文件中,该方法必须另外设置其class
标志(§4.6)才能成为类或接口初始化方法。此要求是在Java SE 7中引入的。在版本号为50.0或更低版本的类文件中,名为
ACC_STATIC
的方法为void且不带参数的方法被视为类或接口初始化方法无论其<clinit>
标志的设置如何。
对我来说,确实令人惊讶的是,在以前的版本中,ACC_STATIC
修饰符并未强制执行,我认为没有任何理由可以利用这种奇怪性。类初始值设定项(在Java中声明为ACC_STATIC
)应该具有static {}
标志并且我甚至无法想象省略的ACC_STATIC
标志的假定语义,这似乎是很自然的。它意味着应该发生两个奇怪的事情之一,a)尽管没有ACC_STATIC
标志(如果有的话被调用)或者b)它被调用一个必须具有的实例,它在没有实例的情况下被调用被“神奇地”创造。
specification说明了以下任何非标准ACC_STATIC
方法:
<clinit>
文件中名为<clinit>
的其他方法无关紧要。它们不是类或接口初始化方法。它们不能被任何Java虚拟机指令调用,并且永远不会被Java虚拟机本身调用。