一文搞懂序列化

news2024/11/25 10:06:21

参考自:
1.https://mp.weixin.qq.com/s/K135j6_t0npqt7E1Su8zhA
2. https://zhuanlan.zhihu.com/p/499806202

文章目录

    • (1) 序列化和反序列化是什么?
    • (2) 什么时候需要用到序列化和反序列化呢?
    • (3) 实现序列化和反序列化为什么要实现Serializable接口?
    • (4) 手动实现序列化和反序列化?
    • (5) 实现Serializable接口就算了, 为什么还要显示指定serialVersionUID的值?
    • (6) Java序列化的其他特性
    • (7) 父子序列化

(1) 序列化和反序列化是什么?

序列化:把java对象转换为字节序列的过程称为对象的序列化.

反序列化:把字节序列恢复为java对象的过程称为对象的反序列化.

(2) 什么时候需要用到序列化和反序列化呢?

当我们只在本地JVM里运行下Java实例, 这个时候是不需要什么序列化和反序列化的, 但当我们需要将内存中的对象持久化到磁盘, 数据库中时, 当我们需要与浏览器进行交互时, 当我们需要实现RPC时, 这个时候就需要序列化和反序列化了.

前两个需要用到序列化和反序列化的场景, 是不是让我们有一个很大的疑问? 我们在与浏览器交互时, 还有将内存中的对象持久化到数据库中时, 好像都没有去进行序列化和反序列化, 因为我们都没有实现Serializable接口, 但一直正常运行.

下面先给出结论:

只要我们对内存中的对象进行持久化或网络传输, 这个时候都需要序列化和反序列化.

理由:

服务器与浏览器交互时真的没有用到Serializable接口吗? JSON格式实际上就是将一个对象转化为字符串, 所以服务器与浏览器交互时的数据格式其实是字符串, 我们来看来String类型的源码:

public final class String
    implements 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接口的基本属性.

(3) 实现序列化和反序列化为什么要实现Serializable接口?

可以发现接口中什么也没有,这其实是Java中的标识语义,用来告诉JVM帮我在底层进行序列化和反序列化。如果不实现这个接口,就只能手动实现序列化和反序列化代码了,如下

(4) 手动实现序列化和反序列化?

Java.IO.ObjectOutputStream代表对象输出流。writeObject(Object obj)方法可对参数指定的obj对象进行序列化。
Java.IO.ObjectInputStream代表对象输入流,它的readObject()方法可以反序列化。

/**
 * 序列化
 */
File file = new File(pathName);
ObjectOutputStream oos=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
//序列化
oos.writeObject(list);

/**
 * 反序列化
 */
File file = new File(pathName);
ObjectInputStream oin=new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)));
//反序列化
Object object = oin.readObject();

具体案例看:https://blog.csdn.net/qq_42665745/article/details/128111377的命令模式实现日志持久化

(5) 实现Serializable接口就算了, 为什么还要显示指定serialVersionUID的值?

  • 序列化时:如果不指定serialVersionUID,JVM会帮我们根据类中的属性生成一个serialVersionUID,然后进行序列化,最后进行持久化或者数据传输;

  • 反序列化时:JVM会根据属性生成一个新的serialVersionUID,然后将这个新的serialVersionUID与序列化时的serialVersionUID进行比对,如果相同,则反序列化成功,否则失败!

  • 当我们指定了serialVersionUID时,JVM也会生成一个serialVersionUID,但它会将我们指定的serialVersionUID赋给生成的,这样就保证了UID一致性。

在实际开发中, 不显示指定serialVersionUID的情况会导致什么问题? 如果我们的类写完后不再修改, 那当然不会有问题, 但这在实际开发中是不可能的, 我们的类会不断迭代, 一旦类被修改了, 那旧对象反序列化就会报错. 所以在实际开发中, 我们都会显示指定一个serialVersionUID, 值是多少无所谓, 只要不变就行.

案例:
1.实体类

@Data
@ToString
public class User implements Serializable {

    private String name;

    private Integer age;
}

2.测试类

public class Test {

    private static void serialize(User user) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("C:\\Users\\Lenovo\\Desktop\\test.txt")));
        oos.writeObject(user);
        oos.close();
    }

    private static User deserialize() throws Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("C:\\Users\\Lenovo\\Desktop\\test.txt")));
        return (User) ois.readObject();
    }

    public static void main(String[] args) throws Exception {
        User user = new User();
        user.setName("cong");
        user.setAge(20);
        System.out.println("序列化前的结果: " + user);

        serialize(user);

        User dUser = deserialize();
        System.out.println("反序列化后的结果: "+ dUser);
    }
}

3.结果
在这里插入图片描述

测试错误情况:

  • 修改user类,加个属性phone
  • 再注释序列化方法,执行反序列方法

