15

私はこのコードを知っています:

Set<String> set = new HashSet<String>() {{
  add("test1");
  add("test2");
}};

本当に:

Set<String> set = new HashSet<String>() {
  {//initializer
    add("test1");
    add("test2");
  }
};

イニシャライザ ブロックは、コンストラクタ ブロックのに実行されています。上記の例では、コンストラクターが実行される前に add("test1") が呼び出されます。このクラスが機能するように、コンストラクターは多くのインスタンス フィールドを初期化している可能性があります。コンストラクターが機能する前に.add()を呼び出すのはなぜですか? 問題となるケースはありますか?

4

4 に答える 4

17

これを説明するために省略した詳細があります。

最初に、初期化手順のステップ 3 から 5 を確認しましょう(要約)。

3. スーパークラス コンストラクターが呼び出される
4. インスタンス初期化子が呼び出される
5. コンストラクターの本体が呼び出される

あなたが省略した詳細は、あなたの式が単にHashSetクラスの新しいインスタンスを作成しているのではなく、実際にはの匿名サブクラスの新しいインスタンスを作成していることですHashSet。(これはセクション 15.9.1で指定されていると思います。)

コンストラクターを宣言していないため、デフォルトのコンストラクターが使用されます。しかしその前に、スーパークラスのコンストラクターHashSetは完了しています。

したがって、要約すると、HashSetコンストラクターは初期化ブロックが実行される前に完了します。

于 2013-01-18T19:04:07.773 に答える
6

この仮定は間違っています:

イニシャライザ ブロックは、コンストラクタ ブロックの前に実行されています。

この特定のケースでは、イニシャライザ ブロックがコンストラクタ ブロックの一部であるためです。

ドキュメントは明確にそれを述べています

Java コンパイラは、イニシャライザ ブロックをすべてのコンストラクタにコピーします。したがって、このアプローチを使用して、複数のコンストラクター間でコードのブロックを共有できます。

静的初期化子と混同していると思います。

于 2013-01-18T18:56:24.467 に答える
4

インスタンス初期化子は、オブジェクトが構築された直後に実行されます。基本的に HashSet のインライン拡張を作成し、それが作成された「直後」に 2 つの項目を追加します。

これは、JMock などのテスト用のモック オブジェクトでよく使用されるパターンですが、他にも便利な使い方があります。

お役に立てれば。

于 2013-01-18T18:59:16.630 に答える
3

アプリケーションのメモリ使用量とパフォーマンスに影響を与える可能性のある無意味なサブクラスを作成するため、これは悪い習慣だと思います。とにかく、スーパークラスのコンストラクターがインスタンス初期化子の前に呼び出されるため、プログラムは正しいです。したがって、イニシャライザが実行されると、HashSetコンストラクタが実行されるため、への呼び出しaddが機能します。

于 2013-01-18T19:00:16.280 に答える