プロジェクトに複数のクラスが含まれており、各クラスに静的初期化ブロックがあるとします。これらのブロックはどの順序で実行されますか?クラス内では、そのようなブロックはコードに現れる順序で実行されることを知っています。クラス間で同じであることを読みましたが、私が書いたいくつかのサンプルコードはこれに同意しません。私はこのコードを使用しました:
package pkg;
public class LoadTest {
public static void main(String[] args) {
System.out.println("START");
new Child();
System.out.println("END");
}
}
class Parent extends Grandparent {
// Instance init block
{
System.out.println("instance - parent");
}
// Constructor
public Parent() {
System.out.println("constructor - parent");
}
// Static init block
static {
System.out.println("static - parent");
}
}
class Grandparent {
// Static init block
static {
System.out.println("static - grandparent");
}
// Instance init block
{
System.out.println("instance - grandparent");
}
// Constructor
public Grandparent() {
System.out.println("constructor - grandparent");
}
}
class Child extends Parent {
// Constructor
public Child() {
System.out.println("constructor - child");
}
// Static init block
static {
System.out.println("static - child");
}
// Instance init block
{
System.out.println("instance - child");
}
}
そして、この出力を得ました:
開始
static-祖父母
static-親
static-子供
インスタンス-祖父母
constructor-祖父母
インスタンス-親
constructor-parent
インスタンス-子
constructor-子供
終わり
それからの明らかな答えは、親のブロックが子供のブロックの前に実行されることですが、それは偶然かもしれず、2つのクラスが同じ階層にない場合は役に立ちません。
編集:
これをLoadTest.Javaに追加して、サンプルコードを変更しました。
class IAmAClassThatIsNeverUsed {
// Constructor
public IAmAClassThatIsNeverUsed() {
System.out.println("constructor - IAACTINU");
}
// Instance init block
{
System.out.println("instance - IAACTINU");
}
// Static init block
static {
System.out.println("static - IAACTINU");
}
}
クラス名が示すように、新しいクラスをどこでも参照したことはありません。新しいプログラムは、古いプログラムと同じ出力を生成しました。
クラスの静的初期化子は、インスタンスを作成するため、または静的メソッドまたは静的フィールドにアクセスするために、クラスが最初にアクセスされたときに実行されます。
したがって、複数のクラスの場合、これらのクラスをロードするために実行されるコードに完全に依存します。
JLSバージョン8 のセクション12.4および12.5を参照してください。これらすべてについて詳細に説明します(静的の場合は12.4、インスタンス変数の場合は12.5)。
静的初期化の場合(セクション12.4):
クラスまたはインターフェイスタイプTは、次のいずれかが最初に発生する直前に初期化されます。
(およびいくつかのイタチ語句)
キースとクリスの答えはどちらも素晴らしいです。特定の質問にさらに詳細を追加するだけです。
静的初期化ブロックは、クラスが初期化される順序で実行されます。では、それはどのような順序ですか? JLS 12.4.1に準拠:
クラスまたはインターフェイスタイプTは、次のいずれかが最初に発生する直前に初期化されます。
- Tはクラスであり、Tのインスタンスが作成されます。
- Tはクラスであり、Tによって宣言された静的メソッドが呼び出されます。
- Tによって宣言された静的フィールドが割り当てられます。
- Tによって宣言された静的フィールドが使用され、そのフィールドは定数変数ではありません(4.12.4)。
- Tは最上位クラスであり、T内で字句的にネストされたassertステートメント(§14.10)が実行されます。
クラスClassおよびパッケージJava.lang.reflectの特定のリフレクトメソッドを呼び出すと、クラスまたはインターフェイスの初期化も行われます。クラスまたはインターフェイスは、他の状況では初期化されません。
例として、この例で何が起きているかを説明します。
クラスの初期化は、静的イニシャライザーと、クラスで宣言された静的フィールド(クラス変数)のイニシャライザーの実行で構成されます。
インターフェースの初期化は、インターフェースで宣言されたフィールド(定数)の初期化子の実行で構成されます。
クラスを初期化する前に、その直接のスーパークラスを初期化する必要がありますが、クラスによって実装されるインターフェースは初期化されません。同様に、インターフェイスが初期化される前に、インターフェイスのスーパーインターフェイスは初期化されません。
http://docs.Oracle.com/javase/tutorial/Java/javaOO/initial.html
Java documentation。
静的ブロックがどのように存在しても、それらが現れる順序で単一ブロックとして実行されることを明確に述べました
そう、
ここでの私の理解はJavaはあなたのコードを
static{
i=1;
i=2;
}
static int i;
それがあなたが出力2を得ている理由です
これがお役に立てば幸いです
静的ブロックが呼び出されない場合が1つあります。
class Super {
public static int i=10;
}
class Sub extends Super {
static {
system.out.println("Static block called");
}
}
class Test {
public static void main (String [] args) {
system.out.println(Sub.i);
}
}
上記のコードは10
を出力します
class A {
public A() {
// 2
}
}
class B extends A{
static char x = 'x'; // 0
char y = 'y'; // 3
public B() {
// 4
}
public static void main(String[] args) {
new B(); // 1
}
}
コメント内の数字は、評価順序を示し、小さいほど早くなります。
例が示したように、