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

“避免序列化灾难:掌握实现 Serializable 的真相!(二)”

文章目录

      • 一、什么是序列化?
      • 二、`Serializable` 是如何起作用的?
      • 三、为什么不自动序列化所有对象?
      • 四、Java 序列化的底层原理
        • 序列化的核心步骤:
      • 五、反序列化的原理
      • 六、总结:为什么必须实现 `Serializable` 才能序列化?
      • 推荐阅读文章

在学习 Java 的时候,你可能遇到过一个疑问: 为什么类必须实现 Serializable,否则就没法序列化对象? 这个看似简单的要求,其实和 Java 的底层机制紧密相关。今天,我们今天就来聊聊这个问题的本质,带你了解为什么 Serializable 是 Java 序列化必不可少的一环。

一、什么是序列化?

先来简单回顾一下什么是序列化。序列化的作用,就是把一个Java 对象转换成字节流,这样我们就可以把它存到文件、通过网络传输、或者传递给其他系统。反过来,把字节流还原成对象的过程叫“反序列化”。

例如,你有一个 User 对象,包含用户名和年龄。序列化后,这个对象会变成一串字节:

User user = new User("Alice", 25);
// 序列化对象到文件
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.ser"));
out.writeObject(user);
out.close();

之后你可以读取文件,反序列化回一个 User 对象:

ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.ser"));
User user = (User) in.readObject();
in.close();

这个过程依赖的是 Java 的序列化机制,而 Serializable 就是这个机制的核心。

二、Serializable 是如何起作用的?

Serializable 是一个标记接口,它本身没有定义任何方法。那它为什么如此重要?让我们从 Java 的序列化机制来看。

Java 序列化机制背后是由 ObjectOutputStreamObjectInputStream 这两个类来完成的。当你调用 writeObject() 方法时,Java 会执行一系列操作来把对象转换为字节流。而这些操作,都是基于对象的类是否实现了 Serializable 接口。如果类没有实现 Serializable,Java 会直接抛出异常,阻止序列化的进行。

为什么会这样呢?这是因为 Java 底层的序列化机制需要知道一个类是否允许被序列化。Serializable 就像是给 Java 的一个“信号”,告诉它这个类的对象是可以被安全地序列化和反序列化的。如果类没有实现 Serializable,Java 默认认为这个类的对象不能被序列化,也就没有办法执行后续操作。

三、为什么不自动序列化所有对象?

你可能会想:为什么 Java 不让所有的类自动支持序列化呢?这样岂不是更方便?

实际上,Java 不自动序列化所有对象,是出于安全性和效率的考虑。原因如下:

  1. 安全性问题
    并不是所有类的对象都适合被序列化。有些类可能包含敏感信息,比如密码、系统配置、用户身份信息等。如果随便把这些类序列化,可能会带来安全隐患。例如,一些类设计时可能没有考虑到数据暴露的问题,而序列化可能会无意间将这些数据泄露给外部系统。

  2. 效率问题
    序列化和反序列化的过程是需要消耗系统资源的,特别是在涉及到复杂对象时。如果 Java 默认让所有类都支持序列化,不仅会增加不必要的开销,还可能导致性能下降。比如某些类可能有非常大的对象图,序列化这些对象可能会产生很大的字节流,影响系统效率。

因此,Java 让开发者自己决定哪些类需要支持序列化,而不是一刀切地自动支持所有类。通过让类实现 Serializable,开发者明确地告诉 Java:这个类是可以被序列化的

四、Java 序列化的底层原理

当一个对象实现了 Serializable 接口,Java 底层会使用反射机制来遍历对象的所有字段,并将这些字段的值按顺序转换成字节流。这其中包括:

  • 基本类型(如 intdouble 等)的直接序列化。
  • 对象类型的递归序列化(比如一个对象里包含另一个对象,也会序列化这个嵌套的对象)。

