2013-02-25 33 views
5

ジュニアJava開発者のためのタスクとして与えられるコードがあります。私は5年間のJavaを使用すると、コードのこの部分は完全に私を混乱:Java:オブジェクトの初期化シーケンス

public class Main { 

    String variable; 

    public static void main(String[] args) { 
     System.out.println("Hello World!"); 
     B b = new B(); 
    } 

    public Main(){ 
     printVariable(); 
    } 

    protected void printVariable(){ 
     variable = "variable is initialized in Main Class"; 
    } 
} 

public class B extends Main { 

    String variable = null; 

    public B(){ 
     System.out.println("variable value = " + variable); 
    } 

    protected void printVariable(){ 
     variable = "variable is initialized in B Class"; 
    } 
} 

出力は次のようになります。

Hello World! 
variable value = null 

しかし、我々はString variable;String variable = null;を変更した場合、我々は持っています:

Hello World! 
variable value = variable is initialized in B Class 

2番目の出力は私にとってより明確です。

  • 私たちは、このルートの親クラスに来たときに私たちは、(Javaのためにそれがクラスオブジェクトは常にある)クラス階層のルートに行く:だから、私の知る限り、このようにJavaでinizialisationのシーケンスを知っているよう :
    • すべての静的データフィールドが初期化されます。
    • すべての静的フィールド初期化子と静的初期化ブロックが実行されます。
    • すべての非静的データフィールドが初期化されます。
    • すべての非静的フィールド初期化子と非静的初期化ブロックが実行されます。
    • デフォルトコンストラクタが実行されます。
  • 次に、基本となる子クラスの手順を繰り返します。

    1. :上記のルールに基づいて

      Calling base class overridden function from base class methodが、私はこのような配列を有することを前提と -

はまた、スーパークラスのコンテキストでthisキーワードの動作を説明する投稿がありクラスBの新しいインスタンスを作成します。

  • 私たちは部品クラスMainに行きます。
  • main.variableをnullで初期化します。
  • 次に、クラスMainのデフォルトのコンストラクタに移動します。
  • コンストラクターは、のメソッドMainのメソッドを呼び出します。 (?なぜそれが私たちはここthisキーワードを持っていないmain.printvariableを呼び出すことはありません。)
  • フィールドをb.variable
  • 今、私たちはクラスBに戻ってくる「変数ははBクラスに初期化されます」。
  • フィールドb.variableをヌル値で初期化する必要がありますか?
  • クラスBのデフォルトコンストラクタが
  • をしてください実行し、誰かがこの継承inizialisationシーケンスがどのように動作するかの完全かつ完全な説明を与えることができます。そしてString variable = null;String variable;に変更すると別の出力につながるのはなぜですか?

    +1

    printVariable(でき)はかなり誤解を招くようなメソッド名である - (よりはSetVariableようにする必要があります) – Jimmt

    +1

    あなたは5年間Javaを書いてきましたが、あなたはデバッガの使い方を知らないのですか? (コードをステップ実行すると、何が起こっているのか、どのような順序であるのかが正確に表示されます)。 –

    +0

    @BrianRoach私はデバッガを使うことができますし、javap -v -c B.classも試しました。しかし、Java開発者やインタビューの質問にこのようなタスクが表示されるたびに、出力を予測して理解し、なぜこのように動作し、コードをわずかに修正すればどうなるでしょう。ステッピングスルーはルールと実行プロセスの理由を説明しません。 – INlHELL

    答えて

    8

    順序は次のとおりです。

    1. メイン - > "こんにちは"
    2. メイン - > new() - > b.printVariable() - >変数を設定します。
    3. initialisiに戻るng Bなので、variable = nullが発生します。

    基本的に、スーパーオブジェクトMain()は、クラスBの任意の初期化イベントの前に構築されます。つまり、後でvariable = nullが発生します。そうでなければBはMainの初期化を破る可能性があります。

    ジョシュア・ブロッホは、危険な継承がいかにうまくいくかについての彼の効果的なJavaの本で、多くの良い根拠をカバーしています。私はそれをお勧めします。

    +0

    説明をいただき、ありがとうございました。また、私が丁寧にもう一度それを読んでいただきましたことを述べた本に感謝します。 – INlHELL

    2

    まず、variable = null;と書いたときに何が起こるのかを理解する必要があります。そのコードはいつ実行されますか?これは基本的に出力を決定します。

    開始する前に、class Bのオブジェクトを作成すると、メインクラスのprintVariable()関数が呼び出されないことにも言及する必要があります。代わりに、常にBのprintVariable()が呼び出されます。

    variable = nullがある場合は、Bのコンストラクタの実行が開始されます。最初にMain()が呼び出され、printVariable()メソッドが呼び出されます。最後に、variable=nullは、variable変数を上書きすると呼ばれます。

    variable=nullを初期化しない場合、printVariable()関数で設定されたvariableは上書きされないため、期待していたものが得られます。要約すると

    あなたがnew B()を行うとき、これは、ステートメントの実行の順序である:

    Main()  //super constructor 
        B#printVariable() 
        initializtion of variables in B's constructor (if any) [i.e. variable=null, if present] 
    
    +0

    ありがとう、あなたの説明は完全にこのコードを明確にします。私が得られなかったことは、フィールドを初期化することが可能であるということです。クラス。 – INlHELL

    1

    これは素晴らしい演習です!しかし、ジュニア開発者に質問するのは公正な質問ではありません。これは高齢者のためのものです。人は何が起こるかお答えします場合は、引数を削除し、元の質問を

    public Main(String something){ 
    printVariable(); 
    } 
    

    :しかし、技術的なインタビューの中便利な、このテキストを作るために、私はメインのコンストラクタに引数を追加することによって、それを修正のです。人が答えることができない場合 - 続ける必要はありません - 中学生です。

    あなたは、クラスBで保護された修飾子を削除して、あなたはこの人を雇うしないという目標を持っている場合は何が起こるか尋ねる:)