JAvaがクラスの静的変数を呼び出すと、クラスの静的コードブロックがどのように実行され、クラスの初期化の問題が発生しますか?
3773 ワード
クラスは、仮想マシンメモリにロードされてから始まり、メモリがアンインストールされるまでのライフサイクル全体にわたって、ロード、検証、準備、解析、初期化、使用、アンインストールの7段階が含まれます.クラス初期化はクラスロードプロセスの最後のフェーズであり、初期化フェーズになってから、クラス内のJavaプログラムコードの実行が本格的に開始されます.仮想マシン仕様では、クラスをすぐに初期化する必要があるのは5つのみです.
1つ目は、new、getstatic、putstatic、invokestaticの4つのバイトコード命令に遭遇した場合、クラスが初期化されていない場合は、初期化をトリガーする必要があります.この4つの命令を生成する最も一般的なJavaコードシーンは、newキーワードを使用してオブジェクトをインスタンス化する場合、クラスの静的フィールドを読み込みまたは設定する場合(static修飾でfinal修飾され、コンパイル中に結果を定数プールの静的フィールドに入れた場合を除く)と、クラスの静的メソッドを呼び出す場合.2つ目は、Java.lang.refactパッケージを使用してクラスを反射呼び出した場合、クラスがまだ初期化されていない場合は、まず初期化をトリガーする必要があります.3つ目は、クラスを初期化する場合、例えば親がまだ初期化されていないことが判明した場合は、親の初期化をトリガーする必要があります.4つ目:仮想マシンが起動すると、ユーザーは実行するプライマリクラスを指定する必要があります.仮想機会はまずプライマリクラスを実行します.5つ目:JDK 1を使用する場合.5サポート時にjavaが1つある場合.langl.incoke.MethodHandleインスタンスの最後の解析結果REF_getStatic、REF_putStatic、REF_invokeStaticのメソッドハンドルであり,このメソッドハンドルに対応するクラスが初期化されていない場合は,まず初期化をトリガする必要がある.
実行コード:
実行結果:
まとめ:static final値がstatic final int numB=2のように「コンパイル期間定数」である場合.そうすれば、この値はBクラスを初期化することなく読み取ることができる.しかし、1つのドメインをstaticとfinalに設定だけでは、static final int numA=Mainなどの動作を確保するのに十分ではない.rand.nextInt(100);のアクセスは、コンパイル期間定数ではないため、クラスの初期化を強制します.staticドメインがfinalでない場合、アクセス時には、static int numC=3のように、読み取り前にリンク(このドメインにストレージスペースを割り当てる)と初期化(ストレージスペースを初期化する)が常に要求されます.そんな!!
1つ目は、new、getstatic、putstatic、invokestaticの4つのバイトコード命令に遭遇した場合、クラスが初期化されていない場合は、初期化をトリガーする必要があります.この4つの命令を生成する最も一般的なJavaコードシーンは、newキーワードを使用してオブジェクトをインスタンス化する場合、クラスの静的フィールドを読み込みまたは設定する場合(static修飾でfinal修飾され、コンパイル中に結果を定数プールの静的フィールドに入れた場合を除く)と、クラスの静的メソッドを呼び出す場合.2つ目は、Java.lang.refactパッケージを使用してクラスを反射呼び出した場合、クラスがまだ初期化されていない場合は、まず初期化をトリガーする必要があります.3つ目は、クラスを初期化する場合、例えば親がまだ初期化されていないことが判明した場合は、親の初期化をトリガーする必要があります.4つ目:仮想マシンが起動すると、ユーザーは実行するプライマリクラスを指定する必要があります.仮想機会はまずプライマリクラスを実行します.5つ目:JDK 1を使用する場合.5サポート時にjavaが1つある場合.langl.incoke.MethodHandleインスタンスの最後の解析結果REF_getStatic、REF_putStatic、REF_invokeStaticのメソッドハンドルであり,このメソッドハンドルに対応するクラスが初期化されていない場合は,まず初期化をトリガする必要がある.
実行コード:
package com.spring.partise;
import java.util.Random;
class A{
static final int numA = Main.rand.nextInt(100);
static{
System.out.println("I am A");
}
}
class B{
static final int numB = 2;
static{
System.out.println("I am B");
}
}
class C{
static int numC = 3;
static{
System.out.println("I am C");
}
}
public class Main {
static Random rand = new Random();
public static void main(String[] args) throws Exception {
System.out.println("---------------------------");
System.out.println(A.numA);// static
System.out.println("---------------------------");
System.out.println(B.numB);// static
System.out.println("---------------------------");
System.out.println(C.numC);
}
}
実行結果:
---------------------------
I am A
22
---------------------------
2
---------------------------
I am C
3
まとめ:static final値がstatic final int numB=2のように「コンパイル期間定数」である場合.そうすれば、この値はBクラスを初期化することなく読み取ることができる.しかし、1つのドメインをstaticとfinalに設定だけでは、static final int numA=Mainなどの動作を確保するのに十分ではない.rand.nextInt(100);のアクセスは、コンパイル期間定数ではないため、クラスの初期化を強制します.staticドメインがfinalでない場合、アクセス時には、static int numC=3のように、読み取り前にリンク(このドメインにストレージスペースを割り当てる)と初期化(ストレージスペースを初期化する)が常に要求されます.そんな!!