【Java基础面试题001】Java中序列化和反序列化是什么?

在Java中,序列化和反序列化是用于将对象的状态保存和恢复的重要机制。

序列化

是将Java对象转换为字节流的过程,这样Java对象才可以网络传输、持久化存储还有缓存。Java提供了java.io.Serializable接口来支持序列化,只要类实现了这个接口,就可以将该类的对象进行序列化

反序列化

是将字节流重新转化为Java对象的过程,即从存储中读取数据并重新创建对象

相关要点

  • 应用场景:包括网络传输、远程调用、持久化存储(如保存到文件或者数据库)、以及分布式系统中数据交换
  • 相关类和接口:ObjectOutputStream用于序列化,ObjectInputStream用于反序列化。类必须实现Serializable接口才能被序列化
  • 忽略字段:Java提供的Transient关键字可以标记不需要被序列化的字段,这些字段在反序列化时,会被初始化为其对应默认值(null,0,false等)
  • 业务中建议忽略的字段:
    • 敏感信息(密码/API密钥/个人身份信息/信用卡号等),
    • 计算值(用户会话ID/临时数据/缓存值/动态计算结果等),
    • 大对象或集合( 会带来性能开销,指向大文件的引用会导致序列化后的数据体积庞大 / 不必要的超大集合等),
    • 标志位或状态字段(这些字段用于内部逻辑控制而不是对外接口)
    • 冗余字段(可以从其他字段推导出的数据)
  • 版本控制:每个Serializable类都应该定义一个serialVersionUID,用于在反序列化时验证版本的一致性。如果没有明确指定,Java会根据类的定义自动生成一个UID,可是这种自动生成的UID可能在不同的编译器或不同的JDK版本之间变化,版本不匹配可能导致反序列化失败
  • 序列化性能问题:Java的默认序列化机制可能比较慢,尤其是对于大规模分布式系统,可能会选择更加高效的序列化框架(如 Protobuf、Kryo)
  • 安全性:反序列化是一个潜在的安全风险,因为通过恶意构造的字节流,可能会加载不安全的类或执行不期望的代码。因此反序列化过程需要进行输入验证,避免反序列化漏洞(相关教程:Java反序列化漏洞专题-基础篇(21/09/05更新类加载部分)_哔哩哔哩_bilibili  全网最牛逼的Java反序列化基础教程_哔哩哔哩_bilibili)

扩展知识

1.反序列化与序列化的进一步理解

序列化其实就是将Java对象转化成可传输的字节序列格式,以便于存储和传输

比如将如下Java对象转化成这样子

import java.io.Serializable;public class User implements Serializable {private String username;private transient String password; // 不会被序列化
}
[魔法值][版本号]
[类名长度][类名][字段数]
[字段0类型][字段0名称][字段0值]
[字段1类型][字段1名称][字段1值]  // password字段不在这里,因为它是transient
...
[其他信息]
AC ED 00 05 73 72 00 04 55 73 65 72 00 0D 6A 61 76 61 2E 75 74 69 6C 2E 55 73 65 72 12 00 08 77 69 6E 64 6F 77 73 74 72 00 09 70 61 73 73 77 6F 72 64 00 02 76 61 6C 75 65 ...

因为对象在JVM中可以抽象的认为是“立体”的,会有各种引用,比如在内存地址 【Ox1234】引用了某个Java对象,那此时这个对象要传输到网络的另一端时候就需要把这些引用"压扁"

因为网络的另一端的内存地址【Ox1234】是可以没有某某对象的,所以传输的对象需要包含这些信息,然后接收端将这些扁平的信息再反序列化得到对象

所以,反序列化就是将字节序列格式转换为对象的过程。

实例:

有这两个类

import java.io.Serializable;class Address implements Serializable {private String city;private String country;public Address(String city, String country) {this.city = city;this.country = country;}// Getter 和 Setter 略...
}class User implements Serializable {private String username;private transient String password; // 不会被序列化private Address address; // 引用类型字段public User(String username, String password, Address address) {this.username = username;this.password = password;this.address = address;}// Getter 和 Setter 略...
}

创建对象:

