当前位置: 首页 > news >正文

Java序列化与反序列化详细介绍

目录

  1. 什么是序列化与反序列化?
  2. Java中的序列化实现
  3. 实战示例:对象与文件的互转
  4. 关键细节与注意事项
  5. 安全性问题与替代方案
  6. ** 为什么现在代码中很少见到serialVersionUID
  7. 总结与最佳实践

1. 什么是序列化与反序列化?

序列化(Serialization) 是将对象转换为字节流的过程,以便存储或传输。
反序列化(Deserialization) 则是将字节流恢复为对象的过程。
想当初刚开始学习java的时候,对序列化与反序列化总是似懂非懂,还到处请教。不知道现在你是否也有同样的困惑。没关系突然有一天会明白的。
常见用途包括:

  • 持久化存储(如保存到文件或数据库)
  • 网络通信(如RPC或RMI)
  • 深拷贝实现

2. Java中的序列化实现

通过实现 java.io.Serializable 接口标记类为可序列化:

public class User implements Serializable {private static final long serialVersionUID = 1L; // 显式声明版本号private String name;private transient int age; // transient字段不会被序列化// 构造方法、getter/setter省略
}

3. 实战示例:对象与文件的互转

序列化对象到文件

try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.dat"))) {User user = new User("Alice", 30);oos.writeObject(user);
} catch (IOException e) {e.printStackTrace();
}

从文件反序列化对象

try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.dat"))) {User user = (User) ois.readObject();System.out.println(user.getName()); // 输出 "Alice"
} catch (IOException | ClassNotFoundException e) {e.printStackTrace();
}

4. 关键细节与注意事项

  • serialVersionUID
    显式声明以避免自动生成导致的版本不一致错误。

  • transient关键字
    标记不需要序列化的字段(如敏感信息或计算缓存)。

  • 静态字段不参与序列化
    静态变量属于类级别,不会被序列化。

  • 继承关系
    父类若未实现 Serializable,子类需负责序列化父类字段。


5. 为什么现在代码中很少见到serialVersionUID

在早期的 Java 开发中,serialVersionUID 是序列化机制(Serializable 接口)中强制要求显式声明的字段,用于保证对象版本兼容性。但随着技术演进和开发范式的变化,现代项目中显式声明 serialVersionUID 的场景显著减少。以下是具体原因和详细解释:


1. Java 原生序列化的使用场景减少

Java 原生的 Serializable 接口序列化存在以下问题:

  • 性能低:序列化后的二进制数据体积大,效率低。
  • 安全性差:反序列化漏洞(如 InvokerTransformer 攻击)频发。
  • 兼容性脆弱:字段增减或类型修改易导致 InvalidClassException

替代方案
现代项目更多使用以下序列化协议,无需依赖 Serializable

协议特点
JSON跨平台、易调试,兼容性强(如 Jackson/Gson)
Protobuf高效二进制协议,支持 Schema 演进,自带版本控制
Avro动态 Schema,适合大数据场景
Kryo高性能 Java 序列化框架(但不跨语言)

在这些协议中,版本控制通过显式 Schema 定义注解配置实现,无需 serialVersionUID


2. 显式声明 serialVersionUID 的必要性降低

即使仍使用 Java 原生序列化,以下场景也减少了对 serialVersionUID 的依赖:

  • 微服务架构:服务间通过 HTTP + JSON 通信,而非直接传递序列化对象。
  • 容器化环境:服务实例无状态化,减少了持久化存储 Java 序列化对象的需求。
  • ORM 框架成熟:如 Hibernate 直接操作数据库实体,而非序列化存储。

3. Lombok 等代码生成工具的普及

许多项目使用 Lombok 的 @Data@Value 注解生成 Bean,但 Lombok 默认不会生成 serialVersionUID。若仍需兼容 Java 序列化,需手动添加:

@Data
public class User implements Serializable {private static final long serialVersionUID = 1L; // 手动声明private String name;
}

