java设计模式之单例模式你真的会了吗?(饿汉式篇)
    
java设计模式之单例模式你真的会了吗?(饿汉式篇)
一、什么是单例模式?
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
二、单例模式之饿汉式有什么特点以及优缺点?
- 构造方法私有化
 - 类初始化时自行实例化
 - 对外提供统一的静态工厂方法返回实例
 - 优点:实现简单,不存在多线程问题。
 - 缺点:class类在被加载的时候创建Singleton实例,如果对象创建后一直没有使用,则会浪费很大的内存空间,此方法不适合创建大对象。
 
三、我们常见的饿汉式单例的写法
public class HungrySingleton implements Serializable{
    private static final long serialVersionUID = -1008862048413058509L;
    private HungrySingleton() {}
    //类初始化时自行实例化
    private static final HungrySingleton INSTANCE = new HungrySingleton();
    //对外提供统一的静态工厂方法返回实例
    public static HungrySingleton getInstance() {
        return INSTANCE;
    }
}四、上面的单例模式是真的就是单例的吗?运行下面代码中的main方法试试?
public class HungrySingleton implements Serializable{
    private static final long serialVersionUID = -1008862048413058509L;
    private HungrySingleton() {}
    //类初始化时自行实例化
    private static final HungrySingleton INSTANCE = new HungrySingleton();
    //对外提供统一的静态工厂方法返回实例
    public static HungrySingleton getInstance() {
        return INSTANCE;
    }
    
    //测试方法
    public static void main(String[] args) {
        //序列化
        ObjectOutputStream oo;
        try {
            oo = new ObjectOutputStream(new FileOutputStream(new File("C:/HungrySingleton.txt")));
            oo.writeObject(HungrySingleton.getInstance());
            oo.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //反序列化
        ObjectInputStream ois;
        HungrySingleton hungrySingleton = null;
        try {
            ois = new ObjectInputStream(new FileInputStream(new File("C:/HungrySingleton.txt")));
            hungrySingleton = (HungrySingleton) ois.readObject();
            ois.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("是否相同:" + (hungrySingleton == HungrySingleton.getInstance()));
    }
}
结论:通过序列化和反序列化的操作后我们成功的破坏了“单例”
五、为什么饿汉式单例会被序列化和反序列化的操作破坏?








结论:反序列化时如果没有readResolve方法则会返回newInstance的实例,所以导致“单例”被破坏了,如果有readResolve方法则会调用此方法,返回readResolve方法返回的对象
六、所以如何防止饿汉式单例被破坏?需要添加一个readResolve方法并且方法中返回实例即可。
public class HungrySingleton implements Serializable{
    private static final long serialVersionUID = -1008862048413058509L;
    private HungrySingleton() {}
    //类初始化时自行实例化
    private static final HungrySingleton INSTANCE = new HungrySingleton();
    //对外提供统一的静态工厂方法返回实例
    public static HungrySingleton getInstance() {
        return INSTANCE;
    }
    /**
     * 防止采用序列化、反序列化的方式破坏单例
     */
    private Object readResolve() {
        return INSTANCE;
    }
    //测试方法
    public static void main(String[] args) {
        //序列化
        ObjectOutputStream oo;
        try {
            oo = new ObjectOutputStream(new FileOutputStream(new File("C:/HungrySingleton.txt")));
            oo.writeObject(HungrySingleton.getInstance());
            oo.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //反序列化
        ObjectInputStream ois;
        HungrySingleton hungrySingleton = null;
        try {
            ois = new ObjectInputStream(new FileInputStream(new File("C:/HungrySingleton.txt")));
            hungrySingleton = (HungrySingleton) ois.readObject();
            ois.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println("是否相同:" + (hungrySingleton == HungrySingleton.getInstance()));
    }
}
PS:如果你看到了这篇文章,并且觉得对你有帮助,请给个关注和点赞,谢谢!
作者寄语:如果这篇博文对您有所帮助,请给个推荐和收藏吧,谢谢!
作者:野生D程序猿
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.










