单例模式序列化后反序列化单例失效的问题

Posted shoneworn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式序列化后反序列化单例失效的问题相关的知识,希望对你有一定的参考价值。

不做处理的情况下,单例模式失效,代码如下:

  

public class User implements Serializable {
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public  static final User INSTANCE= new User();
    private String  name ;
    
//    private  Object readResolve(){
//        return INSTANCE;
//    }
    
    public User() {
    }

}

  运行的代码

  

public class Test {
    
    public static void main(String [] arg) throws IOException, ClassNotFoundException{
        User user = (User) User.INSTANCE;
        
//        System.out.println("user:cxx");
//        user.setName("cxx");
//        
//        new Thread(new  Runnable() {
//            public void run() {
//                System.out.println("user1:"+User.INSTANCE.getName());
//            }
//        }).start();
//        User user1= User.INSTANCE;
//        System.out.println("user1:"+user1.getName());
        
        try {
            FileOutputStream fos = new FileOutputStream(new File("singToneTest.txt"));
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(user);
            fos.close();
            oos.close();
            System.out.println("user"+user.INSTANCE.hashCode());
            
            FileInputStream fis= new FileInputStream(new File("singToneTest.txt"));
            ObjectInputStream ois = new ObjectInputStream(fis);
            User newuser = (User) ois.readObject();
            fis.close();
            ois.close();
            System.out.println("newuser"+newuser.hashCode());
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

这个时候,看看运行结果

可以看出,上面的单例已经失效了。

放开上面readResolve()方法的注释部分。运行一下

这个时候可以看出,上面的单例模式又神奇的好了。

 

为什么会出现这种情况呢?

可以去参阅一下jdk关于ObjectInputStream的readObject()方法

这里给出ObjectInputStream的readObject的调用栈:

 readObject--->readObject0--->readOrdinaryObject--->checkResolve

这里看一下重点代码,readOrdinaryObject方法的代码片段:

private Object readOrdinaryObject(boolean unshared)
        throws IOException
    {
        //此处省略部分代码

        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);
        }

        //此处省略部分代码

        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;
    }

这里创建的这个obj对象,就是本方法要返回的对象,也可以暂时理解为是ObjectInputStream的readObject返回的对象。

isInstantiable:如果一个serializable/externalizable的类可以在运行时被实例化,那么该方法就返回true。

desc.newInstance:该方法通过反射的方式调用无参构造方法新建一个对象。

所以。到目前为止,也就可以解释,为什么序列化可以破坏单例了

以上是关于单例模式序列化后反序列化单例失效的问题的主要内容,如果未能解决你的问题,请参考以下文章

设计模式 创建者模式 -- 单例模式存在的问题和解决办法(序列化反序列化破坏单例模式 & 反射破坏单例模式)

设计模式课程 设计模式精讲 8-6 单例设计模式-序列化破坏单例模式原理解析及解决方案

单例模式写法

单例模式--反射--防止序列化破坏单例模式

单例模式进阶之Android中单例模式的应用场景

K:单例模式中存在的问题