Javap输出:差异静态{}和公共{}

时间:2018-03-13 15:00:50

标签: java jvm bytecode bytecode-manipulation jvm-bytecode

我有两个示例类文件,一个来自示例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文件。

1 个答案:

答案 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虚拟机本身调用。