Java对象序列化:它是什么以及为什么需要它?
Java中的序列化是将对象状态转换为字节流的过程,以便保存到文件、数据库或通过网络传输。相反的过程——从字节流恢复对象——称为反序列化。这项技术是许多Java框架的基础:从RMI(远程方法调用)到消息传递系统。
在本文中,我们将通过实际示例解析Java内置序列化的工作原理,并探讨其使用的最佳实践。
Java中的序列化如何工作?
Java通过java.io.Serializable接口提供内置的序列化机制。该接口不包含任何方法——它是一个标记接口。如果一个类实现了Serializable,JVM会自动允许其对象的序列化。
用于写入和读取对象的两个主要类来自java.io包:
ObjectOutputStream——将对象序列化为字节流ObjectInputStream——从字节流反序列化对象
简单的序列化示例
创建一个可以序列化的Person类:
import java.io.Serializable;
public class Person implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age; private transient String password; // 不会被序列化
public Person(String name, int age, String password) { this.name = name; this.age = age; this.password = password; }
@Override public String toString() { return "Person{name='" + name + "', age=" + age + ", password='" + password + "'}"; }}现在编写序列化和反序列化的代码:
import java.io.*;
public class SerializationDemo { public static void main(String[] args) { Person person = new Person("伊万", 30, "secret123"); // 序列化 try (FileOutputStream fos = new FileOutputStream("person.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos)) { oos.writeObject(person); System.out.println("对象已序列化: " + person); } catch (IOException e) { e.printStackTrace(); }
// 反序列化 try (FileInputStream fis = new FileInputStream("person.ser"); ObjectInputStream ois = new ObjectInputStream(fis)) { Person restoredPerson = (Person) ois.readObject(); System.out.println("对象已恢复: " + restoredPerson); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } }}程序输出:
对象已序列化: Person{name='伊万', age=30, password='secret123'}对象已恢复: Person{name='伊万', age=30, password='null'}请注意:password字段被标记为transient关键字,反序列化后其值为null。这是从序列化中排除敏感数据的标准方法。
Java序列化的重要特性
- serialVersionUID——类的唯一版本标识符。如果没有显式声明,JVM会自动生成,但这可能在类更改时导致
InvalidClassException错误。建议始终声明private static final long serialVersionUID。 - 静态字段不会被序列化——它们属于类,而不是对象。
- 嵌套对象——如果序列化对象包含对其他对象的引用