lab*_*b27 13 java assert decompiler
java 中的断言编译为添加到测试中的私有合成静态布尔值 - 该提案在这里有很好的记录:
在其中,我们创建
最终私有静态布尔值$assertionsEnabled = ClassLoader.desiredAssertionStatus(className);
进而
断言(X)变成
if ($assertionsEnabled && !x) { throw }
这完全有道理;)
但是,我注意到我实际得到的是
public void test1(String s) {
assert (!s.equals("Fred"));
System.out.println(s);
}
Run Code Online (Sandbox Code Playgroud)
变成
static final /* synthetic */ boolean $assertionsDisabled;
public void test1(String s) {
if ((!(AssertTest.$assertionsDisabled)) && (s.equals("Fred"))) {
throw new AssertionError();
}
System.out.println(s);
}
static {
AssertTest.$assertionsDisabled = !(AssertTest.class.desiredAssertionStatus());
}
Run Code Online (Sandbox Code Playgroud)
我找不到任何关于他们为什么进行否定测试而不是肯定测试的文档 - 即原始提案捕获了 assertionsENABLED,现在我们使用 assertionsDISABLED。
我唯一能想到的是这可能(可能!)产生更好的分支预测,但这对我来说似乎是一个非常蹩脚的猜测 - Java 哲学(几乎)总是使字节码简单,并让 JIT整理优化。
(请注意,这不是关于断言如何工作的问题 - 我知道!:))
(顺便说一句,很有趣的是,这会导致不正确的教程!本教程的6.2.1 ,有人在回答之前关于断言的 SO 问题时引用了该内容,从而导致测试错误!:)
有任何想法吗?
Tag*_*eev 20
这实际上是有原因的,不仅仅是为了更紧凑的字节码或更快的条件执行。如果您查看Java 语言规范第 14.10 节,您将看到以下注释:
启用在其类或接口完成初始化之前执行的 assert 语句。
还有一个包含初始化循环的示例:
class Bar {
static {
Baz.testAsserts();
// Will execute before Baz is initialized!
}
}
class Baz extends Bar {
static void testAsserts() {
boolean enabled = false;
assert enabled = true;
System.out.println("Asserts " +
(enabled ? "enabled" : "disabled"));
}
}
Run Code Online (Sandbox Code Playgroud)
作为Bar的超类Baz,它必须在初始化之前进行Baz初始化。但是,它的初始化程序在Baz尚未初始化的类的上下文中执行断言语句,因此没有机会设置该$assertionsDisabled字段。在这种情况下,该字段具有其默认值,并且一切都按照规范进行:执行断言。如果我们有一个$assertionsEnabled字段,则不会执行未初始化类的断言,因此它会违反规范。
布尔值实际上是用整数实现的。人们普遍认为与零比较更快,但我看不出有任何理由使用禁用而不是启用。
恕我直言,因为 false 是布尔值的默认值,所以我尝试选择一个默认值为 的标志false 在这种情况下$assertionsEnabled会更有意义。
| 归档时间: |
|
| 查看次数: |
2741 次 |
| 最近记录: |