Java序列化详解:对象序列化与反序列化
Java序列化详解:对象序列化与反序列化
概述
序列化是将对象转换为字节序列的过程,反序列化是将字节序列转换为对象的过程。Java提供了Serializable接口和ObjectOutputStream/ObjectInputStream来实现序列化。
1. 基本序列化
import java.io.*;
// 可序列化的类
class Person implements Serializable {
private static final long serialVersionUID = 1L; // 版本号
private String name;
private int age;
private String email;
public Person(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + ", email='" + email + "'}";
}
// Getter和Setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
public class SerializationBasic {
public static void main(String[] args) {
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("person.ser"))) {
Person person = new Person("Alice", 25, "alice@example.com");
oos.writeObject(person);
System.out.println("对象已序列化: " + person);
} catch (IOException e) {
System.out.println("序列化异常: " + e.getMessage());
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("person.ser"))) {
Person person = (Person) ois.readObject();
System.out.println("反序列化对象: " + person);
} catch (IOException | ClassNotFoundException e) {
System.out.println("反序列化异常: " + e.getMessage());
}
}
}
2. 自定义序列化
transient关键字
import java.io.*;
class User implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private String password; // 不序列化
private transient String sessionToken; // 不序列化
public User(String username, String password, String sessionToken) {
this.username = username;
this.password = password;
this.sessionToken = sessionToken;
}
@Override
public String toString() {
return "User{username='" + username + "', password='" + password + "', sessionToken='" + sessionToken + "'}";
}
}
public class TransientExample {
public static void main(String[] args) {
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("user.ser"))) {
User user = new User("alice", "secret123", "token456");
oos.writeObject(user);
System.out.println("序列化前: " + user);
} catch (IOException e) {
System.out.println("序列化异常: " + e.getMessage());
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("user.ser"))) {
User user = (User) ois.readObject();
System.out.println("反序列化后: " + user);
} catch (IOException | ClassNotFoundException e) {
System.out.println("反序列化异常: " + e.getMessage());
}
}
}
自定义序列化方法
import java.io.*;
class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String department;
private double salary;
public Employee(String name, String department, double salary) {
this.name = name;
this.department = department;
this.salary = salary;
}
// 自定义序列化方法
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject(); // 执行默认序列化
// 自定义加密
oos.writeDouble(salary * 0.9); // 序列化时打折
}
// 自定义反序列化方法
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject(); // 执行默认反序列化
// 自定义解密
salary = ois.readDouble() / 0.9; // 反序列化时恢复
}
@Override
public String toString() {
return "Employee{name='" + name + "', department='" + department + "', salary=" + salary + "}";
}
}
public class CustomSerializationExample {
public static void main(String[] args) {
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("employee.ser"))) {
Employee emp = new Employee("Alice", "IT", 10000);
oos.writeObject(emp);
System.out.println("序列化前: " + emp);
} catch (IOException e) {
System.out.println("序列化异常: " + e.getMessage());
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("employee.ser"))) {
Employee emp = (Employee) ois.readObject();
System.out.println("反序列化后: " + emp);
} catch (IOException | ClassNotFoundException e) {
System.out.println("反序列化异常: " + e.getMessage());
}
}
}
3. 序列化集合
import java.io.*;
import java.util.*;
public class CollectionSerialization {
public static void main(String[] args) {
// 序列化集合
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("collection.ser"))) {
List<String> list = Arrays.asList("Alice", "Bob", "Charlie");
Map<String, Integer> map = new HashMap<>();
map.put("Alice", 25);
map.put("Bob", 30);
oos.writeObject(list);
oos.writeObject(map);
System.out.println("集合已序列化");
} catch (IOException e) {
System.out.println("序列化异常: " + e.getMessage());
}
// 反序列化集合
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("collection.ser"))) {
List<String> list = (List<String>) ois.readObject();
Map<String, Integer> map = (Map<String, Integer>) ois.readObject();
System.out.println("List: " + list);
System.out.println("Map: " + map);
} catch (IOException | ClassNotFoundException e) {
System.out.println("反序列化异常: " + e.getMessage());
}
}
}
4. JSON序列化(Jackson)
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.*;
// 使用Jackson进行JSON序列化
public class JacksonExample {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
try {
// 序列化为JSON
Person person = new Person("Alice", 25, "alice@example.com");
String json = mapper.writeValueAsString(person);
System.out.println("JSON: " + json);
// 写入文件
mapper.writeValue(new File("person.json"), person);
System.out.println("JSON已写入文件");
// 从JSON反序列化
Person deserialized = mapper.readValue(json, Person.class);
System.out.println("反序列化: " + deserialized);
// 从文件读取
Person fromFile = mapper.readValue(new File("person.json"), Person.class);
System.out.println("从文件读取: " + fromFile);
} catch (Exception e) {
System.out.println("JSON处理异常: " + e.getMessage());
}
}
}
5. 实际应用示例
配置管理器
import java.io.*;
import java.util.*;
public class ConfigManager implements Serializable {
private static final long serialVersionUID = 1L;
private Map<String, String> config;
private String configFile;
public ConfigManager(String configFile) {
this.configFile = configFile;
this.config = new HashMap<>();
}
public void setProperty(String key, String value) {
config.put(key, value);
}
public String getProperty(String key) {
return config.get(key);
}
public String getProperty(String key, String defaultValue) {
return config.getOrDefault(key, defaultValue);
}
public void save() throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(configFile))) {
oos.writeObject(this);
}
}
public static ConfigManager load(String configFile) throws IOException, ClassNotFoundException {
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(configFile))) {
return (ConfigManager) ois.readObject();
}
}
@Override
public String toString() {
return "ConfigManager{config=" + config + "}";
}
public static void main(String[] args) {
try {
// 创建配置
ConfigManager manager = new ConfigManager("config.ser");
manager.setProperty("database.url", "jdbc:mysql://localhost:3306/mydb");
manager.setProperty("database.username", "root");
manager.setProperty("database.password", "secret");
// 保存配置
manager.save();
System.out.println("配置已保存: " + manager);
// 加载配置
ConfigManager loaded = ConfigManager.load("config.ser");
System.out.println("配置已加载: " + loaded);
} catch (Exception e) {
System.out.println("配置管理异常: " + e.getMessage());
}
}
}
6. 最佳实践
- 实现Serializable接口:需要序列化的类必须实现此接口
- 定义serialVersionUID:确保版本兼容性
- 使用transient:敏感数据不应该被序列化
- 考虑JSON替代:JSON序列化更通用、更易读
- 处理版本兼容:序列化类的修改可能影响反序列化
总结
序列化是Java中重要的机制,用于对象的持久化和网络传输。掌握序列化的使用方法和最佳实践,可以帮助我们实现数据持久化、配置管理等功能。在实际编程中,要根据需求选择合适的序列化方式。