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

Java 序列化和反序列化为什么要实现 Serializable 接口

第一、序列化和反序列化
序列化:把对象转换为字节序列的过程称为对象的序列化.
反序列化:把字节序列恢复为对象的过程称为对象的反序列化.

第二、什么时候需要用序列化和反序列化呢?
当我们只在本地JVM里运行下Java实例, 这个时候是不需要什么序列化和反序列化的, 但当我们需要将内存中的对象持久化到磁盘, 数据库中时, 当我们需要与浏览器进行交互时, 当我们需要实现RPC时, 这个时候就需要序列化和反序列化了.
前两个需要用到序列化和反序列化的场景, 是不是让我们有一个很大的疑问? 我们在与浏览器交互时, 还有将内存中的对象持久化到数据库中时, 好像都没有去进行序列化和反序列化, 因为我们都没有实现Serializable接口, 但一直正常运行.
下面先给出结论:
只要我们对内存中的对象进行持久化或网络传输, 这个时候都需要序列化和反序列化.
理由:
服务器与浏览器交互时真的没有用到Serializable接口吗? JSON格式实际上就是将一个对象转化为字符串, 所以服务器与浏览器交互时的数据格式其实是字符串, 我们来看来String类型的源码:

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];/** Cache the hash code for the string */private int hash; // Default to 0/** use serialVersionUID from JDK 1.0.2 for interoperability */private static final long serialVersionUID = -6849794470754667710L;

String类型实现了Serializable接口, 并显示指定serialVersionUID的值.
然后我们再来看对象持久化到数据库中时的情况, Mybatis数据库映射文件里的insert代码:

<insert id="insertUser" parameterType="org.tyshawn.bean.User">INSERT INTO t_user(name, age) VALUES (#{name}, #{age})
</insert>

实际上我们并不是将整个对象持久化到数据库中, 而是将对象中的属性持久化到数据库中, 而这些属性都是实现了Serializable接口的基本属性。

第三、实现序列化和反序列化为什么要实现Serializable接口?
在Java中实现了Serializable接口后, JVM会在底层帮我们实现序列化和反序列化, 如果我们不实现Serializable接口, 那自己去写一套序列化和反序列化代码也行, 至于具体怎么写, Google一下你就知道了.

第四、实现Serializable接口就算了, 为什么还要显示指定serialVersionUID的值?
如果不显示指定serialVersionUID, JVM在序列化时会根据属性自动生成一个serialVersionUID, 然后与属性一起序列化, 再进行持久化或网络传输. 在反序列化时, JVM会再根据属性自动生成一个新版serialVersionUID, 然后将这个新版serialVersionUID与序列化时生成的旧版serialVersionUID进行比较, 如果相同则反序列化成功, 否则报错.
如果显示指定了serialVersionUID, JVM在序列化和反序列化时仍然都会生成一个serialVersionUID, 但值为我们显示指定的值, 这样在反序列化时新旧版本的serialVersionUID就一致了.
在实际开发中, 不显示指定serialVersionUID的情况会导致什么问题? 如果我们的类写完后不再修改, 那当然不会有问题, 但这在实际开发中是不可能的, 我们的类会不断迭代, 一旦类被修改了, 那旧对象反序列化就会报错. 所以在实际开发中, 我们都会显示指定一个serialVersionUID, 值是多少无所谓, 只要不变就行.
新增Person类

import java.io.Serializable;
public class Person implements Serializable{private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "name="+this.name+",age="+this.age;}
}

测试类

public class Test {private static void serialize(Person person) throws Exception {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\111.txt")));oos.writeObject(person);oos.close();}private static Person deserialize() throws Exception{ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\111.txt")));return (Person) ois.readObject();}public static void main(String [] args) throws Exception {Person person = new Person();person.setName("tyshawn");person.setAge(18);System.out.println("序列化前的结果: " + person);serialize(person);Person dperson = deserialize();System.out.println("反序列化后的结果: "+ dperson);}
}

先注释掉反序列化代码, 执行序列化代码, 然后Person 类新增一个属性sex

import java.io.Serializable;
public class Person implements Serializable{private String name;private int age;private String sex;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}@Overridepublic String toString() {return "name="+this.name+",age="+this.age+",sex="+this.sex;}
}

再注释掉序列化代码执行反序列化代码, 最后结果如下:

local class incompatible: stream classdesc serialVersionUID = 6167745078708303300, local class serialVersionUID = 2146094259367098212

报错结果为序列化与反序列化产生的serialVersionUID不一致.
接下来我们在上面Person 类的基础上显示指定一个serialVersionUID

