2017-01-28 1 views
0

Javaのフィールドの初期化に奇妙な順序があることがわかったとき、私は非常に混乱しました。 init()の結果は、フィールドの初期化によって上書きされ 例コード:最初に使用する前にフィールドを初期化しないのはなぜですか?

public abstract class Parent { 

    public String parentField = "dupa"; 

    public Parent(){ 
     init(); // uhh, bad practice to call abstract method in a super constructor 
    } 

    protected abstract void init(); 
} 

public class Child extends Parent { 

    public String childField = null; // assigning null is unnecessary, another bad practice 

    @Override 
    protected void init(){ 
     childField = "initialized"; 
     System.out.println("After init(): " + childField); 
    } 
} 

... 

Child child = new Child(); // OUTPUT: After init(): initialized 
System.out.println("After all: " + child.childField); // OUTPUT: After all: null 

私はnew Child();を呼び出すときに実行順序が何であるかが分かった:

  1. 親フィールドの初期化が、childFieldがすでに存在し、デフォルトを持っています親コンストラクタによって呼び出された値(childField = NULL)
  2. 親コンストラクタ
    • オーバーライドのinit()(CH私はこの例では、悪い習慣に満ちている知っているchildField =ヌル(再び)
    • 子コンストラクタ

:ildField =

  • 子は初期化フィールド) "初期化"。しかし、私の直観的な順序は、フィールドの初期化(親から子へ)、次にコンストラクタ(親から子へ)です。

    このような初期化の目的は何ですか? フィールドイニシャライザが最初に使用される前に実行されないのはなぜですか? フィールドがまだ初期化されていない場合は、なぜそれを使用することができますか?

  • +0

    'ChildField'の初期化は、' Parent'のためのctorが終了した後どのように 'Child' _ _において起こりますか? –

    +0

    コンストラクタでオーバーライド可能なメソッドを呼び出す理由は、不完全なオブジェクトが他のコードに漏れることです。同様に、子フィールド初期化子は、 'super'が完全に構築されることを期待しています。 – 4castle

    +0

    子と親の両方にparamsを持つコンストラクタを使用すると、子コンストラクタが独自のコンストラクタコードの前に親を呼び出すように強制されます。この種の質問は私にはボットが生成されたようだ – efekctive

    答えて

    2

    私は、新しいオブジェクトの構築のあなたの「直感的」順言い換えてみましょう:

    1. 親のフィールドが初期化されているが
    2. 子供のフィールドは親のコンストラクタが呼び出され
    3. 初期化され
    4. が子供のコンストラクタが呼び出され

    これは、子供のfの初期化ieldsは親に依存する可能性があります。

    オブジェクトは、コンストラクタが返されたときに「適切に初期化された」とみなすことができます。同意する?代わりにParentChildを使用しての

    、のはBoxTreasureBoxを使ってみましょう。 TreasureBoxを作成するには、まずBoxを作成します。ボックスが作成された後は、別の装飾を追加してすべての装飾やクールな装飾を施したり、ロックなどを追加することもできます。

    を参照してください。ここの注文?子を初期化する前に、まず親を適切に初期化することが最も理にかかります。つまり、親クラスのコンストラクタが返された後に子クラスの初期化が行われる必要があります。これはまさにJavaがやっていることです。

    子のフィールドは、親のフィールドに依存することがあります。 TreasureBoxにロックをかけるには、ボックスの前面を見つけてそこに置く必要があります。ボックスの前面がまだ作成されていない場合は、どうやってロックをかけることができますか?ここで

    は、私が何を意味するかを明確にするいくつかのコードです:

    class Parent { 
    
        public String parentField; 
    
        public Parent(){ 
         parentField = "Hello"; 
        } 
    } 
    
    class Child extends Parent { 
    
        public int childField = parentField.length(); 
    } 
    

    Javaがあなたの「直感的」順序を使用している場合は、NPEがスローされます。

    +0

    コンストラクタ内のフィールド初期化子と依存値に一定の値のみを割り当てるように1つのスキームを保つ場合、その2つのオーダーに違いはありません。あなたのサンプルコードは、反対のスキームを使用します。 – igrek51

    関連する問題