码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-03-10 22:26:14      阅读:776      评论:0      收藏:0      [点我收藏+]

标签:cto   http   trace   and   blog   catch   运行时   ini   shared   

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

  

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:该方法通过反射的方式调用无参构造方法新建一个对象。

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

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

标签:cto   http   trace   and   blog   catch   运行时   ini   shared   

原文地址:http://www.cnblogs.com/shoneworn/p/6533196.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!