1.問題
最近、シングルトンパターンを作成するときに@Autiwiredアノテーションインジェクションの動作に遭遇しましたが、NULL
調査の結果、これがクラスの初期化シーケンスに関連していることがわかりました。最初に私の質問を投げます:
//异步处理
public class AsyncManager {
@Autowired
ScheduledExecutorService scheduledExecutorService;
/**
* 操作延迟10毫秒
*/
private final int OPERATE_DELAY_TIME = 10;
/**
* 静态AsyncManager,单例
*/
private static AsyncManager manager = new AsyncManager();
/**
* 无参构造函数
*/
private AsyncManager(){}
/**
* 单例模式(饿汉式)
* @return AsyncManager
*/
public static AsyncManager getManager() {
return manager;
}
public void execute(TimerTask task) {
scheduledExecutorService.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
}
}
public SysUser login(String username, String password) {
AsyncManager.getManager().execute(new TimerTask() {
@Override
public void run() {
System.out.println(123);
}
});
return null;
}
問題:
AsyncManager.getManager().execute()
メソッドを呼び出すときに導入さscheduledExecutorService
れNULL
ませんでした。
理由:
@Autowired
外部参照から設定する前に、このクラスの構築が完了するまで待つ必要があります。AsyncManager.getManager().execute()
メソッドが呼び出されscheduledExecutorService
ても、注入されていないため@Autowired
、コンストラクターまたはメソッドに注釈を書き込むことをお勧めします。
2.クラスの初期化順序
上記の問題から、クラスの初期化と初期化シーケンスの問題が拡張されます。
まずテストコードを見てください:
public class Dog {
public static int a;
public int b;
static {
System.out.println("Static{} a, " + a++);
}
{
System.out.println("{} a, " + a++);
System.out.println("{} b, " + b++);
}
public Dog() {
System.out.println("Construct a, " + a++);
System.out.println("Construct b, " + b++);
}
public static void show() {
System.out.println("show() a, " + a++);
}
public void display() {
System.out.println("display() a, " + a++);
System.out.println("display() b, " + b++);
}
public static void main(String[] args) {
//Dog.show();
//System.out.println(Dog.a);
new Dog();
}
}
main
メソッドで実行new Dog()
すると、プログラムの実行結果は次のようになります。
Static{} a, 0
{} a, 1
{} b, 0
Construct a, 2
Construct b, 1
結果は、初期化シーケンスが次のとおりであることを示しています。
静的メンバー変数->静的コードブロック->共通メンバー変数->共通コードブロック->コンストラクター
継承関係がある場合、順序は次のとおりです。親クラスの静的メンバー変数->親クラスの静的コードブロック->サブクラスの静的メンバー変数->サブクラスの静的コードブロック->親クラスの通常メンバー変数->親クラスの通常コードブロック- >サブクラスの通常のメンバー変数->サブクラスの通常のコードブロック->親クラスのコンストラクター->コンストラクター
3.クラスはいつ初期化されますか
- クラスのインスタンスを作成するとき、オブジェクトは新しい
- クラスまたはインターフェースの静的変数にアクセスするか、静的変数に値を割り当てます
- クラスの静的メソッドを呼び出す
- リフレクション
- クラスのサブクラスを初期化します(サブクラスの親クラスが最初に初期化されます)
- JVMの起動時に示される起動クラス、つまり、同じファイル名とクラス名を持つクラス
クラスが初期化されるときは、Java(ClassLoader)のクラス読み込み順序の概要を参照してください。