private static final long serialVersionUID = 2146094259367098212L;

显示指定serialVersionUID后就解决了序列化与反序列化产生的serialVersionUID不一致的问题。
第五、Java序列化的其他特性
.先说结论, 被transient关键字修饰的属性不会被序列化, static属性也不会被序列化.。
修改Person类

import java.io.Serializable;
public class Person implements Serializable{private static final long serialVersionUID = 2146094259367098212L;private String name;private int age;private transient String sex;private static String signature = "你眼中的世界就是你自己的样子";public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}@Overridepublic String toString() {return "name="+this.name+",age="+this.age+",sex="+this.sex+",signature="+this.signature;}
}

修改测试类

public class Test {private static void serialize(Person person) throws Exception {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\111.txt")));oos.writeObject(person);oos.close();}private static Person deserialize() throws Exception{ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\111.txt")));return (Person) ois.readObject();}public static void main(String [] args) throws Exception {Person person = new Person();person.setName("tyshawn");person.setAge(18);person.setSex("男");System.out.println("序列化前的结果: " + person);
//        serialize(person);Person dperson = deserialize();System.out.println("反序列化后的结果: "+ dperson);}
}

先注释掉反序列化代码, 执行序列化代码, 然后修改Person类signature = “你眼中的世界就是你自己的样子2”, 再注释掉序列化代码执行反序列化代码, 最后结果如下:

序列化前的结果: name=tyshawn,age=18,sex=,signature=你眼中的世界就是你自己的样子2
反序列化后的结果: name=tyshawn,age=18,sex=null,signature=你眼中的世界就是你自己的样子2

第六、static属性为什么不会被序列化?
因为序列化是针对对象而言的, 而static属性优先于对象存在, 随着类的加载而加载, 所以不会被序列化.
看到这个结论, 是不是有人会问, serialVersionUID也被static修饰, 为什么serialVersionUID会被序列化? 其实serialVersionUID属性并没有被序列化, JVM在序列化对象时会自动生成一个serialVersionUID, 然后将我们显示指定的serialVersionUID属性值赋给自动生成的serialVersionUID.

欢迎大家积极留言交流学习心得,点赞的人最美丽!

相关文章:

Java 序列化和反序列化为什么要实现 Serializable 接口

第一、序列化和反序列化 序列化&#xff1a;把对象转换为字节序列的过程称为对象的序列化. 反序列化&#xff1a;把字节序列恢复为对象的过程称为对象的反序列化. 第二、什么时候需要用序列化和反序列化呢? 当我们只在本地JVM里运行下Java实例, 这个时候是不需要什么序列化和…...

vite+vue3+ts中使用require.context | 报错require is not defined | 获取文件夹中的文件名

vitevue3ts中使用require.context|报错require is not defined|获取文件夹中的文件名 目录 vitevue3ts中使用require.context|报错require is not defined|获取文件夹中的文件名一、问题背景二、报错原因三、解决方法 一、问题背景 如题在vitevue3ts中使用required.context时报…...

C#(Csharp)我的基础教程(四)(我的菜鸟教程笔记)-Windows项目结构分析、UI设计和综合事件应用的探究与学习

目录 windows项目是我们.NET学习一开始必备的内容。 1、窗体类&#xff08;主代码文件窗体设计器后台代码文件&#xff09; 主窗体对象的创建&#xff1a;在Program类里面&#xff1a; Application.Run(new FrmMain());这句代码就决定了&#xff0c;当前窗体是项目的主窗体。…...

Flink: Only supported for operators

