← 返回首页
📦

Java序列化详解:对象序列化与反序列化

📂 java ⏱ 5 min 904 words

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. 最佳实践

  1. 实现Serializable接口:需要序列化的类必须实现此接口
  2. 定义serialVersionUID:确保版本兼容性
  3. 使用transient:敏感数据不应该被序列化
  4. 考虑JSON替代:JSON序列化更通用、更易读
  5. 处理版本兼容:序列化类的修改可能影响反序列化

总结

序列化是Java中重要的机制,用于对象的持久化和网络传输。掌握序列化的使用方法和最佳实践,可以帮助我们实现数据持久化、配置管理等功能。在实际编程中,要根据需求选择合适的序列化方式。