单例模式是如何被破坏的

在学习单例的时候,看到这样一句话在序列化|反序列化过程中,单例模式是会打破的,今天就来一探究竟。

环境搭建

恶汉

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

    private HungrySingleton(){}

    public static HungrySingleton getInstance(){
        return INSTANCE;
    }

  /*  private Object readResolve(){ return INSTANCE;} */
}

test-case

  private static void destory_hungry() throws IOException, ClassNotFoundException {
        HungrySingleton instance = HungrySingleton.getInstance();

        Path path = Paths.get("HungrySingleton_001");
        if(Files.exists(path)) {
            Files.delete(path);
        }

        //序列化到指定文件
        File file = Files.createFile(path).toFile();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
        oos.writeObject(instance);

        //反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        HungrySingleton instance2 = (HungrySingleton) ois.readObject();
        
        //打印false ,证明存在两个对象 ,说明单例模式被打破
        System.out.println(instance == instance2);
    }

源码分析
反序列化方法的入口ois.readObject(),从这里跟踪代码分析:

//java.io.ObjectInputStream

//1.
public final Object readObject()
        throws IOException, ClassNotFoundException{
	try {
		//2.
		Object obj = readObject0(false);
		return obj;
	} finally {
	}
}

//2.
private Object readObject0(boolean unshared) throws IOException {
    try {
        switch (tc) {
           //略.......
            case TC_OBJECT:
               //3.1 readOrdinaryObject(unshared)
                return checkResolve(readOrdinaryObject(unshared));
            //略.......
        }
    } finally {
    }
}

//3.1
private Object readOrdinaryObject(boolean unshared)
        throws IOException
    {
        ObjectStreamClass desc = readClassDesc(false);
        desc.checkDeserialize();
        Class<?> cl = desc.forClass();
    
        Object obj;
        try {
        	//执行无参构造方法,实例化一个对象
            obj = desc.isInstantiable() ? desc.newInstance() : null;
        } catch (Exception ex) {
        }

      
        //desc.hasReadResolveMethod():判断是否定义readResolve方法
        if (obj != null &&
            handles.lookupException(passHandle) == null &&
            desc.hasReadResolveMethod())
        {	
        	//如果有则 执行该方法;
            Object rep = desc.invokeReadResolve(obj);
            if (unshared && rep.getClass().isArray()) {
                rep = cloneArray(rep);
            }
            if (rep != obj) {
            	// obj = rep;  覆盖obj原有值
                handles.setObject(passHandle, obj = rep);
            }
        }
        return obj;
    }

解决
如何防止单例模式被破坏呢,可以通过定义readResolve()方法来实现,
解开前文恶汉中封印的代码:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值