Exception in thread "main" java.lang.UnsupportedOperationException: Only supported for operators.at org.apache.flink.streaming.api.scala.DataStream.name(...

NSIDC定义的海冰相关概念

文章目录 相关概念Matlab绘图结果展示 相关概念 NSIDC 表示 “National Snow and Ice Data Center”&#xff0c;即美国国家雪和冰数据中心。NSIDC 是一个位于美国科罗拉多大学波尔得分校的研究中心&#xff0c;致力于收集、管理和分发全球雪和冰的科学数据。 Matlab绘图 cl…...

【码银送书第八期】《Python数据挖掘:入门进阶与实用案例分析》

摘要&#xff1a;本案例将主要结合自动售货机的实际情况&#xff0c;对销售的历史数据进行处理&#xff0c;利用pyecharts库、Matplotlib库进行可视化分析&#xff0c;并对未来4周商品的销售额进行预测&#xff0c;从而为企业制定相应的自动售货机市场需求分析及销售建议提供参…...

微信小程序底部tabBar不显示图标

现场还原 在设置微信小程序底部tabBar导航图标时&#xff0c;无论如何操作均无法显示在界面上 解决思路 问题1 图标类型 一开始以为不支持png类型&#xff0c;但查看官方API仅提示ICON尺寸大小 打开其他项目可以正常展示&#xff0c;排除图标类型问题 iconPath string 否 …...

PostgreSQL基操之角色、表空间、数据库与表

PostgreSQL基操之角色、表空间、数据库与表 角色创建与管理表空间创建与管理数据库创建与管理表创建与管理 角色创建与管理 PostgreSQL数据库里没有User的概念&#xff0c;只有Role的概念。有的Role可以用于登录数据库&#xff0c;这些Role与其他数据库中的用户等价。 --创建…...

【算法|滑动窗口No.1】leetcode209. 长度最小的子数组

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…...

11_博客管理系统_实现过程

项目初始化 创建项目文件夹进入文件夹&#xff0c;执行 npm init -y 命令安装 express 和 mongoose&#xff0c;npm install express mongoose创建项目入口文件&#xff0c;app.js 或 index.js在 app.js 中进行项目搭建配置网站的路由配置网站静态资源目录 配置静态页面 配置…...

安防视频监控平台EasyCVR集成到ios系统不能播放是什么原因?如何解决?

视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#…...

hutool实现文件上传与下载

<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.16</version></dependency> 文件上传需要创建一个表 Autowiredprivate SysFileInfoMapper sysFileInfoMapper;Value("${ty.…...

vue3学习源码笔记(小白入门系列)------provide和 inject 跨层级数据传递原理

目录 前言provideinject 总结 前言 需要从父组件向子组件传递数据时&#xff0c;会使用 props。对于层级不深的父子组件可以通过 props 透传数据&#xff0c;但是当父子层级过深时&#xff0c;数据透传将会变得非常麻烦和难以维护。 而依赖注入则是为了解决 prop 逐级透传 的问…...

【Python深度学习】目标检测和语义分割的区别

在计算机视觉领域&#xff0c;语义分割和目标检测是两个关键的任务&#xff0c;它们都是对图像和视频进行分析&#xff0c;但它们之间存在着明显的区别。本文将通过图像示例&#xff0c;详细阐述语义分割和目标检测之间的差异。 一、基本概念 1.1 语义分割&#xff08;Semantic…...

取消加考!自考专业调整,2026年起执行新计划!

就在2023年10月7日&#xff0c;广东省教育考试院发布《关于广东省高等教育自学考试专业调整有关事项的通知》&#xff0c;自学考试迎来新变化&#xff0c;本次专业调整政策性强&#xff0c;涉及面广&#xff0c;持续时间长&#xff0c;一起来看看具体说明~ 关于广东省高等教育自…...

项目串讲(后端)要讲哪些东西?

刚进入一家公司&#xff0c;leader说给你几天时间&#xff0c;对咱们的公司的项目熟悉熟悉&#xff0c;做一个串讲吧。我很慌&#xff0c;没有串讲过&#xff0c;啥也不知道&#xff0c;不知道该怎么写&#xff0c;不知道讲出来leader满不满意&#xff0c;这些都是我在串讲前的…...

区块链技术在供应链管理中的创新应用

区块链技术以其独特的不可篡改和透明性特点&#xff0c;正在逐步改变供应链管理的传统模式。本文将探讨区块链技术在供应链管理中的创新应用及其带来的效益。 区块链技术的出现为许多行业带来了创新的可能&#xff0c;其中之一就是供应链管理。通过区块链技术&#xff0c;企业可…...

tcp/ip协议2实现的插图,数据结构2 (9 - 章)

&#xff08;20&#xff09; 20 九章1 IP选项处理 ip_dooptions &#xff08;21&#xff09;...

嵌入式Linux裸机开发(六)EPIT 定时器

系列文章目录 文章目录 系列文章目录前言介绍配置过程前言 前面学的快崩溃了,这也太底层了,感觉学好至少得坚持一整年,我决定这节先把EPIT学了,下面把常见三种通信大概学一下,直接跳过其他的先学移植了,有些太多了内容。 介绍 EPIT(Enhanced Periodic Interrupt Timer…...

如何批量导出文件名?

如何批量导出文件名&#xff1f;在电商行业从事工作的一些同事可能经常会遇到这样的问题&#xff1a;需要将产品文件夹中的所有图片或产品名称导出到Excel工作表&#xff0c;在工作表中创建这些名称的超链接&#xff0c;并且可能会为每个产名称的后面填写一些相关信息&#xff…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...