Java 序列化 (Serialization)
Java 序列化是一种将对象的状态信息转换为可以存储或传输的格式(如字节序列)的机制。反序列化则是从字节序列中重新构建出对象。这个功能对于持久化对象状态或在网络上传输对象非常有用。
什么是序列化?
想象一下,您在程序中创建了一个复杂的对象,它包含了各种状态数据。当程序关闭时,这个对象以及它的状态就会从内存中消失。如果您希望在下次程序启动时能恢复这个对象,就需要将它序列化(写入到文件或数据库),并在需要时反序列化(从文件或数据库中读回)。
Serializable 接口
要使一个类的对象可以被序列化,该类必须实现 java.io.Serializable 接口。
Serializable是一个标记接口 (marker interface),它本身没有任何方法。它只是向 JVM 表明该类的对象是允许被序列化的。
序列化和反序列化对象
ObjectOutputStream: 用于将对象写入到一个输出流(如FileOutputStream)。它的writeObject()方法执行序列化操作。ObjectInputStream: 用于从一个输入流中读取对象。它的readObject()方法执行反序列化操作。
示例代码
transient 关键字
默认情况下,对象的所有非静态字段都会被序列化。如果您不希望某个字段被序列化(例如,该字段是临时的,或者包含敏感信息如密码),可以使用 transient 关键字来标记它。
当一个包含 transient 字段的对象被反序列化时,该字段的值将是其类型的默认值(对于引用类型是 null,对于数值类型是 0,对于布尔类型是 false)。
serialVersionUID
序列化机制通过一个名为 serialVersionUID 的版本号来验证序列化的对象和加载它的类是否兼容。这是一个 private static final long 类型的字段。
- 作用:在反序列化时,JVM 会比较文件中的
serialVersionUID和类中的serialVersionUID。如果两者不匹配,将抛出InvalidClassException。 - 为什么重要:如果您没有显式声明
serialVersionUID,Java 编译器会根据类的结构(字段、方法等)自动生成一个。这意味着如果您修改了类(例如添加或删除了一个字段),自动生成的serialVersionUID就会改变,导致无法反序列化旧版本的对象。
最佳实践是始终在实现了 Serializable 接口的类中显式声明 serialVersionUID。
通过显式声明,即使您对类做了一些不影响序列化兼容性的修改(如添加一个方法),serialVersionUID 保持不变,仍然可以成功反序列化旧对象。