单例模式的反序列化总结

最近观看effective in java ,提到单例模式创建过程中,如果是要保证该对象是可序列化的,需要考虑两点:

1、继承Serializable接口

2、增加readResolve方法

比较疑惑的是为什么需要增加这个方法,在以往的使用中需要被序列化的场景也不多,但是自己确实不明白这个单例对象在反序列化的时候会导致增加一个假冒的对象,从而’单例变的也不在单例‘

深入到代码细节观察发现:

ObjectInputStream反序列化会利用ObjectStreamClass序列化描述符创建一个实例

1、如果实例不为空

2、且描述符内检测到含有readResolve方法

3、反序列化中没有异常发生

满足以上条件会反射执行readResolve获取实例对象,并且和先前的对象作比较,不相等,用本次的值覆盖先前的返回值

不满足以上条件直接返回实例对象,完成反序列化

ObjectInputStream源码如下(标红部分):

    private Object readOrdinaryObject(boolean unshared) 
    throws IOException 
    {
    if (bin.readByte() != TC_OBJECT) {
        throw new InternalError();
    }

    ObjectStreamClass desc = readClassDesc(false);
    desc.checkDeserialize();

    Object obj;
    try {
        obj = desc.isInstantiable() ? desc.newInstance() : null;
    } catch (Exception ex) {
        throw (IOException) new InvalidClassException(
        desc.forClass().getName(), 
        "unable to create instance").initCause(ex);
    }

    passHandle = handles.assign(unshared ? unsharedMarker : obj);
    ClassNotFoundException resolveEx = desc.getResolveException();
    if (resolveEx != null) {
        handles.markException(passHandle, resolveEx);
    }
    
    if (desc.isExternalizable()) {
        readExternalData((Externalizable) obj, desc);
    } else {
        readSerialData(obj, desc);
    }

    handles.finish(passHandle);
    
    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) {
        handles.setObject(passHandle, obj = rep);
        }
    }

    return obj;
    }

-----------------------------------------------------------------------------------------------------------------------

测试程序如下:

package com.tt.st;

import java.io.ObjectStreamException;
import java.io.Serializable;

public class Singleton implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 2090309963475550553L;
    private static final Singleton instance = new Singleton();
    
    private Singleton() {
        System.out.println(System.currentTimeMillis());
    }
    
    public static Singleton getInstance() {
        return instance;
    }

    private Object readResolve()  throws ObjectStreamException {
        return instance;
    }
}

package com.tt.st;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Main {
    private static native ClassLoader latestUserDefinedLoader();

    public static void main(String[] args) throws Exception{
        // TODO Auto-generated method stub
        File file = new File("d:\\doc\\ab.out");
        
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));
        Singleton singleton = Singleton.getInstance();
        System.out.println("first: " + singleton);
        objectOutputStream.writeObject(singleton);
        objectOutputStream.close();
        
        
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
        Object object = objectInputStream.readObject();
        System.out.println("second: " + object);
        objectInputStream.close();
    }

}


 

转载于:https://my.oschina.net/13426421702/blog/703843

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值