Address address = new Address("New York", "USA");
User user = new User("john_doe", "securePassword", address);

对象在JVM中的表现:

  • 在JVM中,User对象位于某个内存地址(例如0x1234),并且它持有一个对Address对象的引用。
  • Address对象也位于另一个内存地址(例如0x5678)。

序列化过程:

  • 当我们将user对象序列化以传输到另一端时,它需要将所有相关的信息“压扁”,也就是将内存中的引用关系转换为字节数据。
  • 具体来说,序列化过程会包含:
    • User对象的基本属性(如username)。
    • Address对象的内容(如citycountry)。
  • 而不是仅仅传输内存地址(比如0x5678),序列化会将Address对象的实际内容转储到字节流中。

序列化后的字节流示例:

序列化后,字节流可能包含以下信息(这是一个概念性表示)

[User类名][username][john_doe][address类名][city][New York][country][USA]

反序列化:

在接收端,当我们反序列化这个字节流时,会重新构建出User对象及其引用的Address对象。整个对象结构和信息被完整还原,而不是简单地处理内存地址。

2.Java序列化Serializable的意义

无实际意义,起类标记作用

看源码【java.io.ObjectOutputStream】

判断此对象是否是String、数组、枚举类的实例,是否实现了Serializable接口,如果是就走writeOrdinaryObject()方法

3.serialVersionUID又有什么用?

起到验证作用

private static final long serialVersionUID = 1L;

经常会用到这个代码,这个UID是反序列化的时候验证对应的序列化对象的UID是否一致

如果不显式指定UID,系统会默认按照对象的类结构自动生成的,当你修改了代码会立即生成新的UID替换掉之前的UID,所以序列化一个对象之后,在反序列化之前把对象的类结构改了,比如增加了一个成员变量,则此时的反序列化会失败

这么看的话,这个UID的数字其实并不重要,无论是简单的1L还是多复杂的还是IDEA自动生成的,只要保持序列化和反序列化的时候UID一致即可

4.静态变量/方法不会被序列化

静态变量/方法属于类本身,序列化机制仅处理对象的状态,而不涉及类的方法

底层原因:通过调用对象的writeObject()和readObject()方法实现将对象写入输出流/读取输入流的,静态变量又不属于对象,因此调用这两个方法的时候静态变量压根不参与其中,自然也就无法被序列化

import lombok.Data;
import java.io.*;@Data
public class Test implements Serializable {@Serialprivate static final long serialVersionUID = 1L;private String name = "测试name01";private static int age = 1;private transient String password = "测试password01";public static void main(String[] args) {try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("sky-server/src/main/java/com/sky/test对象序列化.txt"));ObjectInputStream ois = new ObjectInputStream(new FileInputStream("sky-server/src/main/java/com/sky/test对象序列化.txt"));){// 序列化Test test = new Test();oos.writeObject(test);// 反序列化之前修改所有属性test.name = "测试name02";Test.age = 2;test.password = "测试password02";// 反序列化Test test1 = (Test) ois.readObject();System.out.println(test1);}catch (Exception e){e.printStackTrace();}}
}

结果显示

可以看到被transient关键字修饰的属性,在反序列化后自动赋予了默认值

被static修饰的属性,压根不会被序列化

5.SpringBoot对于序列化操作的支持

从上面的源码可以看到,java处理对象的序列化使用了ObjectOutputStream()类的writeOrdinaryObject()方法。

在使用SpringBoot进行编程时,许多情况下,即使类没有实现Serializable接口,也可以完成对象的序列化和反序列化。这是因为SpringBoot并没有使用这个ObjectOutputStream()类实现序列化,而是使用了其他机制,例如:SpringBoot默认使用Jackson框架以JSON字符串作为中转格式,从而实现了序列化

然而,如果遇到了使用ObjectOutputStream()类进行序列化的情况,对象不实现Serializable接口就会报错,因此,为了兼容更多的场景,通常还是建议将需要序列化的类实现Serializable接口

6.serialVersionUID被static修饰了还会被序列化吗?

看最下面的是我的回答【AutismBtkrsr】,上面也有其他人做出了其他回答,有待考证

