、验证、准备、解析、初始化
初始化就是执行编译后的()方法,而()方法就是在编译时将静态变量赋值和静态块合并到一起生成的。
所以说,“饿汉模式”的创建对象是在类加载的初始化阶段进行的,那么类加载的初始化阶段在什么时候进行呢?jvm规范规定有且只有以下7种情况下会进行类加载的初始化阶段:
1.使用new关键字实例化对象的时候
2.设置或读取一个类的静态字段(被final修饰,已在编译器把结果放入常量池的静态字段除外)的时候
3.调用一个类的静态方法的时候
4.使用java.lang.reflect包的方法对类进行反射调用的时候
5.初始化一个类的子类(会首先初始化父类)
6.当虚拟机启动的时候,初始化包含main方法的主类
7.当使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。
基本来说就是只有当你以某种方式调用了这个类的时候,它才会进行初始化,而不是说jvm启动的时候就初始化,所以说假如你的单例类里只有一个getInstance()方法,那基本上就是当你从其他类调用getInstance()方法的时候才会进行初始化,这事实上和“懒汉模式”是一样的效果。
当然,也有一种可能就是单例类里除了getInstance()方法还有一些其他静态方法,这样当调用其他静态方法的时候,也会初始化实例,但是这个很容易解决,只要加个内部类就行了(这种模式叫holder pattern):
package common;
public class Singleton {
? ? private static class SingletonHolder{
? ? ? ? private static Singleton instance=new Singleton();
? ? }
? ?
? ? public static Singleton getInstance(){
? ? ? ? return SingletonHolder.instance;
? ? }
}
这样只有当调用getInstance()方法的时候,才会初始化内部类SingletonHolder。
总结
经过以上分析,“懒汉模式”实现复杂而且没有任何独占优点,“饿汉模式”完胜。