4

Java クラスを定義すると、次のようになります。

class A {
   private String str = "init method 1";

   public A() {
       str = "init method 2";
   }
}

str定義時に初期化するか、コンストラクターで初期化できます。私の質問は、2 つの方法の違いは何ですか? どの方法が好まれますか?

4

4 に答える 4

4

初期化ブロックの値は、コンストラクターが割り当てる前に割り当てられます。

したがって、値init member 1は最初に割り当てられ、次にinit member 2割り当てられます。

theJavaGeek のこの例を考えてみましょう

class InitBlocksDemo {

    private String name ;

    InitBlocksDemo(int x) {
        System.out.println("In 1 argument constructor, name = " + this.name);
    }

    InitBlocksDemo() {
        name = "prasad";
        System.out.println("In no argument constructor, name = " + this.name);

    }

    /* First static initialization block */
    static {
        System.out.println("In first static init block ");
    }

    /* First instance initialization block  */
    {
        System.out.println("In first instance init block, name = " + this.name);
    }

    /* Second instance initialization block */
    {
        System.out.println("In second instance init block, name = " + this.name);
    }

    /* Second static initialization block  */
    static {
        System.out.println("In second static int block ");
    }

    public static void main(String args[]) {
        new InitBlocksDemo();
        new InitBlocksDemo();
        new InitBlocksDemo(7);
    }

}

これは、

In first static init block
In second static int block
In first instance init block, name = null
In second instance init block, name = null
In no argument constructor, name = prasad
In first instance init block, name = null
In second instance init block, name = null
In no argument constructor, name = prasad
In first instance init block, name = null
In second instance init block, name = null
In 1 argument constructor, name = null

プログラムの流れは以下の通りです。

  • プログラムの実行が開始されると、クラスInitBlocksDemoが JVM にロードされます。
  • 静的初期化ブロックは、クラスがプログラムに表示される順序でロードされるときに実行されます。
  • 静的ブロックの実行が完了すると、mainメソッドが検出されます。
  • このステートメントnew InitBlocksDemo();により、引数のないコンストラクターが呼び出されます。
  • super引数 のないコンストラクターへのデフォルトの呼び出しがあるため、制御はスーパークラス、つまりObject クラスに移動します
  • 完了すると、制御がクラスに戻り、インスタンス変数にデフォルト値を与え始めます。この場合、変数名には として値が割り当てられますnull
  • インスタンス ブロックは、プログラムに表示される順序で実行されます。name 変数にまだ値を再割り当てしていないため、出力されますnull
  • インスタンス ブロックが実行された後、制御はコンストラクターに渡されます。ここで name = "prasad"; 新しい値を再割り当てするため、「prasad」は引数なしのコンストラクターに出力されます
  • 9. このステートメント new InitBlocksDemo(7); により、引数が 1 つのコンストラクターが呼び出されます。残りのプロセスは同じです。唯一の違いは、名前が新しい値に再割り当てされないため、出力されることですnull
于 2013-07-24T08:13:01.047 に答える
3

違いは、割り当てがいつ行われるかです。コンストラクターが実行される前にフィールドに const 値が割り当てられるため、コンストラクターに次の行を追加すると、次のようになります。

System.out.println(str);

コンストラクターで新しい値を割り当てる前に、古い値がそこにあることがわかります。

それ以外に大きな違いはなく、どちらを使用するかはほとんど個人的な好みです。

個人的には、フィールド宣言の一部として直接割り当てることができるものは何でも - それが私がしていることです。

于 2013-07-24T08:12:54.850 に答える
3

それらの間に違いはありません。コンパイラは初期化ブロックをコンストラクタにコピーします

クラス用に生成されたクラス ファイルを逆コンパイルする場合

class A {
    private String str1 = "init method 1";

    private String str2;

    public A() {
        str2 = "init method 2";
    }

    public A(String str2) {
        str2 = str2;
    }
}

発見できる

class A
{

    private String str1;
    private String str2;

    public A()
    {
        str1 = "init method 1";
        str2 = "init method 2";
    }

    public A(String str2)
    {
        str1 = "init method 1";
        str2 = str2;
    }
}
于 2013-07-24T08:14:17.137 に答える
1

私の個人的な経験では、オブジェクトの初期化がどれほど高価であるか、または詳細であるかがすべてです。第二に、怠惰な作成と能動的な作成とを考えることもできます。コンストラクターのみが関与する場合、通常はインスタンス変数レベルでオブジェクトを作成します。問題のメンバーを初期化するための呼び出しがさらにある場合、呼び出しは確実にコンストラクターまたは初期化が必要なメソッドに移動されます。

そのため、ファクトリ メソッド パターンを使用して、実際のオブジェクトの作成を別のクラスに委譲します。

于 2013-07-24T08:18:25.207 に答える