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
结果说明初始化顺序为:
Static成员变量 -> Static代码块 -> 普通成员变量 -> 普通代码块 -> 构造函数
如果有继承关系,则顺序为:父类Static成员变量 -> 父类Static代码块 -> 子类Static成员变量 -> 子类Static代码块 -> 父类普通成员变量 -> 父类普通代码块 -> 子类普通成员变量 -> 子类普通代码块 -> 父类构造函数 -> 构造函数
3. 类什么时候初始化
- 创建类的实例的时候,即new一个对象
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射
- 初始化一个类的子类(会首先初始化子类的父类)
- JVM启动时标明的启动类,即文件名和类名相同的那个类
类什么时候初始化参考Java中类的加载顺序介绍(ClassLoader)