正如其他人所说,在 Java 中是非法的,但在字节码中是合法的。
javac 断言
assert
是一个 Java 示例,它在 Oracle JDK 1.8.0_45 中生成多个名称相同但类型不同的字段。例如:
public class Assert {
// We can't use a primitive like int here or it would get inlined.
static final int[] $assertionsDisabled = new int[0];
public static void main(String[] args) {
System.out.println($assertionsDisabled.length);
// currentTimeMillis so it won't get optimized away.
assert System.currentTimeMillis() == 0L;
}
}
的存在会assert
生成bool $assertionsDisable
一个合成字段来缓存方法调用,有关详细信息,请参见:https ://stackoverflow.com/a/29439538/895245 。
然后:
javac Assert.java
javap -c -constants -private -verbose Assert.class
包含以下行:
#3 = Fieldref #9.#28 // Assert.$assertionsDisabled:[I
#5 = Fieldref #9.#31 // Assert.$assertionsDisabled:Z
#12 = Utf8 $assertionsDisabled
#28 = NameAndType #12:#13 // $assertionsDisabled:[I
#31 = NameAndType #12:#14 // $assertionsDisabled:Z
public static void main(java.lang.String[]);
3: getstatic #3 // Field $assertionsDisabled:[I
10: getstatic #5 // Field $assertionsDisabled:Z
请注意常量表是如何重用#12
作为变量名的。
但是,如果我们声明了另一个布尔值,它将无法编译:
static final boolean $assertionsDisabled = false;
有错误:
the symbol $assertionsDisabled conflicts with a compile synthesized symbol
这也是为什么使用带有美元符号的字段名称是一个非常糟糕的主意:我什么时候应该在变量名中使用美元符号 ($)?
茉莉
当然,我们也可以用 Jasmin 试试看:
.class public FieldOverload
.super java/lang/Object
.field static f I
.field static f F
.method public static main([Ljava/lang/String;)V
.limit stack 2
ldc 1
putstatic FieldOverload/f I
ldc 1.5
putstatic FieldOverload/f F
getstatic java/lang/System/out Ljava/io/PrintStream;
getstatic FieldOverload/f I
invokevirtual java/io/PrintStream/println(I)V
getstatic java/lang/System/out Ljava/io/PrintStream;
getstatic FieldOverload/f F
invokevirtual java/io/PrintStream/println(F)V
return
.end method
其中包含两个静态字段,一个int
( I
) 和一个float
( F
),并输出:
1
1.5
如果有效,因为:
getstatic
指向Fieldref
常量表上的结构
Fieldref
指向一个NameAndType
NameAndType
显然指向类型
因此,为了区分它们,Jasmin 只是使用了两种不同Fieldref
的类型。