谈谈你对Java序列化的理解

谈谈你对Java序列化的理解

章节目录

文章目录

  • 谈谈你对Java序列化的理解
  • 1. 什么是序列化和反序列化?
  • 2. 如何实现序列化和反序列化?
  • 3. 序列化和反序列化的注意事项
  • 5. 序列化和反序列化的性能优化
  • 6. 面试常见问题
    • 问题 1:为什么需要序列化?
    • 问题 2:transient和 static字段为什么不参与序列化?
    • 问题 3:serialVersionUID 的作用是什么?
    • 问题 4:如何提高序列化的性能?
    • 问题 5:序列化和反序列化有哪些安全问题?
    • 问题 6:上面的readObject和 readResolve方法有啥区别呢?
  • 7. **总结**

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

  • 序列化:将 Java 对象转换为字节流(如保存到文件或通过网络传输)。

  • 反序列化:将字节流还原为 Java 对象。

序列化的核心是让对象能够在非 Java 环境(如文件、数据库、网络)中存储或传输。

Java的序列化是指将Java对象转换为字节流的过程,可以将这些字节流保存到文件中或通过网络传输。反序列化则是指将字节流恢复成对象的过程。

序列化的主要目的是实现对象的持久化存储和传输,让对象可以在不同的计算机或不同的时间点被重建和使用。通过序列化,可以将对象的状态以字节的形式保存下来,并且在需要的时候进行恢复,从而实现了对象的跨平台传输和持久化存储。

在Java中,要使一个类可序列化,需要满足以下条件:

  • 实现java.io.Serializable接口,该接口是一个标记接口,没有任何方法。
  • 所有的非静态、非瞬态的字段都可以被序列化。

使用Java的序列化机制,可以通过ObjectOutputStream将对象转换为字节流并写入文件或网络流中。反之,通过ObjectInputStream可以从字节流中读取数据并还原为对象。

需要注意的是,在进行序列化和反序列化时,对象的类和字段的定义必须保持一致,否则可能会导致序列化版本不匹配或字段丢失的问题。

2. 如何实现序列化和反序列化?

Java 提供了Serializable接口,用于标记需要序列化的类。