1.修改实体类

@Data
@ToString
public class User implements Serializable {

    private String name;

    private Integer age;

    private String phone;
}

2.注释序列化方法

public static void main(String[] args) throws Exception {
    User user = new User();
    user.setName("cong");
    user.setAge(20);
    user.setPhone("110");
    System.out.println("序列化前的结果: " + user);

//        serialize(user);

    User dUser = deserialize();
    System.out.println("反序列化后的结果: "+ dUser);
}

3.结果
在这里插入图片描述
报错信息,可以看到有两个serialVersionUID在比较

Exception in thread "main" java.io.InvalidClassException: com.yida.vo.contract.User; local class incompatible: stream classdesc serialVersionUID = 951362248228968412, local class serialVersionUID = -7408572177048388061

实体类加上serialVersionUID 就不会报错了

private static final long serialVersionUID = 1L;

(6) Java序列化的其他特性

transient关键字修饰的属性不会被序列化, static属性也不会被序列化.因为静态变量属于类的状态,序列化并不保存静态变量!

(7) 父子序列化

结论:

  • 当父类实现序列化时,子类所有的属性也会全部被序列化;
  • 当父类没有实现序列化,子类在序列化时,父类属性并不会被序列化!

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

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

相关文章

如何快速搜索多个文件中内容是否有你需要的东西?

有没有这么的经历&#xff0c;我想搜索自己电脑里有没有想要的文件&#xff0c;这时大家应该可以&#xff1a; 方案一、windows自带搜索 方案二、Everything 那如果要搜索的不是文件名称而是文件的内容呢&#xff1f; 重点来了&#xff01;&#xff01;&#xff01;&#xff0…

Git commitId 压缩(推送远程和未推送远程)

背景&#xff1a; 代码提交后&#xff0c;基于review 风格&#xff0c;和代码整洁度&#xff0c;以及后续业务划分&#xff0c;需要对commitId进行压缩操作 核心思想 基于rebase命令进行合并操作 场景一 commitId提交本地且推送远程 1、准备数据 准备所有已经提交且推送远…

切换模糊化的自适应滑模控制

目录 前言 1.系统描述 2.控制器设计 3.模糊逼近切换项 4.仿真分析 4.1仿真系统 4.2仿真模型 4.3仿真结果 4.4结论 5.总结 前言 前面两篇文章分别介绍了切换增益模糊化和系统不确定项f或g模糊化&#xff0c;其原理都是使用模糊控制对未知量进行估计&#xff0c;上两篇…

uni vuex 组件及常用api

vuex 在store>index.js //导入vue import Vuex from vuex //导入Vue import Vue from vue //使用Vuex Vue.use(Vuex) //导出Vuex export default new Vuex.Store({//状态state:{gTitle:{text:你好,color:#000,fontSize:"24px",background:#f70},joks:[]},//改变状…

循环神经网络(四)

一、循环神经网络和自然语言处理介绍 目标 知token和tokenization知道N-gram的概念和作用知道文本向量化表示的方法 1.1 文本的tokenization 1.1.1 概念和工具的介绍 tokenization 就是通常所说的分词&#xff0c;分出的每一个词话我们把它称为token。 常见的分词工具很多…

【Android App】物联网中查看手机支持的传感器及实现摇一摇功能-加速度传感器(附源码和演示 超详细)

需要源码请点赞关注收藏后评论区留言~~~ 一、传感器的种类 传感器Sensor是一系列感应器的总称&#xff0c;是Android设备用来感知周围环境和运动信息的工具。 因为具体的感应信息依赖于相关硬件&#xff0c;所以虽然Android定义了众多感应器&#xff0c;但是并非每部手机都能支…

JZ-7Y-15 AC220V【静态中间继电器】

系列型号&#xff1a; JZ-7Y-15静态中间继电器&#xff1b; JZ-7J-15静态中间继电器&#xff1b; JZ-7L-15静态中间继电器&#xff1b; JZ-7D-15静态中间继电器&#xff1b; JZ-7Y-16静态中间继电器&#xff1b; JZ-7J-16静态中间继电器&#xff1b; JZ-7L-16静态中间继电器&am…

【Redis-07】Redis哨兵机制Sentinel的实现原理

Sentinel是Redis高可用性的解决方案&#xff1a;由一个或者多个Sentinel实例组成的哨兵系统监视多个主从服务器&#xff0c;并实现主从服务器的故障转义。  Sentinel本质上只是一个运行在特殊模式下的Redis服务器&#xff0c;使用以下命令可以启动并初始化一个Sentinel实例&am…

Express 4 快速入门 - 基本路由

Express Express 中文网 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 文章目录Express4 快速入门 - 基本路由4.1 什么是路由4.2 定义简单路由4.2.1 在主页回复字符串4.2.2 响应/应用程序主页根路由 ( ) 上的 POST 请求&#xff1a;4.2.3 响应对/user路…

