4

次の2つの違いは何ですか? どちらがより好ましいですか??

public class foo {

    int i = 2;

}

public class foo {

  int i;
    foo() {

        i = 2;

    }
}
4

5 に答える 5

4

あなたの例では、行動セマンティクスに違いはありません。Java では、すべてのインスタンス フィールド初期化子 (およびインスタンス ブロック) は、スーパークラスの初期化の、コンストラクターの本体の前に実行されます。JLS 12.5を参照してください。

違いは、コードの読みやすさと、(他の例では) 繰り返しのコーディングと脆弱性の回避にあります1。これらは、ケースバイケースで評価する必要があります。

コンストラクターで初期化する必要がある場合があることにも注意してください。つまり、初期化がコンストラクターのパラメーターに依存する場合です。


1 - 反復性と脆弱性の問題は、同じことの裏返しです。複数のコンストラクターがある場合、「コンストラクターで初期化する」アプローチは繰り返しにつながる傾向があります。さらにフィールドを追加する場合は、関連するすべてのコンストラクターに初期化を追加する必要があります。すなわち脆弱性。

于 2013-02-25T11:52:02.440 に答える
1

2つ以上のコンストラクターがあり、初期化値がそれぞれ異なる場合は、メンバーの初期化で同じことを行う方法がないため、コンストラクターの初期化を使用する必要があります。

ただし、コンストラクターが1つしかない場合は、メンバーの初期化を使用してコードをわかりやすくすることができます。

于 2013-02-25T11:32:32.393 に答える
0

最初の例では、iはクラスfooのインスタンス変数です(より適切な名前はFooです)。クラスの読み込み時に初期化されます。

2番目の例では、iインスタンス変数ですが、この場合はfoo()コンストラクターで初期化されます。

ここでは、特にプリミティブの場合、実際の違いはありません。

ただし、マルチスレッド環境で、コンストラクターでivarを初期化する予定があり、それらのivarが非プリミティブである場合は、部分的に構築されたオブジェクトを公開するリスクを回避する必要があります。この理由は、コンストラクターが同期されておらず、synchronisedキーワードを適用できないためですが、2つのスレッドが同じオブジェクトを構築することはできません。

したがって、これを回避するthisには、コンストラクターで公開しないでください。そのための1つの方法は、非finalメソッドを呼び出すことです。そうすることで、たとえば抽象メソッドを呼び出すと、未知のコードが未完成のオブジェクトに対して何かを実行できるようになります。明らかに、宣言で初期化する場合、これを行うことはできません。

psこれはEffectiveJavaに何かあると思いましたが、何も見つかりませんでした。

于 2013-02-25T11:32:37.007 に答える
0

まず、2番目の例は次のようになります。

public class foo{

  int i;
  foo(){

     i = 0;

  }

}

Otherwise i is just a local variable in the C'tor scope. Second, the first example shows initialization which is called before the class C'tor is invoked. this is good if you want this to happen no matter what C'tor is used. It also enables you to declare i as readonly.

于 2013-02-25T11:33:26.097 に答える
0

特にこの場合、これら 2 つのバリアントに違いはありません。コンストラクター内のフィールドの初期化は、通常どおり、コンストラクター引数からの外部値を使用するため、最初のバリアントがより望ましいです。

于 2013-02-25T11:34:56.243 に答える