7.对transient关键字进行一点补充

  • transient修饰的属性在序列化时不会被保存,因此反序列化后,它的值会是类型的默认值
  • 根据上一条,我们可以得出结论:transient修饰的属性必须是可访问的(有对应的getter,setter),以便反序列化后可以被外部代码调用设置成默认值

完啦,拜拜

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

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

相关文章

前端学习week8——vue.js

Vue.js 基础 Vue 核心概念:了解 Vue 的响应式系统、组件、指令(如 v-if、v-for、v-model 等)。Vue 项目管理:学习 Vue CLI 或 Vite,掌握项目创建、管理和打包。推荐学习顺序:Vue 基础 → 组件化开发 → Vu…

Excel如何限制单元格内可选择的下拉框内容?

先选择想要的表格区域: 如果想要选中如下所示:C2格子及其下面所有的格子(则:点击一下C2格子,然后按一下键盘:SHIFT CTRL ↓) 然后在【sheet2】表,先填写好下拉框可选择的内容&am…

uniapp实现列表页面,实用美观

咨询列表页面 组件 <template><view><view class"news_item" click"navigator(item.id)" v-for"item in list" :key"item.id"><image :src"item.img_url"></image><view class"righ…

Linux学习笔记11 系统启动初始化,服务和进程管理(下)

前文 前文介绍了系统启动初始化程序&#xff0c;介绍了systemd的基础知识。这里主要看一下我们systemd的单元管理和常用的命令以及示例。 Linux学习笔记10 系统启动初始化&#xff0c;服务和进程管理&#xff08;上&#xff09;-CSDN博客 systemd单元管理 启动服务 这很常…

哈希表,哈希桶的实现

哈希概念 顺序结构以及平衡树中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在查找一个元素 时&#xff0c;必须要经过关键码的多次比较。顺序查找时间复杂度为O(N)&#xff0c;平衡树中为树的高度&#xff0c;即 O(logN)&#xff0c;搜索的效率取决…

Maven install java heap space

Maven install java heap space 打包报错 Maven install java heap space 解决&#xff1a; vm option: -Xms1024m -Xmx1024m如果 vm配置了&#xff0c;还是一样报错&#xff0c;就重新选择JRE看看是否正确&#xff0c;idea会默认自己的环境&#xff0c;导致设置vm无效&…

aws(学习笔记第十五课) 如何从灾难中恢复(recover)

aws(学习笔记第十五课) 如何从灾难中恢复 学习内容&#xff1a; 使用CloudWatch对服务器进行监视与恢复区域(region)&#xff0c;可用区(available zone)和子网(subnet)使用自动扩展(AutoScalingGroup) 1. 使用CloudWatch对服务器进行监视与恢复 整体架构 这里模拟Jenkins Se…

【Maven】依赖管理

4. Maven的依赖管理 在 Java 开发中&#xff0c;项目的依赖管理是一项重要任务。通过合理管理项目的依赖关系&#xff0c;我们可以有效的管理第三方库&#xff0c;模块的引用及版本控制。而 Maven 作为一个强大的构建工具和依赖管理工具&#xff0c;为我们提供了便捷的方式来管…

go语言的成神之路-筑基篇-中间件

目录 单个Gin中间件 中间件简要概述 一、中间件的定义&#xff1a; 二、中间件的使用&#xff1a; 效果展示 多个Gin中间件 示例 Abort阻止后续处理函数 执行流程图 return直接返回 执行流程图 全局注册中间件 注意事项 单个Gin中间件 中间件简要概述 在 gin 框架中…

Xilinx PCIe高速接口入门实战(一)

引言&#xff1a;本文对Xilinx 7 Series Intergrated Block for PCI Express PCIe硬核IP进行简要介绍&#xff0c;主要包括7系列FPGA PCIe硬核资源支持、三IP硬核差异、PCIe硬核资源利用等相关内容。 1. 概述 1.1 7系列FPGA PCIe硬件资源支持 7系列FPGA对PCIe接口最大支持如…

【第三讲】Spring Boot 3.4.0 新特性详解:增强的配置属性支持