订单超时自动取消3种方案——我们用这种!

大家好&#xff0c;大家对电商购物应该都比较熟悉了&#xff0c;我们应该注意到&#xff0c;在下单之后&#xff0c;通常会有一个倒计时&#xff0c;如果超过支付时间&#xff0c;订单就会被自动取消。 下单 今天&#xff0c;我们来聊聊订单超时未支付自动取消的几种方案。 1…

【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【02】Nacos、Feign、Gateway

持续学习&持续更新中… 学习态度&#xff1a;守破离 【雷丰阳-谷粒商城 】【分布式基础篇-全栈开发篇】【02】微服务的几大组件SpringCloud Alibaba 简介简介为什么使用版本选择Nacos作为注册中心Feign声明式远程调用Nacos作为配置中心基本使用核心概念命名空间&#xff1…

【Linux】进程通信 | 信号

本篇博客让我们一起来康康信号部分的内容 系统为CentOS7.6&#xff0c;完整代码见 Gitee 文章目录1.什么是信号1.1 何为异步?1.2 信号的种类1.3 信号产生1.4 信号动作2.系统接口2.1 signal2.1.1 前台进程和后台进程2.1.2 循环捕捉所有信号2.1.3 信号9/192.2 kill2.2.1 killall…

人工智能数学基础--概率与统计13:连续随机变量的标准正态分布

一、引言 在《人工智能数学基础–概率与统计12&#xff1a;连续随机变量的概率密度函数以及正态分布》介绍了连续随机变量概率分布及概率密度函数的概念&#xff0c;并介绍了连续随机变量一个重要的概率密度函数&#xff1a;正态分布的概率密度函数的定义以及推导、使用场景&a…

培养出最多亿万富翁的美国大学TOP10榜单

若论世界大学排名&#xff0c;除了U.S. News、QS、软科、泰晤士这四大权威排名外&#xff0c;另有一些依据不同指标的排名。下面知识人网小编就推荐这份福布斯榜单给出的美国大学排名&#xff0c;供感兴趣的读者围观。 福布斯去年发布了一份全球亿万富豪榜&#xff08;World’s…

怎么看网站域名有没有收录 收录情况怎么样 网站收录查询

对于网站收录的概念&#xff0c;互联网中或者搜索引擎中已经有大量的相关定义。网站收录&#xff0c;指的是爬虫爬取了网页&#xff0c;并将页面内容数据放入搜索引擎数据库中这一结果。 怎么看网站域名有没有收录?录情况怎么样? 用站长工具查询网站收录的操作步骤&#xff1…

[TIST 2022]No Free Lunch Theorem for Security and Utility in Federated Learning

联邦学习中的安全性和实用性没有免费午餐定理 No Free Lunch Theorem for Security and Utility in Federated Learning 目录摘要简介2 相关文献2.1 隐私测量2.2 联邦学习2.2.1 FL 中的威胁模型。2.2.2 FL 中的保护机制。2.3 隐私-实用权衡3 一般设置和框架3.1 符号3.2 一般设置…

前端如何实现网页变灰功能的?

备注&#xff1a;本文大量摘取前端充电宝公众号相关文章&#xff0c;大家感兴趣可以关注该公众号进行阅读学习 目录 1.引入 2.页面灰色实现方法 3.filter其他属性 A.blur()&#xff1a;模糊 B.brightness()&#xff1a;亮度 C.contrast()&#xff1a;对比度 C.opacity()…

unity---Mesh网格编程(六)

目录 1.模型切割 2.代码 1.模型切割 如图&#xff0c;对3D模型的Mesh网格进行切割&#xff0c;会经过若干个三角面。而切割后&#xff0c;将会产生新的面来组成左右两边的物体。 要记录每个顶点与顶点下标&#xff0c;新的面要顺时针绘制&#xff0c; 2.代码 using System.…

docker+nginx 安装部署修改资源目录配置文件和容器端口信息

查看docker镜像 可以先查看docker下是否存在nginx镜像&#xff0c;使用如下这些命令查看&#xff1a; docker images: 列出所有镜像。docker images nginx: 列出所有nginx镜像&#xff0c;不同版本等等。docker search nginx: 搜索查看所有nginx镜像信息。 拉取安装nginx镜像…

Java8 函数式编程【基础篇】

Java 8是Java在保持向后兼容的前提下首次迈出重要一步&#xff0c;相比之前&#xff0c;不再是只对类库的改良&#xff0c;在编写复杂的集合处理、并行化执行、代码简洁度等方面都有颠覆性的提升。本文将探索和理解函数式编程的含义&#xff0c;以及它在Java 8中的实现。 一、…