13

Java のアサーションは、テストに追加されたプライベートな合成静的ブール値にコンパイルされます - 提案はここにうまく文書化されています:

JSR アサーション提案

その中で、私たちは作成します

final private static boolean $assertionsEnabled = ClassLoader.desiredAssertionStatus(className);

その後

アサート (X)
になる
if ($assertionsEnabled && !x) { スロー }

これは完全に理にかなっています;)

しかし、実際に得られるのは

public void test1(String s) {
    assert (!s.equals("Fred"));
    System.out.println(s);
}

になる

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());
}

なぜ彼らが肯定的なテストではなく、否定的なテストを行ったのかについての文書を見つけることができません。

私が考えることができる唯一のことは、これがおそらく(おそらく!)より良い分岐予測を生成するということですが、それは私にはかなり不十分な推測のようです.最適化を整理します。

(これはアサーションがどのように機能するかについての質問ではないことに注意してください - 私はそれを知っています! :) )

(余談ですが、これが誤ったチュートリアルにつながることは非常に興味深いことです!このチュートリアルの 6.2.1 は、アサーションに関する以前の SO の質問に応答して誰かが引用したもので、テストの意味が間違っています! :)

何か案は?

4

3 に答える 3

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"));
    }
}

Barのスーパークラスであるため、初期化のBaz前に初期化する必要がありBazます。ただし、その初期化子は、Bazまだ初期化されていないクラスのコンテキストでアサーション ステートメントを実行するため、$assertionsDisabledフィールドを設定する機会がありませんでした。この場合、フィールドにはデフォルト値があり、仕様に従ってすべてが機能します。アサーションが実行されます。フィールドがある$assertionsEnabled場合、初期化されていないクラスのアサーションは実行されないため、仕様に違反します。

于 2019-12-02T04:59:00.460 に答える
2

ブール値は実際には整数で実装されます。ゼロと比較する方が速いという一般的な考えがありますが、有効にする代わりに無効にする理由はわかりません。

私見、偽はブール値のデフォルトであるため、デフォルト値を持つフラグを選択しようとします。false この場合$assertionsEnabled、より理にかなっています。

于 2013-05-31T10:09:42.507 に答える