java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java中的序列化和反序列化

Java中的序列化和反序列化使用及解读

作者:晚夜微雨问海棠呀

文章总结了Java中序列化和反序列化的概念,包括序列化的用途、实现方式和注意事项,此外,还介绍了其他几种常见的序列化框架,如JSON序列化、ProtocolBuffers和Kryo,并给出了最佳实践和使用场景建议

基本概念

序列化(Serialization):将对象的状态信息转换为可以存储或传输的形式(如字节流)的过程。

反序列化(Deserialization):从字节流中恢复对象的过程,是序列化的逆操作。

为什么需要序列化?

  1. 持久化存储:将对象保存到文件或数据库中
  2. 网络传输:在网络上传输对象(如分布式系统、RPC调用)
  3. 进程间通信:在不同进程之间传递对象
  4. 缓存:将对象缓存到内存或磁盘

Java 序列化实现

1. 实现 Serializable 接口

import java.io.*;

// 可序列化的类
public class Person implements Serializable {
    // 序列化版本号(强烈建议)
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    
    // transient 关键字:该字段不会被序列化
    private transient String password;
    
    public Person(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
    }
    
    // getters and setters...
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + ", password='" + password + "'}";
    }
}

2. 序列化操作

public class SerializationDemo {
    public static void serialize(Object obj, String filename) throws IOException {
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream(filename))) {
            oos.writeObject(obj);
            System.out.println("对象序列化成功!");
        }
    }
    
    public static Object deserialize(String filename) throws IOException, ClassNotFoundException {
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream(filename))) {
            Object obj = ois.readObject();
            System.out.println("对象反序列化成功!");
            return obj;
        }
    }
    
    public static void main(String[] args) {
        Person person = new Person("张三", 25, "123456");
        
        try {
            // 序列化
            serialize(person, "person.ser");
            
            // 反序列化
            Person deserializedPerson = (Person) deserialize("person.ser");
            System.out.println("反序列化后的对象: " + deserializedPerson);
            // 输出: Person{name='张三', age=25, password='null'} (password为null因为transient)
            
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

重要概念

1. serialVersionUID

private static final long serialVersionUID = 1L;

2. transient 关键字

private transient String password;  // 不会被序列化

标记不需要序列化的字段,如:

3. 自定义序列化

public class CustomPerson implements Serializable {
    private String name;
    private int age;
    
    // 自定义序列化方法
    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();  // 默认序列化
        // 可以添加额外的序列化逻辑
    }
    
    // 自定义反序列化方法
    private void readObject(ObjectInputStream ois) 
            throws IOException, ClassNotFoundException {
        ois.defaultReadObject();  // 默认反序列化
        // 可以添加额外的反序列化逻辑
    }
}

4. Externalizable 接口

import java.io.*;

public class ExternalizablePerson implements Externalizable {
    private String name;
    private int age;
    
    // 必须有无参构造器
    public ExternalizablePerson() {}
    
    public ExternalizablePerson(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(name);
        out.writeInt(age);
    }
    
    @Override
    public void readExternal(ObjectInput in) 
            throws IOException, ClassNotFoundException {
        name = (String) in.readObject();
        age = in.readInt();
    }
}

序列化的注意事项

安全问题

// 反序列化可能存在安全风险
Object obj = ois.readObject();  // 可能执行恶意代码

性能问题

其他序列化框架

1. JSON 序列化(Jackson)

import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper();

// 序列化为 JSON
String json = mapper.writeValueAsString(person);

// 从 JSON 反序列化
Person person = mapper.readValue(json, Person.class);

2. Protocol Buffers

// 需要定义 .proto 文件
// 高性能、跨语言、体积小

3. 其他框架

最佳实践

  1. 始终声明 serialVersionUID
  2. 使用 transient 保护敏感数据
  3. 考虑使用 JSON 等文本格式替代二进制序列化
  4. 反序列化时进行数据验证
  5. 对于性能敏感场景,使用专业序列化框架
  6. 避免序列化不可信的数据
  7. 不要序列化包含资源(如文件句柄、数据库连接)的对象

总结

特性Java 原生序列化JSON 序列化Protocol Buffers
可读性二进制文本二进制
性能一般较慢很快
跨语言仅 Java支持支持
体积较大较大很小
使用场景Java 内部使用Web API高性能场景

选择合适的序列化方式取决于具体的使用场景、性能要求和跨语言需求。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文