我们知道,静态变量只会被初始化一次。事实上,一个类被JVM加载以后,该类的所有静态变量的值都是默认值(引用变量就是null ,boolean变量就是false),直到有个线程首次访问了该类的任意一个静态变量才使得这个类被初始化,然后类的静态初始化块 (static{})会执行,接下来类的所有静态变量被赋予初始值。(即延迟加载)
final附带的语义是:当一个对象被发布到其他线程的时候,该对象的所有final字段(实例变量)都是初始化完毕的,即其他 线程读取这些字段的时候所读取到的值都是相应字段的初始值(而不是默认值),而非final字段没有这种保障。对于引用型final 字段,final关键字还进一步确保该字段所引用的对象已经初始化完毕。
一个严格意义上的不可变对象需要同时满足以下几个条件:
- 类本身用final修饰:防止通过创建子类从而改变其行为
- 所有字段都是用final修饰的:一方面从语义上说明被修饰字段不可变;另一个更重要的是,这个语义在多线程环境下 保证了被修饰字段的初始化安全,即final修饰的字段在对其他线程可见时,它必定是初始化完成的。
- 对象在初始化过程中没有逃逸:防止其他类(比如该类的匿名内部类)再初始化过程中修改其状态。
- 任何字段,如果引用了其他状态可变的对象(数组,集合等),则这些字段必须为private,并且这些字段值不能对外 暴露。若有相关方法返回这些字段值,则应该进行防御性复制(defensive copy)
ThreadLocal变量通常会被声明为某个类的静态变量