单例模式几种写法

饿汉式

public class HungrySingleton {
    private static final HungrySingleton INSTANCE =new HungrySingleton();
    private HungrySingleton() {}

    public static HungrySingleton getInstance() {
        return INSTANCE;
    }
}

- 要点

  1. 私有构造函数
  2. 变量为private static final类型,static变量在类一加载时就初始化,并且一个类就只有一个,final关键字防止变量被覆盖。
  3. public static类型的getInstance方法

- 缺点
1.没有用到也初始化,浪费内存
2.有反射攻击和反序列化攻击风险

懒汉式

public class LazySingleton {
    private static volatile LazySingleton instance;
    private LazySingleton() {}

    public static LazySingleton getInstance() {
        if (instance ==null) {
            synchronized (LazySingleton.class) {
                if (instance ==null) {
                    instance =new LazySingleton();
                }
            }
        }
        return instance;
    }
}

- 要点
1.私有构造函数
2.private static volatile变量,volatile阻止指令重排序,防止造成返回未完全初始化的对象的问题
3.public static类型的getInstance方法
4.双重检查锁

- 缺点
1.使用了Synchronized,影响性能
2.有反射攻击和反序列化攻击风险

静态内部类

public class StaticInnerClassSingleton {
    private StaticInnerClassSingleton (){}

    public static StaticInnerClassSingleton getInstance() {
        return InnerClass.INSTANCE;
    }
    private static class InnerClass {
        private static final StaticInnerClassSingleton INSTANCE =new StaticInnerClassSingleton();
    }
}

- 要点
1.私有构造函数
2.public static类型的getInstance方法
3.静态内部私有类,必须是静态类否则没有办法声明static类型成员
4.结合了饿汉和懒汉两种写法,内部类采用饿汉式,外部类利用了内部类延迟加载的特性做成懒汉式

- 缺点
有反射攻击和反序列化攻击风险

枚举

public enum EnumSingleton {
    INSTANCE;
    public static EnumSingleton getInstance() {
        return INSTANCE;
    }
}

- 原理
将枚举类型生成的.class文件反序列化,发现编译器为枚举类型生成了一个继承Enum类的class,包括一个私有构造函数和static类型的变量INSTANCE

public final class EnumSingleton extends Enum {
    private EnumSingleton(String s, int i)  {
        super(s, i);
    }
    public static final EnumSingleton INSTANCE;
    static  {
        INSTANCE = new EnumSingleton("INSTANCE", 0);
    }
}

由此可知,枚举单例本质上还是饿汉式,所以它还是具备饿汉式浪费内存的缺点,但优点是可以防止反射攻击和反序列化攻击

总结

- 共同点
1.私有构造函数
2.public static 的getInstance方法返回单例对象
3.public static的单例对象

- 不同点

方法 特点
饿汉式 单例对象声明为final,防止创建后被修改。对象在类加载时被初始化
懒汉式 采用双重检查锁,为了防止返回不完全初始化对象,成员变量要加volatile关键字
静态内部类 外部类不声明成员变量,而是在内部类声明,所以内部类必须是静态的,只有静态内部类能声明静态成员变量
枚举 不是声明一个class而是声明一个enum

你可能感兴趣的:(单例模式几种写法)