我有两个示例类文件,一个来自示例 Java 应用程序,一个来自示例 C 应用程序(使用 LLJVM 编译为字节码)。
查看它们的输出,我可以通过 javap -c -p 看到用于初始化(静态)字段的 Java 应用程序显示以下 block :
static {};
Code:
0: sipush 1339
3: putstatic #7 //Field SRV_ID
etc
这基本上是 <clinit>
方法,如果我理解的话。或者被我正在使用的虚拟机检测到。
但是 C-app 有这个:
public {};
Code:
0: sipush 1339
3: putstatic #7 //Field SRV_ID
etc
这是什么?我的 VM 没有检测到它。
示例类文件。 第一个来自打印消息并等待 20 秒的 Java 应用程序,重复。 第二个是功能大致相同的 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 生成的代码似乎依赖于 old oddity :
In a
class
file whose version number is 51.0 or above, the method must additionally have itsACC_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 itsACC_STATIC
flag.
对我来说,在以前的版本中看到 ACC_STATIC
确实令人惊讶。修饰符不是强制性的,我看不出有任何理由利用这种奇怪之处。类初始值设定项(在 Java 中声明为 static {}
)应该具有 ACC_STATIC
似乎很自然。标志,我什至无法想象省略的 ACC_STATIC
的假定语义旗帜。这意味着应该发生两件奇怪的事情之一,a)尽管没有 ACC_STATIC
,但它在没有实例的情况下被调用。标志(被调用就像拥有它一样)或 b)它被一个必须“神奇地”创建的实例调用。
specification关于任何非标准 <clinit>
的说明如下方法:
Other methods named
<clinit>
in aclass
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.
关于Javap 输出 : difference static {} and public {},我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49259422/