我有两个示例类文件,一个来自示例Java应用程序,一个来自示例C应用程序(使用LLJVM编译为字节码)。
查看它们的输出,我可以通过javap -c -p看到,对于初始化(静态)字段,Java应用程序显示了以下块:
static {};
Code:
0: sipush 1339
3: putstatic #7 //Field SRV_ID
etc这基本上就是<clinit>方法,如果我理解的话。或者被我正在使用的VM检测到。
然而,C-应用程序有这样的功能:
public {};
Code:
0: sipush 1339
3: putstatic #7 //Field SRV_ID
etc这是什么?我的VM没有检测到它。
示例类文件。第一个是来自Java的THe,它打印一条消息,等待20多个,重复。第二个是一个C应用程序,它的功能大致相同。
http://www.fast-files.com/getfile.aspx?file=156962
http://www.fast-files.com/getfile.aspx?file=156961
很抱歉这样做-我不知道如何立即附加文件或有效地显示.class文件。
发布于 2018-03-14 09:37:58
这似乎是javap没有考虑的非标准声明。通常,static初始化器被编译为具有static修饰符的名为<clinit>的字节码方法。显然,javap只是通过打印修饰符的人类可读的形式和省略<clinit>名称来解码它们。
在这里,它遇到了一个名为<clinit>的方法,它有public修饰符(没有static修饰符),并且和往常一样,打印修饰符并省略了<clinit>名称。
LLJVM生成的代码似乎依赖于旧奇。
在版本号为51.0或以上的
class文件中,该方法必须另外设置其ACC_STATIC标志(§4.6),才能成为类或接口初始化方法。 这个要求是在Java 7中引入的。在版本号为50.0或以下的类文件中,一个名为<clinit>的方法无效且不带任何参数,不管它的ACC_STATIC标志的设置如何,它都被视为类或接口初始化方法。
对我来说,在以前的版本中,ACC_STATIC修饰符并没有被强制使用,我看不出有什么理由去利用这个奇怪的地方。类初始化器(在Java中声明为static {} )应该具有ACC_STATIC标志,这是非常自然的,我甚至无法想象省略ACC_STATIC标志的假定语义。这意味着应该发生两种奇怪的事情之一:( a)它是在没有实例的情况下调用的,尽管它没有ACC_STATIC标志(如果调用它的话)或( b)它是用一个必须是“神奇”创建的实例调用的。
规格说明对任何非标准的<clinit>方法都做了如下说明:
在一个
<clinit>文件中名为class的其他方法没有任何意义。它们不是类或接口初始化方法。任何Java虚拟机指令都不能调用它们,Java虚拟机本身也不会调用它们。
https://stackoverflow.com/questions/49259422
复制相似问题