インスタンス初期化子はコンストラクターとどう違うのですか?


82

言い換えれば、なぜインスタンス初期化子が必要なのですか?コンストラクターに対してインスタンス初期化子を作成することには、どのような違いまたは利点がありますか?


2
インスタンスのイニシャライザーは非常にまれです(二重中括弧のイディオムに熱心な誰かからのコードにぶつからない限り)。
トムホーティン-タックライン2009

回答:


109

これはそれをうまく説明しているようです:

インスタンス初期化子は、次の場合にインスタンス変数初期化子の便利な代替手段です。

  • 初期化コードは例外をキャッチする必要があります、または

  • インスタンス変数の初期化子では表現できない凝った計算を実行します。もちろん、いつでもコンストラクターでそのようなコードを書くことができます。

ただし、複数のコンストラクターを持つクラスでは、各コンストラクターでコードを繰り返す必要があります。インスタンス初期化子を使用すると、コードを1回記述するだけで、オブジェクトの作成に使用されるコンストラクターに関係なく実行されます。インスタンス初期化子は、コンストラクターをまったく宣言できない匿名の内部クラスでも役立ちます。

From:JavaでのJavaWorldオブジェクトの初期化


17
一方、1つのコンストラクターでコードを1回記述し、他のすべてのコンストラクターから呼び出すことができます。しかし、匿名の内部クラスは良い点です。
Tadeusz

11
他のコンストラクターから呼び出すこともできますが、その場合は再び呼び出しを繰り返します。新しいコンストラクターを追加する場合は、そのコンストラクターに呼び出しを追加することを忘れないでください。インスタンス初期化子ではそうではありません。
talonx 2010年

5
@talonx、私は忘却についてのあなたの議論に同意しますが、デフォルトの振る舞いを利用することも同様に危険です。サポーターがレガシーコードのコンストラクターを読んでいるとき、可能なインスタンス初期化子を常にチェックすることを忘れないでしょう。一方、明示的に使用されたinit()は目立ちます。
アサンバー2011

1
@ javamonkey79:クラスのインスタンス初期化子ではなくコンストラクターを選択した場合、インスタンス初期化子が役立つのは匿名クラスを操作するときだけだと言っていますか?
realPK 2014

4
@Assambar init()メソッドでfinalフィールドを割り当てることはできませんが、イニシャライザブロックで割り当てることはできます。
ティモス2014

22

オブジェクトのライフサイクルに関しては、違いはありません。どちらも構築時に呼び出され、論理的には初期化ブロックは構築の一部と見なすことができます。

意味的には、イニシャライザはいくつかの理由で便利なツールです。

初期化子は、初期化される変数の横に初期化ロジックを保持することにより、コードの可読性を向上させることができます。

   public class Universe {
       public int theAnswer;
       {
         int SIX = 6;
         int NINE = 7;
         theAnswer = SIX * NINE;
       }

       // a bunch of other vars
   }

vs

   public class Universe {
       public int theAnswer;

       // a bunch of other vars

       public Universe() {
         int SIX = 6;
         int NINE = 7;
         theAnswer = SIX * NINE;

         // other constructor logic
       }
   }

イニシャライザーは、使用されているコンストラクターに関係なく呼び出されます。

イニシャライザーは、コンストラクターでは使用できない匿名の内部クラスで使用できます。


3
あなたが持っているのは、技術的には「インスタンス初期化子」(クラス内に直接ネストされたブロック)ではなく「インスタンス変数初期化子」です。JLSの第3セクション8.6を参照してください。
トムホーティン-タックライン2009

インスタンス初期化ブロックには、ここに示すような名前がありません。そうですね。インスタンス初期化コードに名前を付けましたtheAnswer。あれは正しいですか?または私は何かが欠けています。
RBT 2016

1
@RBTtheAnswerは、宣言されたインスタンス変数です。匿名の初期化ブロックで初期化されます。変数宣言の後のセミコロンに注意してください。
ykaganovich 2016

10

コンストラクターが多数あり、コンストラクターごとに共通のコードを実行する場合は、インスタンス初期化子を使用できます。これは、すべてのコンストラクターに対して呼び出されるためです。


4

私は一般的にインスタンス初期化イディオムを避けます-それが変数初期化子に対して与える唯一の本当の利点は例外処理です。

また、initメソッド(コンストラクターから呼び出し可能)も例外処理を実行でき、コンストラクターのセットアップコードを一元化できますが、コンストラクターのパラメーター値を操作できるという利点があるため、インスタンス初期化子は冗長であると言えます。避けた。


1
すべてのコンストラクターでinitメソッドを手動で呼び出す必要があります。
ステファン

2
@Alex良い点ですが、複数のコンストラクターを持つほとんどのクラスは共通のロジックを持っているため、とにかくお互いを呼び出す傾向があります。少なくとも私のクラスのほとんどでは。
CPerkins 2013年

3

コンストラクターに対するインスタンス初期化子本当の利点は、匿名の内部クラスを使用するときに見られます。

匿名の内部クラスは(匿名である ためコンストラクターを持つことができないため、インスタンス初期化子に非常に自然に適合します


1

オブジェクト作成時にインスタンス変数の初期化を実行する場合は、コンストラクターを選択する必要があります。オブジェクト作成時にアクティビティを実行する場合は、初期化アクティビティ以外に、インスタンスブロックを実行する必要があります。

コンストラクターは引数を取ることができますが、インスタンスブロックは引数を取ることができないため、コンストラクターをインスタンスブロックに置き換えることはできません。

クラスには複数のコンストラクターを含めることができるため、インスタンスブロックをコンストラクターで置き換えることはできません。インスタンスブロックをコンストラクターに置き換えたい場合は、すべてのコンストラクターでインスタンスブロックコードを作成する必要があります。これは、実行時にどのコンストラクターが呼び出されるかを予期できないため、重複コードが不必要に増えるためです。

例:

class MyClass{

    static int object_count = 0;

    MyClass(){
        object_count++;
    }

    MyClass(int i){

        object_count++;
    }

    void getCount() {

        System.out.println(object_count);
    }

    public static void main(String... args) {
        MyClass one = new MyClass();
        MyClass two = new MyClass(2);
        two.getCount();
    }
}

出力: 2

class MyClass{

    static int object_count = 0;

    {
        object_count++;
    }

    MyClass(){

    }

    MyClass(int i){     

    }

    void getCount() {

        System.out.println(object_count);
    }

    public static void main(String... args) {
        MyClass one = new MyClass();
        MyClass two = new MyClass(2);
        two.getCount();
    }
}

出力: 2


0

イニシャライザーはコンストラクター間でコードを共有する方法であり、イニシャライザーを変数宣言とともに使用すると、コードが読みやすくなります。

Javaコンパイラは、初期化ブロックをすべてのコンストラクタにコピーします。したがって、このアプローチを使用して、複数のコンストラクター間でコードのブロックを共有できます。 Oracleのドキュメント

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.