一、序列化算法的步骤
- 将对象实例相关的类元数据输出。
- 递归地输出类的超类描述 直到不再有超类。
- 类元数据完了以后,开始从顶层的超类 开始输出对象实力的实际数据值。
- 从上至下递归输出实例的数据.
二、JDK序列化为啥必须要实现Serializable 接口
三、序列化和单例模式
所谓单例:就是单例模式就是在整个全局中(无论是单线程还是多线程),该对象只存在一个实例,而且只应该存在一个实例,没有副本。
序列化对单例有破坏
1、通过对某个对象的序列化与反序列化得到的对象是一个新的对象,这就破坏了单例模式的单例性。
2、我们知道readObject()的时候,底层运用了反射的技术。
序列化会通过反射调用无参数的构造方法创建一个新的对象。
这破坏了对象的单例性。
举例说明:
实现序列化的单例
public class Singleton implements Serializable {// volatile 禁止指令重排序private static volatile Singleton instance;/*** 私有化构造器,这样该类就不会被实例化;*/private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();return instance;}}}return instance;}/*** 提供readResolve()方法* 当JVM反序列化恢复一个新对象时,系统会自动调用readResolve()方法返回指定好的对象* 从而保证系统通过反序列化机制不会产生多的Java对象** @return 单例对象* @throws ObjectStreamException 异常*/private Object readResolve() throws ObjectStreamException {return instance;}}
测试类:
@Testpublic void testSingeton() throws Exception {//获取instance 对象Singleton instance = Singleton.getInstance();// 获取文件输出流FileOutputStream fileOutputStream = new FileOutputStream("d:\\Test.txt");// 获取对象输出流ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);// 输出对象objectOutputStream.writeObject(instance);// 关闭资源objectOutputStream.close();fileOutputStream.close();// 获取对象输入流ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("d:\\Test.txt"));// 读取对象Object object = objectInputStream.readObject();// 判断两个对象是否相等,返回true/falseSystem.out.println(instance == object);}
当前结果: false ;
原因:因为JVM在反序列化的时候会通过反射创建了一个新的对象;
如何避免 呢 ?
在单例类中提供一个readSolve()方法,当JVM反序列化恢复一个新对象时,系统会自动调用readResolve()方法返回指定好的对象。从而保证系统通过反序列化机制不会产生多的Java对象。
https://blog.csdn.net/m0_48837505/article/details/110084930
引用
https://blog.csdn.net/weixin_39723544/article/details/80527550
https://blog.csdn.net/fuhao_ma/article/details/102969349
https://blog.csdn.net/weixin_39800144/article/details/103432511
