2013-02-15 5 views
12

私は2つのコンストラクタのうちの1つを使用してインスタンス化できる多くの最終メンバーを持つクラスを持っています。コンストラクタは、第3のコンストラクタに格納されているコードを共有します。Javaの最終フィールドを初期化する

// SubTypeOne and SubTypeTwo both extend SuperType 

public class MyClass { 
    private final SomeType one; 
    private final SuperType two; 


    private MyClass(SomeType commonArg) { 
     one = commonArg; 
    } 

    public MyClass(SomeType commonArg, int intIn) { 
     this(commonArg); 

     two = new SubTypeOne(intIn); 
    } 

    public MyClass(SomeType commonArg, String stringIn) { 
     this(commonArg); 

     two = new SubTypeTwo(stringIn); 
    } 

問題は、このコードはコンパイルできないということです:Variable 'two' might not have been initialized.誰かが、おそらくMyClassの内側からの最初のコンストラクタを呼び出すことができますし、新しいオブジェクトには、「2」のフィールドが設定されていないだろう。

この場合、コンストラクタ間でコードを共有するにはどうすればよいでしょうか?通常はヘルパーメソッドを使用しますが、共有コードはコンストラクタからのみ実行できる最終変数を設定できる必要があります。

+3

それは、現在あなたが2つの*同じ*コンストラクタ(同じパラメータ、同じボディを)持っているあなたの質問を理解するのは難しいです。より代表的になるように修正できますか? –

+2

最初のコンストラクタでは、2つが初期化されません。 –

+5

@Jon Skeet - もう一度見てください。パラメータの種類は異なります。 –

答えて

16

これはいかがですか?あなたがMyClass(SomeType oneIn)と呼ばれていた場合、twoが初期化されていないため、このエラーが出る

public class MyClass { 

    private final SomeType one; 
    private final SuperType two; 

    public MyClass (SomeType commonArg, int intIn) { 
     this(commonArg, new SubTypeOne(intIn)); 
    } 

    public MyClass (SomeType commonArg, String stringIn) { 
     this(commonArg, new SubTypeTwo(stringIn)); 
    } 

    private MyClass (SomeType commonArg, SuperType twoIn) { 
     one = commonArg; 
     two = twoIn; 
    } 
} 
+0

ああ、それは私のせいです。私は私の例を少しばかり乱しました。私が今書いた方法をチェックしてください。しかし、あなたは私に、両方のコンストラクタをSuperTypeを取るものに組み合わせ、呼び出し元が実際に呼び出す前にSuperTypeオブジェクトを構築させる考えを与えました。私は、呼び出しが発生した場所でSuperTypeを表示させたくないが、それは私が考えることができる最高のものだ。 –

+0

理解しやすい。これはどう? 'SuperType'のサブクラスを許さず、複製を避け、常に両方の変数に割り当てます。注意してください。あいまいさを避けるために 'null'にキャストしてください。 https://gist.github.com/stickyd/4965120 –

2

「2」が初期化されていることを確認するだけです。最初のコンストラクタでは、ちょうど追加:

two = null; 

をあなただけの最初のコンストラクタが呼び出された場合に、それを与えるしたいのですが、いくつかの他の値がありますしない限り。

+2

しかし、「two」が最終です。 –

+0

最終変数をnullに初期化できます。 * something *に初期化する必要があります。 2つがnull以外の値を持つようにするには、他のコンストラクターの1つを呼び出す必要があります。スティッキーの答えと同じ最終結果を持っています。 – Halogen

+1

しかし、最初のコンストラクタで 'two'をnullに設定した場合、すでに設定されているため、他のコンストラクタでその実際の値を設定できません。 –

1

(変更された質問のために更新)。

3

すべての最終変数をすべてのコンストラクタで初期化する必要があります。私がやることは、すべての変数を初期化し、他のすべてのコンストラクタがそれを呼び出して、nullまたは値が与えられていないフィールドがある場合は何らかのデフォルト値を渡すようなコンストラクタを1つ持つことです。

例:

public class MyClass { 
    private final SomeType one; 
    private final SuperType two; 

    //constructor that initializes all variables 
    public MyClas(SomeType _one, SuperType _two) { 
     one = _one; 
     two = _two; 
    } 

    private MyClass(SomeType _one) { 
     this(_one, null); 
    } 

    public MyClass(SomeType _one, SubTypeOne _two) { 
     this(_one, _two); 
    } 

    public MyClass(SomeType _one, SubTypeTwo _two) { 
     this(_one, _two); 
    } 
} 
関連する問題