Java 在序列化时,不仅仅是保存对象的字段值,还会保存一些元信息,包括:

  • 类的名称
  • 类的版本号(serialVersionUID
  • 对象的字段及其类型

这些信息使得在反序列化时,Java 能够找到正确的类,并根据保存的字段值恢复出对象。如果类发生了变化(比如字段修改了),还可以通过 serialVersionUID 来判断序列化和反序列化是否兼容。

序列化的核心步骤:
  1. 判断对象是否实现 Serializable:只有实现了这个接口的对象,才能继续序列化。
  2. 遍历对象的字段:使用反射,Java 会依次获取对象的每个字段,并将其转换成字节流。
  3. 保存对象的元数据:保存类的信息、版本号、以及字段的类型和值。
  4. 生成字节流:最终将这些信息“打包”成字节流,便于存储或传输。

五、反序列化的原理

反序列化的过程则是将字节流重新解析成对象。Java 会根据字节流中的元数据,找到对应的类,并使用反射机制重建对象的实例。这个过程需要类的 serialVersionUID 与字节流中的版本号一致,确保类结构没有发生不兼容的变化。

如果对象的类没有实现 Serializable,反序列化时也会失败,因为 Java 没有办法恢复出一个未标记为可序列化的类的对象。

六、总结:为什么必须实现 Serializable 才能序列化?

  • Serializable 是一个标记,告诉 Java 这个类可以安全地被序列化和反序列化。Java 需要这个信号来决定是否执行序列化操作。
  • 安全性:并不是所有对象都适合被序列化,Serializable 让开发者有选择地开放序列化权限,避免敏感数据泄露。
  • 效率:序列化和反序列化是有成本的,不自动支持所有类序列化可以避免不必要的性能开销。
  • 底层机制:Java 使用 Serializable 接口配合反射来实现序列化和反序列化过程,只有实现了 Serializable 的类,Java 才会执行序列化流程。

因此,Java 之所以要求类实现 Serializable,是为了通过这一标记来确保序列化的安全性、性能,以及在底层能够正确执行序列化过程。这也是为什么我们必须显式地让类实现 Serializable,否则 Java 序列化机制就没法发挥作用。

推荐阅读文章

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程
  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
  • 如何理解应用 Java 多线程与并发编程?
  • Java Spring 中常用的 @PostConstruct 注解使用总结
  • 线程 vs 虚拟线程:深入理解及区别
  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!
  • “打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”
  • Java 中消除 If-else 技巧总结
  • 线程池的核心参数配置(仅供参考)
  • 【人工智能】聊聊Transformer,深度学习的一股清流(13)
  • Java 枚举的几个常用技巧,你可以试着用用
  • 如何理解线程安全这个概念?
  • 理解 Java 桥接方法
  • Spring 整合嵌入式 Tomcat 容器
  • Tomcat 如何加载 SpringMVC 组件

http://www.mrgr.cn/news/57241.html

相关文章:

  • 如何在浏览器中使用JavaScript进行屏幕截图
  • 步骤详解:弹性公网ipv6如何申请?
  • Python量化交易(三):股票数据应用与获取
  • SQL 干货 | SQL 半连接
  • 【AUTOSAR标准文档】AotuSar结构横向分层详解(RTE、BSW)
  • 禅道源码部署
  • 记录一次从nacos配置信息泄露到redis写计划任务接管主机
  • 【C++算法】11.滑动窗口_最大连续1的个数lll
  • 【Java面向对象三大特征——封装】
  • 青训营 X 豆包MarsCode 技术训练营--充电总时间计算
  • 智能体能和人工智能有什么区别?
  • 云岚到家系统优化
  • 8阻塞队列
  • Python项目内网环境pdm install超时httpx.ReadTimeout: timed out
  • Vue Router实现路由懒加载
  • 简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef
  • Linux中如何理解一切皆文件
  • Python包——Matplotlib
  • 各种数据类型的定义与常规计算
  • 第23周Java主流框架入门-SpringMVC 3.拦截器
  • 【单元测试】深入解剖单元测试的思维逻辑
  • 【论文速看】DL最新进展20241023-多模态、无监督学习、多任务、图像修复
  • 【哈工大_操作系统实验】Lab8 终端设备的控制
  • 买华为系的车,这个理由无法拒绝
  • hass docker openwrt配置
  • 软件分享丨PDF Shaper