5

ジュニアJava開発者向けのタスクとして提供されるコードがあります。私は5年間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 = null;すると、次のString variable;ようになります。

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

2番目の出力は私にとってより明確です。したがって、私が知る限り、Javaでの初期化のシーケンスは次のようになります。

  • このルートの親クラスに到達すると、クラス階層のルート(Javaの場合は常にObjectクラス)に移動します。
    • すべての静的データフィールドが初期化されます。
    • すべての静的フィールド初期化子と静的初期化ブロックが実行されます。
    • すべての非静的データフィールドが初期化されます。
    • すべての非静的フィールド初期化子と非静的初期化ブロックが実行されます。
    • デフォルトのコンストラクターが実行されます。
  • 次に、基になる子クラスに対して手順を繰り返します。

thisまた、スーパークラスのコンテキストでのキーワードの動作を説明する投稿があります-基本クラスのメソッドから基本クラスのオーバーライドされた関数を呼び出す

上記のルールに基づいて、次のようなシーケンスがあると想定します。

  1. クラスの新しいインスタンスを作成しますB;
  2. パーツクラスに移動しMainます;
  3. main.variablenullで初期化します。
  4. 次に、クラスのデフォルトコンストラクタに移動しますMain;
  5. コンストラクターはb.printVariable()クラスのメソッドを呼び出しMainます; (なぜ呼ばないのmain.printvariableですか?thisここにキーワードはありません。)
  6. フィールドb.variable変数はBクラスで初期化されます
  7. 今、私たちはクラスに戻りBます;
  8. フィールドb.variableをnull値で初期化する必要があります、私は正しいですか?;
  9. B実行されるクラスのデフォルトコンストラクタ

誰かがこの継承の初期化シーケンスがどのように機能するかについて完全かつ完全な説明をしてくれませんか。そして、なぜに変更String variable = null;するString variable;と別の出力につながるのですか。

4

3 に答える 3

9

シーケンスは次のとおりです。

  1. メイン->「こんにちは」
  2. メイン->新しいB()
  3. B()-> Main()-> b.printVariable()->変数を設定します
  4. Bの初期化に戻ると、variable=nullが発生します。

したがって、基本的に、スーパーオブジェクトMain()は、クラスBの初期化イベントの前に構築されます。つまり、variable=nullは後で発生します。そうしないと、BがMainの初期化を壊す可能性があるため、これは理にかなっています。

Joshua Blochは、彼の効果的なjavaの本で、継承がいかに危険であるかについて多くの良い根拠をカバーしています。私はそれをお勧めします。

于 2013-02-25T17:57:45.913 に答える
2

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

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

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

他の場合、初期化しないvariable=nullvariable、関数によって設定されたprintVariable()ものが上書きされないため、期待どおりの結果が得られます。

要約すると、これは次の場合のステートメントの実行順序ですnew B()

Main()     //super constructor
  B#printVariable()
  initializtion of variables in B's constructor (if any) [i.e. variable=null, if present]
于 2013-02-25T17:54:48.153 に答える
1

これはいい運動です!しかし、後輩の開発者に尋ねるのは公正な質問ではありません。これは高齢者向けです。しかし、技術面接中にこのテキストを役立つようにするために、Mainのコンストラクターに引数を追加してテキストを変更しました。

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

その人が何が起こるか答えるなら、議論を取り除き、元の質問をします。その人が答えない場合-続ける必要はありません-彼/彼は後輩です。

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

于 2013-02-26T01:27:34.800 に答える