在 Java 中,序列化(Serialization)和反序列化(Deserialization)是对象持久化和恢复的关键技术。它们用于将对象的状态转换为可以存储或传输的格式,并在需要时将其恢复为原始对象。以下是详细介绍:
序列化(Serialization)
定义:
- 序列化 是将 Java 对象的状态转换为字节流的过程。这种字节流可以存储在文件中、发送到网络上,或在其他地方保存。
用途:
- 持久化:将对象状态保存到文件或数据库中,以便将来恢复。
- 传输:在网络上发送对象,允许不同的 Java 应用程序或系统之间交换数据。
实现:
- 对象必须实现
Serializable
接口,这是一个标记接口(没有方法)。 - 序列化过程由
ObjectOutputStream
完成,将对象写入流中。
示例:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Person implements Serializable {
private static final long serialVersionUID = 1L; // 序列化版本号
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class SerializationExample {
public static void main(String[] args) {
Person person = new Person("John", 30);
try (FileOutputStream fileOut = new FileOutputStream("person.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
out.writeObject(person);
System.out.println("Serialized data is saved in person.ser");
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这个例子中,我们将 Person
对象序列化并保存到文件 person.ser
中。
反序列化(Deserialization)
定义:
- 反序列化 是将字节流转换回 Java 对象的过程。这允许我们从保存的字节流中恢复对象的状态。
用途:
- 恢复持久化对象的状态,从文件或网络流中读取对象数据。
- 实现对象在不同 JVM 或进程之间的交换。
实现:
- 反序列化过程由
ObjectInputStream
完成,从流中读取对象并恢复其状态。
示例:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
class Person implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class DeserializationExample {
public static void main(String[] args) {
Person person = null;
try (FileInputStream fileIn = new FileInputStream("person.ser");
ObjectInputStream in = new ObjectInputStream(fileIn)) {
person = (Person) in.readObject();
System.out.println("Deserialized Person:");
System.out.println("Name: " + person.name);
System.out.println("Age: " + person.age);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
在这个例子中,我们从文件 person.ser
中反序列化 Person
对象,并输出其内容。
重要概念
-
序列化版本号(serialVersionUID):
serialVersionUID
是一个唯一的标识符,用于确保序列化和反序列化过程的兼容性。如果类发生变化但serialVersionUID
保持不变,序列化和反序列化仍然可以成功进行。建议显式声明serialVersionUID
。
-
Transient 关键字:
- 使用
transient
修饰的字段不会被序列化。这意味着,序列化和反序列化时这些字段的值会被忽略,恢复后的对象将不包含这些字段的值。
示例:
class Person implements Serializable { private static final long serialVersionUID = 1L; String name; int age; transient String password; // 不会被序列化 Person(String name, int age, String password) { this.name = name; this.age = age; this.password = password; } }
- 使用
-
自定义序列化:
- 可以实现
writeObject
和readObject
方法来定制序列化和反序列化的过程。例如,可以在序列化过程中添加额外的验证或转换逻辑。
示例:
class Person implements Serializable { private static final long serialVersionUID = 1L; String name; int age; Person(String name, int age) { this.name = name; this.age = age; } private void writeObject(java.io.ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(age); // 自定义序列化过程 } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); age = in.readInt(); // 自定义反序列化过程 } }
- 可以实现
总结
- 序列化 是将 Java 对象转换为字节流以便存储或传输。
- 反序列化 是将字节流转换回 Java 对象以恢复其状态。
- 序列化和反序列化使得对象持久化和跨进程、跨网络的数据交换成为可能。
serialVersionUID
、transient
关键字和自定义序列化方法是序列化过程中的重要概念和工具。