单例模式序列化后反序列化单例失效的问题
不做处理的情况下,单例模式失效,代码如下:
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:该方法通过反射的方式调用无参构造方法新建一个对象。
所以。到目前为止,也就可以解释,为什么序列化可以破坏单例了
不积跬步,无以至千里。