作业18:单例模式

一 什么是单例?

顾名思义就是单个实例

当你开出来的摸具,并使用摸具产生唯一一个模型,这就是单例。

而单例模式就是为了保证该类只产生一个实例。

二 什么时候需要单例?

简单说,你不需要多个实例的时候,就可以使用单例。

工具类一般都定义为单例,因为工具类不需要那么多个实例。

单例的好处:

  • 节省维护对象的开销:创建、内存占用、回收
  • 实例状态易于维护,注:一般单例不维护状态,当多个线程进行更改状态时,会产生并发问题。

三 如何实现单例?(不考虑序列化、反射)

1 饿汉式

public class Singleton{
    private static final Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

2 懒汉式

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

3 静态内部类

public class Singleton {
    private Singleton() {}

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }

    static class SingletonHolder {
        private static final Singleton instance = new Singleton3();
    }
}

4 枚举

public enum  Singleton {
    instance;
}

注:枚举本质上就是饿汉模式,具体参考作业16:java枚举类的秘密

四 单例补充

1 考虑反射

  • 暴力反射能打破private限制,从而调用构造方法来创建对象。
public class Main {
    public static void main(String[] args) throws Exception{
        Class<? extends Singleton> aClass = Singleton.getClass();
        Constructor<? extends Singleton> constructor = aClass.getDeclaredConstructor();
        constructor.setAccessible(true); // 暴力反射
        Singleton singleton = constructor.newInstance();
        System.out.println(singleton == Singleton.getInstance()); // false
    }
}

// 以饿汉为例的解决方案:构造器中抛出异常,防止对象创建成功
public class Singleton{
    private static final Singleton instance = new Singleton();

    private Singleton() {
        if (instance != null)
            throw new RuntimeException("private constructor");
    }

    public static Singleton getInstance() {
        return instance;
    }
}

2 考虑序列化

public class Main {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 序列化
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(new File("singleton.txt")));
        oo.writeObject(Singleton.getInstance());
        oo.close();

        // 反序列化
        ObjectInputStream oi = new ObjectInputStream(new FileInputStream(new File("singleton.txt")));
        Singleton singleton = (Singleton) oi.readObject();
        oi.close();

        System.out.println(singleton == Singleton.getInstance()); // false
    }
}

// 以饿汉为例的解决方案:添加readResolve方法
public class Singleton implements Serializable {
    private static final Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }

    private Object readResolve() {
        return instance;
    }
}

参考资料:

posted @ 2019-03-20 11:02  月下小魔王  阅读(186)  评论(0编辑  收藏