zoukankan      html  css  js  c++  java
  • 单例模式序列化后反序列化单例失效的问题

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

      

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

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

  • 相关阅读:
    js 实现商品放大镜效果
    Angular.js数据绑定时自动转义html标签及内容
    Sublime 快捷键一览表
    这么牛的简历,你见过么?
    正向代理与反向代理
    负载均衡
    redis搭建与安装
    svn服务配置和日常维护命令
    Mysql导出导入
    linux搭建svn服务器
  • 原文地址:https://www.cnblogs.com/shoneworn/p/6533196.html
Copyright © 2011-2022 走看看