importjava.io.*;publicclassSerializationExampleimplementsSerializable{privatestaticfinallongserialVersionUID=1L;// 序列化版本号privateStringname;privatetransientintage;// transient 关键字表示该字段不参与序列化// 构造方法、getter 和 setter 略publicstaticvoidmain(String[]args){SerializationExampleobj=newSerializationExample();obj.setName("张三");obj.setAge(25);// 序列化try(ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream("object.ser"))){oos.writeObject(obj);System.out.println("对象已序列化");}catch(IOExceptione){e.printStackTrace();}// 反序列化try(ObjectInputStreamois=newObjectInputStream(newFileInputStream("object.ser"))){SerializationExamplenewObj=(SerializationExample)ois.readObject();System.out.println("对象已反序列化: "+newObj.getName());// 注意:transient 字段会被还原为默认值(这里是 0)System.out.println("年龄: "+newObj.getAge());}catch(IOException|ClassNotFoundExceptione){e.printStackTrace();}}}
  • 序列化底层原理:ObjectStreamClass类中可以看到writeObjectMethod属性,值来自对象writeObject方法;
  • 反序列化底层原理:ObjectStreamClass类中可以看到readObjectMethod属性,值来自对象readObject方法;
  • 自行编写readObject()函数,用于对象的反序列化构造,从而提供约束性。可以自定义反序列化对象的校验信息。

3. 序列化和反序列化的注意事项

序列化和反序列化存在安全风险,尤其是反序列化时:

  • 反序列化恶意数据可能导致代码执行或数据泄露。

  • 面试官可能会问你如何避免这些问题。

解决方法:

  • 自定义readObjectwriteObject方法:在类中覆盖readObjectwriteObject方法,验证数据的合法性。
privatevoidreadObject(ObjectInputStreamois)throwsIOException,ClassNotFoundException{ois.defaultReadObject();// 验证数据if(name==null){thrownewInvalidObjectException("name 不能为空");}}
  • 使用安全的序列化框架:避免使用 Java 默认的序列化机制,改用更安全的框架(如 Protobuf、Kryo)。

  • 避免敏感数据参与序列化:使用transient修饰敏感字段,确保它们不被序列化。

5. 序列化和反序列化的性能优化

Java 的默认序列化机制效率较低,可以通过以下方式优化:

使用Externalizable接口

  • ExternalizableSerializable的子接口,允许自定义序列化逻辑。

  • 通过实现writeExternalreadExternal方法,可以减少序列化数据的大小。

使用高效的序列化库

  • Protobuf:Google 开发的高效序列化框架,支持跨语言。

  • Kryo:轻量级、高性能的序列化框架。

  • FST:快速、紧凑的序列化库。

6. 面试常见问题

问题 1:为什么需要序列化?

序列化可以将对象转换为字节流,方便存储或传输。例如,将对象保存到文件、通过网络发送对象、在分布式系统中传递对象。

问题 2:transient和 static字段为什么不参与序列化?

transient表示字段不参与序列化,static字段属于类而不是对象,因此也不参与序列化。

问题 3:serialVersionUID 的作用是什么?

serialVersionUID用于标识类的版本。如果类的结构发生变化,serialVersionUID不匹配会导致反序列化失败。

问题 4:如何提高序列化的性能?

可以使用Externalizable接口自定义序列化逻辑,或者使用高效的序列化库(如 Protobuf、Kryo)。

问题 5:序列化和反序列化有哪些安全问题?

反序列化恶意数据可能导致代码执行或数据泄露。

如何防止反序列化破坏单例模式的对象呢?

  • 可以通过重写readObject方法 或者readResolve方法、使用安全的序列化框架、避免敏感数据参与序列化来解决。

重写readObject

publicclassSingletonimplementsSerializable{privatestaticfinallongserialVersionUID=1L;privatestaticfinalSingletonINSTANCE=newSingleton();// 私有构造方法,防止外部实例化privateSingleton(){// 防止反射破坏单例if(INSTANCE!=null){thrownewIllegalStateException("Already instantiated");}}// 提供获取实例的方法publicstaticSingletongetInstance(){returnINSTANCE;}// 重写 readObject 方法,阻止反序列化privatevoidreadObject(ObjectInputStreamois)throwsIOException,ClassNotFoundException{thrownewIOException("Singleton cannot be deserialized");}publicstaticvoidmain(String[]args){Singletoninstance1=Singleton.getInstance();// 尝试序列化和反序列化try(ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream("singleton.ser"))){oos.writeObject(instance1);}catch(IOExceptione){e.printStackTrace();}try(ObjectInputStreamois=newObjectInputStream(newFileInputStream("singleton.ser"))){Singletoninstance2=(Singleton)ois.readObject();System.out.println(instance1==instance2);// false,因为 readObject 抛出了异常}catch(IOException|ClassNotFoundExceptione){e.printStackTrace();}}}

重新readResolve

publicclassSingletonimplementsSerializable{privatestaticfinallongserialVersionUID=1L;privatestaticfinalSingletonINSTANCE=newSingleton();// 私有构造方法,防止外部实例化privateSingleton(){// 防止反射破坏单例if(INSTANCE!=null){thrownewIllegalStateException("Already instantiated");}}// 提供获取实例的方法publicstaticSingletongetInstance(){returnINSTANCE;}// 使用 readResolve 方法,确保返回的是单例的唯一实例privateObjectreadResolve(){returnINSTANCE;}publicstaticvoidmain(String[]args){Singletoninstance1=Singleton.getInstance();// 尝试序列化和反序列化try(ObjectOutputStreamoos=newObjectOutputStream(newFileOutputStream("singleton.ser"))){oos.writeObject(instance1);}catch(IOExceptione){e.printStackTrace();}try(ObjectInputStreamois=newObjectInputStream(newFileInputStream("singleton.ser"))){Singletoninstance2=(Singleton)ois.readObject();System.out.println(instance1==instance2);// true,因为 readResolve 返回了 INSTANCE}catch(IOException|ClassNotFoundExceptione){e.printStackTrace();}}}

问题 6:上面的readObject和 readResolve方法有啥区别呢?

  • readObject方法:适合用来阻止反序列化或验证对象状态。

    • ObjectInputStream的方法,用于自定义反序列化逻辑。

    • 适合用来验证对象的状态或直接阻止反序列化。

  • readResolve()方法:适合用来确保反序列化后返回的是单例的唯一实例。

    • 是一个特殊的钩子方法,用于在反序列化完成后返回一个对象。

    • 适合用来确保返回的是单例的唯一实例。

7.总结

  • 序列化:将对象转换为字节流。

  • 反序列化:将字节流还原为对象。

  • 注意事项transientserialVersionUID、静态字段。

  • 安全性:避免反序列化恶意数据,使用安全的序列化框架。

  • 性能优化:使用Externalizable或高效的序列化库。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1134469.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2026年转型大厂算法工程师:大模型技术学习全攻略(必收藏)

对求职者来说,能成为一名大厂的算法工程师,无疑是职业生涯的巅峰。毕竟,互联网大不同厂工种薪资排序,大体是算法>工程>产品>运营>其他,同职级的员工,算法的薪水可能是运营人员的一倍&#xff0…

CRNN模型实战:构建支持API的OCR服务

CRNN模型实战:构建支持API的OCR服务 👁️ 高精度通用 OCR 文字识别服务 (CRNN版) 📖 项目简介 本镜像基于 ModelScope 经典的 CRNN (Convolutional Recurrent Neural Network) 模型构建,提供轻量级、高可用的通用文字识别能力。该…

渗透测试实战:KALI换源加速漏洞库更新

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个渗透测试专用KALI换源工具,功能包括:1.专业渗透测试源集合(含漏洞库、工具库);2.自动同步OWASP、ExploitDB等资源;3.支持Me…

从零到一:用CRNN构建智能文档识别系统

从零到一:用CRNN构建智能文档识别系统 📖 技术背景与项目定位 在数字化转型加速的今天,OCR(光学字符识别)技术已成为信息自动化处理的核心工具之一。无论是发票扫描、证件录入,还是历史文档电子化&#x…

RAG vs 传统搜索:效率提升300%的秘诀

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 构建一个性能对比测试工具,分别实现:1. 传统关键词搜索系统;2. RAG增强搜索系统。测试指标包括:响应时间、结果准确率、用户满意度。…

蓝易云 - 动态BGP与静态BGP的区别

下面这篇内容直击本质、面向真实网络与云业务场景,从路由机制、网络行为、成本模型、稳定性与适用场景五个层面,系统讲清 动态 BGP 与静态 BGP 的核心差异。不是营销说法,而是网络工程视角的硬逻辑。一、先给结论(非常关键&#x…

语音合成延迟高?API响应优化技巧大幅提升效率

语音合成延迟高?API响应优化技巧大幅提升效率 在中文多情感语音合成场景中,响应延迟是影响用户体验的关键瓶颈。尤其是在基于深度学习的端到端模型(如 Sambert-Hifigan)构建的服务中,尽管音质表现优异,但推…

Node.js process.hrtime精准计时技巧

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 Node.js精准计时的艺术:超越process.hrtime的基础陷阱与高级技巧目录Node.js精准计时的艺术:超越process…

CRNN OCR在模糊图片识别中的增强技术

CRNN OCR在模糊图片识别中的增强技术 📖 技术背景:OCR文字识别的挑战与演进 光学字符识别(Optical Character Recognition, OCR)是计算机视觉中一项基础而关键的技术,其目标是从图像中自动提取可读文本。传统OCR系统…

如何用AI快速配置DEVECOSTUDIO中文环境

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 创建一个自动化脚本,能够自动检测DEVECOSTUDIO的当前语言设置,如果没有配置中文,则自动下载并安装中文语言包。脚本需要包含以下功能&#xff1…

OpenSpeedy加速语音服务:结合Sambert-Hifigan构建高性能TTS中台

OpenSpeedy加速语音服务:结合Sambert-Hifigan构建高性能TTS中台 📌 背景与挑战:中文多情感TTS的工程化落地难题 在智能客服、有声阅读、虚拟主播等场景中,高质量、自然流畅的中文语音合成(Text-to-Speech, TTS&#…

requestAnimationFrame在游戏开发中的5个实战技巧

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个简单的2D游戏引擎核心,基于requestAnimationFrame实现游戏主循环。功能要求:1. 稳定的60FPS运行机制 2. 支持多层级渲染 3. 实现基本的物理碰撞检测…

WINMEMORYCLEANER入门指南:轻松优化你的电脑内存

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个简单易用的内存清理工具,适合新手用户。功能包括:一键内存清理、内存使用情况可视化、简单的设置选项。使用Python和Tkinter编写,提供友…

Canvas动画平移基础教程:掌握translate让动画更流畅

在Canvas动画制作中,平移(translate)是基础且关键的操作之一。它不仅仅是移动物体位置那么简单,理解了平移的原理与正确应用,你能更高效地实现复杂的运动轨迹,避免动画中的常见坑点。掌握好坐标变换的机制&…

基于ModelScope的语音合成方案:多情感表达,API调用仅需3行代码

基于ModelScope的语音合成方案:多情感表达,API调用仅需3行代码 📌 业务场景描述:让AI语音“有情绪”地说话 在智能客服、虚拟主播、有声读物等实际应用中,传统语音合成(TTS)系统往往输出机械、单…

AI助力FSCAN:智能代码生成与自动化扫描

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 使用快马平台生成一个FSCAN自动化扫描脚本,要求能够自动扫描指定IP段的开放端口,并输出扫描结果。脚本应包含多线程处理、结果过滤和报告生成功能。使用Pyt…

三菱FX3U-485ADP-MB与欧姆龙E5CC温控器的MODBUS通讯实践

三菱fx3u485ADP MB与4台欧姆龙E5CC温控器通讯案例程序 功能:通过三菱fx3u 485ADP-MB板对4台欧姆龙E5cc温控器进行modbus通讯,实现温度设定,实际温度读取 配件:三菱fx3u 485ADP-mb,三菱fx3u 485BD板,昆仑通态…

CRNN模型量化部署:进一步降低CPU资源消耗

CRNN模型量化部署:进一步降低CPU资源消耗 📖 项目背景与技术选型 在当前智能文档处理、自动化办公、工业质检等场景中,OCR(光学字符识别) 技术已成为不可或缺的核心能力。尤其在边缘设备或无GPU环境的服务器上&#xf…

CRNN OCR多模型融合:提升复杂场景识别准确率

CRNN OCR多模型融合:提升复杂场景识别准确率 📖 项目简介 在当前数字化转型加速的背景下,OCR(光学字符识别)技术已成为信息自动化提取的核心工具,广泛应用于文档电子化、票据处理、车牌识别、工业质检等多…

告别手动配置:CYGWIN一键初始化方案对比

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 生成一个CYGWIN效率对比工具:包含手动配置步骤计时器和AI脚本自动配置模块。要求输出可视化报告(ASCII图表),显示两种方式的时间消耗…