开发者可能因疏忽或认为不再需要而省略此字段。


4. 序列化框架的智能兼容性处理

部分现代序列化框架(如 Jackson)通过以下方式绕过 serialVersionUID 的限制:

  • 字段名匹配:反序列化时通过字段名称而非二进制结构匹配。
  • 忽略未知字段:配置 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES = false
  • 版本化注解:通过 @JsonFormat 或自定义注解实现版本控制。

5. 安全开发规范的推动

鉴于 Java 原生序列化的安全风险,许多企业规范直接禁止使用 Serializable,强制使用更安全的替代方案(如 Protobuf),从而彻底规避 serialVersionUID 问题。


何时仍需显式声明 serialVersionUID

在以下场景中,仍需显式声明:

  1. 遗留系统维护:依赖 Java 原生序列化的旧系统。
  2. RMI 或分布式缓存:如使用 Hazelcast、Redis 存储 Java 序列化对象。
  3. 严格版本控制需求:需确保不同版本客户端和服务端的强兼容性。

正确示例

public class LegacyBean implements Serializable {// 显式声明以避免自动生成导致的版本不一致private static final long serialVersionUID = 20231001L; private String data;
}

6. 安全性问题与替代方案

风险提示

  • 反序列化攻击:恶意构造的字节流可导致远程代码执行(如Apache Commons Collections漏洞)。
  • 数据篡改:序列化数据可能被中间人修改。

安全建议

  1. 避免反序列化不可信数据
  2. 使用Java 9+的ObjectInputFilter设置反序列化白名单
    ObjectInputFilter filter = info -> info.serialClass() == User.class ? Status.ALLOWED : Status.REJECTED;
    ois.setObjectInputFilter(filter);
    
  3. 优先选择更安全的序列化格式
    • JSON(如Jackson/Gson)
    • Protocol Buffers(Google高效二进制协议)
    • Apache Avro(支持Schema演进)

7. 总结与最佳实践

  • 谨慎使用Java原生序列化:尤其在处理外部数据时。

  • 显式声明serialVersionUID:确保版本兼容性。

  • 敏感字段标记为transient:或手动加密处理。

  • 考虑替代方案:JSON/Protobuf在跨平台和安全性上更具优势。

  • **安全与性能- 优化:规避原生序列化的缺陷。

  • 工具链支持:Lombok 和框架简化了开发流程。

  1. 架构演进:微服务和无状态化减少序列化对象传递。

若仍需使用 Java 原生序列化,显式声明 serialVersionUID 仍是最佳实践,可避免潜在的兼容性问题。

相关文章:

  • QT写槽函数的注意事项
  • js实现音频的录制
  • LangGraph-agent-天气助手
  • 地下综合管廊 3D 可视化平台
  • 微信小程序数据接收
  • uniapp-商城-67-shop(3-品牌信息显示,弹窗显示完整品牌信息,弹窗拨打电话、地图定位)
  • 安卓11 不带谷歌包默认桌面布局
  • HarmonyOS赋能套件介绍
  • 聊一聊手动测试与探索性测试的区别
  • mysql统计数据库大小
  • 从Embedding到多模态检索:AI知识库构建的进阶路线图
  • 2021-10-28 C++判断完全平方数
  • 学习STC51单片机14(芯片为STC89C52RC)
  • 点云补全技术深度解析:从原理到实践
  • JWT生成的token的构成部分
  • 5.Java 面向对象编程入门:类与对象的创建和使用​
  • 【C++】深入理解C++中的函数与运算符重载
  • Android中获取控件尺寸进阶方案
  • vocabulary in code
  • SMT贴片机操作核心步骤精要
  • 化州手机网站建设公司/哪个网站百度收录快
  • dw网站的站点建设/常用的seo查询工具
  • 政府网站html模板/百度网站客服
  • b2b网站的主要功能/网站seo设置是什么意思
  • 网站建设与实现 文献综述/图片搜索
  • 网站视频背景怎么做/知名的seo快速排名多少钱