Javap 输出:区别 static {} 和 public {}

Javap output: difference static {} and public {}

我有两个示例 class 文件,一个来自示例 Java 应用程序,一个来自示例 C 应用程序(使用 LLJVM 编译为字节码)。

查看它们的输出,我可以通过 javap -c -p 看到用于初始化(静态)字段的 Java 应用程序显示以下块:

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

这是什么?我的虚拟机没有检测到它。

示例 class 文件。 第一个来自 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 生成的代码似乎依赖于 old oddity:

In a class file whose version number is 51.0 or above, the method must additionally have its ACC_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 its ACC_STATIC flag.

对我来说,读到在以前的版本中 ACC_STATIC 修饰符不是强制性的,我真的很惊讶,我看不出有任何理由去利用这个奇怪的地方。 class 初始化器(在 Java 中声明为 static {})应该有 ACC_STATIC 标志似乎很自然,我什至无法想象省略的假定语义ACC_STATIC 标志。这意味着应该发生两件奇怪的事情之一,a)尽管没有 ACC_STATIC 标志(被调用 as-if 有它),但它在没有实例的情况下被调用,或者 b)它被一个实例调用一定是“神奇地”创造出来的。

specification 对任何 non-standard <clinit> 方法的说明如下:

Other methods named <clinit> in a class 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.