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

 更新时间:2026年02月17日 11:37:16   作者:晚夜微雨问海棠呀  
文章总结了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;
  • 用于标识类的版本
  • 如果类结构发生变化,serialVersionUID 也应改变
  • 如果不指定,JVM 会自动生成,但可能导致反序列化失败

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();  // 可能执行恶意代码
  • 反序列化不受信任的数据可能导致代码执行
  • 建议使用白名单验证类
  • 考虑使用安全的序列化框架

性能问题

  • Java 原生序列化性能较差
  • 生成的字节流较大
  • 考虑使用其他序列化框架

其他序列化框架

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. 其他框架

  • Gson:Google 的 JSON 库
  • Fastjson:阿里巴巴的 JSON 库
  • Kryo:高性能二进制序列化
  • Hessian:二进制序列化协议

最佳实践

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

总结

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

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

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

相关文章

  • Spring Boot 启动加载数据 CommandLineRunner的使用

    Spring Boot 启动加载数据 CommandLineRunner的使用

    本篇文章主要介绍了Spring Boot 启动加载数据 CommandLineRunner的使用,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2017-04-04
  • Java实现自定义语言和表达式解析的解释器模式

    Java实现自定义语言和表达式解析的解释器模式

    Java解释器设计模式通过解析自定义语言和表达式,实现对复杂逻辑的处理,提高程序可扩展性和灵活性。它将语法解析和执行过程分离,通过抽象语法树和解释器实现对语言和表达式的解析和求值,避免了硬编码和复杂的条件判断,提高了程序的可读性和可维护性
    2023-04-04
  • JavaWeb中的Filter过滤器解读

    JavaWeb中的Filter过滤器解读

    这篇文章主要介绍了JavaWeb中的Filter过滤器解读,Filter过滤器是JavaWeb的三大组件之一,Filter过滤器是JavaEE的规范也就是接口,Filter的作用是拦截请求,过滤响应,需要的朋友可以参考下
    2023-10-10
  • Java中的Semaphore信号量使用解析

    Java中的Semaphore信号量使用解析

    这篇文章主要介绍了Java中的Semaphore信号量使用解析,Semaphore 通常我们叫它信号量,可以用来控制同时访问特定资源的线程数量,通过协调各个线程,以保证合理的使用资源,需要的朋友可以参考下
    2023-11-11
  • Java设计模式之单例模式Singleton Pattern详解

    Java设计模式之单例模式Singleton Pattern详解

    这篇文章主要介绍了Java设计模式之单例模式Singleton Pattern详解,一些常用的工具类、线程池、缓存,数据库,数据库连接池、账户登录系统、配置文件等程序中可能只允许我们创建一个对象,这就需要单例模式,需要的朋友可以参考下
    2023-12-12
  • 轻松掌握Java备忘录模式

    轻松掌握Java备忘录模式

    这篇文章主要帮助大家轻松掌握Java备忘录模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-09-09
  • java实现可视化日历

    java实现可视化日历

    这篇文章主要为大家详细介绍了java实现可视化日历,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-09-09
  • struts2+jsp+jquery+Jcrop实现图片裁剪并上传实例

    struts2+jsp+jquery+Jcrop实现图片裁剪并上传实例

    本篇文章主要介绍了struts2+jsp+jquery+Jcrop实现图片裁剪并上传实例,具有一定的参考价值,有兴趣的可以了解一下。
    2017-01-01
  • MyBatis-Plus多表联查(动态查询)的项目实践

    MyBatis-Plus多表联查(动态查询)的项目实践

    本文主要介绍了MyBatis-Plus多表联查(动态查询)的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • MyBatis的mapper.xml文件中入参和返回值的实现

    MyBatis的mapper.xml文件中入参和返回值的实现

    这篇文章主要介绍了MyBatis的mapper.xml文件中入参和返回值的实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01

最新评论