Spring Boot 3.4.0 版本在配置属性的支持上进行了显著增强&#xff0c;使得开发者能够更灵活地管理和使用应用程序的配置。新的特性包括对配置属性的改进、类型安全增强、以及对环境变量的更好支持。这些改进旨在提升开发效率和代码可读性&#xff0c;同时简化配置过程。本文将…

如何使用 Chrome 无痕浏览模式访问网站?

无痕浏览&#xff08;Incognito Mode&#xff09;是 Google Chrome 浏览器提供的一种隐私保护功能&#xff0c;它允许用户在一个独立的会话中浏览网页&#xff0c;而不会记录用户的浏览历史、下载历史、表单数据等。这对于希望保护个人隐私或进行临时性匿名浏览的用户来说非常有…

拥抱 OpenTelemetry:阿里云 Java Agent 演进实践

作者&#xff1a;陈承 背景 在 2018 年的 2 月&#xff0c;ARMS Java Agent 的第一个版本正式发布&#xff0c;为用户提供无侵入的的可观测数据采集服务。6 年后的今天&#xff0c;随着软件技术的迅猛发展、业务场景的逐渐丰富、用户规模的快速增长&#xff0c;我们逐渐发现过…

AI数据分析工具(二)

豆包-免费 优点 强大的数据处理能力&#xff1a; 豆包能够与Excel无缝集成&#xff0c;支持多种数据类型的导入&#xff0c;包括文本、数字、日期等&#xff0c;使得数据整理和分析变得更加便捷。豆包提供了丰富的数据处理功能&#xff0c;如数据去重、填充缺失值、转换格式等…

C/C++ 数据结构与算法 【时间复杂度和空间复杂度】【日常学习,考研必备】

一、时间复杂度 定义&#xff1a;时间复杂度描述了算法运行时间随输入大小增长而增长的趋势。它主要关注的是算法中最耗时的部分&#xff0c;并忽略常数因子、低阶项等细节。表示方法&#xff1a;通常使用大O符号&#xff08;Big O notation&#xff09;来表示时间复杂度。例如…

linux 文件权限,修改权限,c库调用

参考chmod 777 到底是啥 ???看完这个你就完全懂了&#xff01;-CSDN博客 ls -l 查看当前目录文件的权限 会有一个十位的东西 分别为 d:这是一个文件夹 后面3*3位分别表示所有者用户&#xff0c;同组用户&#xff0c;其他用户的读(r)&#xff0c;写(w)&#xff0c;执行(x)…

mysql 事务之LBCC与MVCC

一、事务 数据库事务&#xff08;Database Transaction&#xff09;是数据库管理系统&#xff08;DBMS&#xff09;中执行的一系列操作&#xff0c;这些操作被当作一个逻辑单元进行处理&#xff0c;以保证数据的一致性和完整性。 ACID&#xff0c;事务四个关键特性 1、原子性…

Wireshark 4.4.2:安全更新、错误修复、更新协议支持

流行的网络协议分析器Wireshark已更新至4.4.2版本。它可用于网络故障排除、分析、开发和教育。 已修复以下漏洞&#xff1a; wnpa-sec-2024-14 FiveCo RAP 解剖器无限循环。wnpa-sec-2024-15 ECMP 解析器崩溃。 更新的协议支持&#xff1a; ARTNET、ASN.1 PER、BACapp、B…

Vue-01

Vue框架 Vue官网&#xff1a; Vue.js 框架 数据模型和view的通信就是依靠viewmodel的关键。 目前主流版本仍然是vue2版本。 Vue快速入门 1.新建一个HTML文件&#xff0c;引入Vue.js文件。Vue.js文件是官方引入的一个文件&#xff0c;我们如果要使用Vue就必须引入这个文件。…

HarmonyOS 5.0应用开发——列表(List)

【高心星出品】 文章目录 列表&#xff08;List&#xff09;列表介绍列表布局设置主轴方向设置交叉轴方向 列表填充分组列表填充 滚动条位置设置滚动位置滚到监听 列表项侧滑 列表&#xff08;List&#xff09; 列表介绍 列表作为一种容器&#xff0c;会自动按其滚动方向排列…