• 作业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;
        }
    }
    

    参考资料:

  • 相关阅读:
    ACM模板——次短路及K短路
    ACM模板——最小生成树
    Leetcode-743 Network Delay Time(网络延迟时间)
    ACM模板——最短路
    HDU-2037 今年暑假不AC
    Leetcode-1015 Numbers With Repeated Digits(至少有 1 位重复的数字)
    Leetcode-1014 Capacity To Ship Packages Within D Days(在 D 天内送达包裹的能力)
    Leetcode-1013 Pairs of Songs With Total Durations Divisible by 60(总持续时间可被 60 整除的歌曲)
    Leetcode-1012 Complement of Base 10 Integer(十进制整数的补码)
    LeetCode--204--计数质数
  • 原文地址:https://www.cnblogs.com/linzhanfly/p/10563606.html
Copyright © 2020-2023  润新知