1

この例を見つけて、その背後にあるロジックを理解したいですか? コンストラクターと静的ブロックと初期化ブロックは継承でどのように機能しますか? それぞれがどの段階で呼び出されますか?

public class Parent {

    static {
        System.out.println("i am Parent 3");
    }

    {
        System.out.println("i am parent 2");
    }

    public Parent() {
        System.out.println("i am parent 1");
    }

}

public class Son extends Parent {

    static {System.out.println("i am son 3");}
    {System.out.println("i am son 2");}

    public Son() {
        System.out.println("i am son 1");
    }

    public static void main(String[] args) {
        new Son();
    }
}

出力は次のとおりです。

i am Parent 3
i am son 3
i am parent 2
i am parent 1
i am son 2
i am son 1
4

4 に答える 4

13

あなたはそれを知る必要があります

  1. コンストラクターの最初の命令は、その親クラスのコンストラクターを呼び出すsuper(params)か、デフォルトのコンストラクターを使用する場合ですsuper()。デフォルトのコンストラクタの場合、明示的に記述する必要はありません。
  2. super(...)初期化ブロック内のコードは、呼び出しの直後にすべてのコンストラクターに移動されます
  3. 静的ブロックは、クラスが初期化されるときに実行されます。これは、JVM によって (その親クラスと共に) 完全にロードされた後に実行されます。

したがって、クラスはこれに似たクラスにコンパイルされます。

public class Parent {
    static {
        System.out.println("Parent static block");
    }

    public Parent() {
        super();
        {
            System.out.println("Parent initializer block");
        }
        System.out.println("Parent constructor");
    }

}

public class Son extends Parent {

    static {
        System.out.println("Son static block");
    }

    public Son() {
        super();
        {
            System.out.println("Son initializer block");
        }
        System.out.println("Son constructor");
    }

    public static void main(String[] args) {
        new Son();
    }
}

クラス JVMmainからメソッドを実行できるようにするには、このクラス (およびそれが拡張するクラス) のコードをロードする必要があります。クラスが完全にロードされた後、JVMは静的ブロックの実行を含む静的コンテンツを初期化します (はい、1 つのクラスに複数の静的ブロックが存在する可能性があります)。クラスを完全にロードするには、JVM はその親クラスの詳細を知る必要があるため、その前にクラスを完全にロードします。つまり、クラス内の静的ブロックの前に静的ブロックも実行します。SonSonParentSonSon

したがって、出力は次のようになります。

  • Parent static block
  • Son static block

メソッドで、コードが次のように見えるクラスコンストラクターをmain呼び出していますSonnew Son()

super();
{
    System.out.println("Son initializer block");
}
System.out.println("Son constructor");

クラスコンストラクターをsuper()参照しているため、Parent

super();// this will invoke Object constructor since Parent 
        // doesn't extend anything (which means it extends Object class)
{
    System.out.println("Parent initializer block");
}
System.out.println("Parent constructor");

結果としてあなたは見るでしょう

  • Parent initializer block
  • Parent constructor

このハンドルは次のようにParent#constructor()実行されるので、次に生成されるsuper()Son コンストラクターからのコードが表示されます。super()

  • Son initializer block
  • Son constructor

Sonコンストラクターやメソッドを使用する前でもクラスがロードされることを確認するには、コンストラクターのようなmainものを使用する前に何かを出力するだけですSon

System.out.println("ABC                      // before new Son()");
new Son();

その結果、

Parent static block
Son static block
ABC                      // before new Son()
Parent initializer block
Parent constructor
Son initializer block
Son constructor
于 2014-02-01T23:25:56.920 に答える
2

クラスがロードされ、クラスがjvmのクラスローダーによって最初にロードされるときに呼び出される静的ブロックなので、最初に実行されます

次に、親のinitブロックが呼び出されるようにオブジェクトを作成し、Javaでのコンストラクターチェーンにより親コンストラクターが呼び出され、次に派生クラスのinitブロック、次に派生クラスのコンストラクターが呼び出されます

于 2014-02-01T23:00:04.463 に答える
1

静的ブロックはクラスが JVM にロードされるときに実行されますが、コンストラクター ブロックはインスタンスの作成時に実行されます。

静的初期化子は、静的コンテキストのコンストラクターと同等です。確かに、インスタンス初期化子よりも頻繁に表示されます。

于 2014-02-01T22:58:37.957 に答える