基本概念
Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。
序列化的目的:实现对象远程传输、实现对象持久化保存
如何序列化
- 只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列。(不是则会抛出异常)
- Serializable 是一个空接口,用来标识当前类可以被 ObjectOutputStream 序列化,以及被 ObjectInputStream 反序列化。
- 序列化类的属性没有实现 Serializable 那么在序列化就会报错
- 在反序列化过程中,它的父类如果没有实现序列化接口,那么将需要提供父类的无参构造函数来重新创建对象,否则会报错
- 一个实现 Serializable 接口的子类也是可以被序列化的。
- 静态成员变量是不能被序列化
- transient 标识的对象成员变量不参与序列化
序列化代码示例:
1 | BlackCat black = new BlackCat(); |
序列化ID
serialVersionUID主要影响反序列化,在进行反序列化时,JVM会把传进来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。
serialVersionUID 发生改变有三种情况:
- 手动去修改导致当前的 serialVersionUID 与序列化前的不一样。
- 没有指定时 JVM 内部会根据类结构去计算得到这个 serialVersionUID 值,在类结构发生改变时(属性增加,删除或者类型修改了)这种也是会导致 serialVersionUID 发生变化。
- 假如类结构没有发生改变,并且没有定义 serialVersionUID ,但是反序列和序列化操作的虚拟机不一样也可能导致计算出来的 serialVersionUID 不一样。
注意事项:
- serialVersionUID可以手动指定也可以借助工具生成
- JVM 规范强烈建议我们手动声明一个版本号,最好是 private 和 final 的保证不变。
序列化步骤是什么
- 将对象实例相关的类元数据输出
- 递归地输出类的超类描述直到不再有超类
- 类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值
- 从上至下递归输出实例的数据
如何反序列化
代码示例:
1 | ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_PATH)); |
序列化单例
问题:程序中有一个单例的对象。如果对其进行序列化,再反序列化,则得到了另一个对象。破坏了其单例性。
解决方法是在类中定义readResolve方法:
1 | public final class Singleton implements Serializable { |
这样,当反序列化时,就会调用这个readResolve方法返回我们制定好的对象。
版权声明:本文为博主原创文章,欢迎转载,转载请注明作者、原文超链接,感谢各位看官!!!
本文出自:monkeyGeek
座右铭:生于忧患,死于安乐
欢迎志同道合的朋友一起交流、探讨!
