单例模式的反序列化总结
2016-07-01 00:00
429 查看
摘要: java Singleton Serializable 单例 序列化
最近观看effective in java ,提到单例模式创建过程中,如果是要保证该对象是可序列化的,需要考虑两点:
1、继承Serializable接口
2、增加readResolve方法
比较疑惑的是为什么需要增加这个方法,在以往的使用中需要被序列化的场景也不多,但是自己确实不明白这个单例对象在反序列化的时候会导致增加一个假冒的对象,从而’单例变的也不在单例‘
深入到代码细节观察发现:
ObjectInputStream反序列化会利用ObjectStreamClass序列化描述符创建一个实例
1、如果实例不为空
2、且描述符内检测到含有readResolve方法
3、反序列化中没有异常发生
满足以上条件会反射执行readResolve获取实例对象,并且和先前的对象作比较,不相等,用本次的值覆盖先前的返回值
不满足以上条件直接返回实例对象,完成反序列化
-----------------------------------------------------------------------------------------------------------------------
测试程序如下:
最近观看effective in java ,提到单例模式创建过程中,如果是要保证该对象是可序列化的,需要考虑两点:
1、继承Serializable接口
2、增加readResolve方法
比较疑惑的是为什么需要增加这个方法,在以往的使用中需要被序列化的场景也不多,但是自己确实不明白这个单例对象在反序列化的时候会导致增加一个假冒的对象,从而’单例变的也不在单例‘
深入到代码细节观察发现:
ObjectInputStream反序列化会利用ObjectStreamClass序列化描述符创建一个实例
1、如果实例不为空
2、且描述符内检测到含有readResolve方法
3、反序列化中没有异常发生
满足以上条件会反射执行readResolve获取实例对象,并且和先前的对象作比较,不相等,用本次的值覆盖先前的返回值
不满足以上条件直接返回实例对象,完成反序列化
[code=language-java]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; }
-----------------------------------------------------------------------------------------------------------------------
测试程序如下:
[code=language-java]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()); &nb 3ff0 sp;} 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(); } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树