assert 声明 JDK 1.8 案例研究
assert 语句是在 Oracle JDK 1.8.0_45 中生成 static synthetic 字段的构造示例:
public class Assert {
public static void main(String[] args) {
assert System.currentTimeMillis() == 0L;
}
}
基本上编译成:
public class Assert {
// This field is synthetic.
static final boolean $assertionsDisabled =
!Assert.class.desiredAssertionStatus();
public static void main(String[] args) {
if (!$assertionsDisabled) {
if (System.currentTimeMillis() != 0L) {
throw new AssertionError();
}
}
}
}
这可以通过以下方式验证:
javac Assert.java
javap -c -constants -private -verbose Assert.class
其中包含:
static final boolean $assertionsDisabled;
descriptor: Z
flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
生成合成字段,Java 只需在加载时调用一次Assert.class.desiredAssertionStatus(),然后将结果缓存在那里。
另请参阅:https://stackoverflow.com/a/29439538/895245 以获得更详细的说明。
请注意,此合成字段可能会与我们可能定义的其他字段产生名称冲突。例如,以下在 Oracle JDK 1.8.0_45 上编译失败:
public class Assert {
static final boolean $assertionsDisabled = false;
public static void main(String[] args) {
assert System.currentTimeMillis() == 0L;
}
}
唯一能“防止”的就是在标识符上不使用美元的命名约定。另见:When should I use the dollar symbol ($) in a variable name?
奖金:
static final int $assertionsDisabled = 0;
会起作用,因为与 Java 不同,字节码允许多个具有相同名称但类型不同的字段:Variables having same name but different type