JAVA序列化

  对象序列化(object serialization)是java支持的通用机制,可以将任何对象写出到流中,并在之后将其回读。简单来说,就是可以将对象数据保存为文件,甚至可以通过网络传输,在这之后或者别的主机上恢复当前保存的数据状态。

  • 序列化:把Java对象转换为字节序列的过程
  • 反序列:把字节序列恢复为Java对象的过程

序列化方式

序列化方式:Serializable接口和Externalizable接口两种方式。
1.Seriallizable接口
Serializable接口是一个标记接口,没有方法或字段。一旦实现了此接口,就标志该类的对象就是可序列化的。

public interface Serializable {
}

2.Externalizable接口
Externalizable继承了Serializable接口,还定义了两个抽象方法:writeExternal()和readExternal(),如果开发人员使用Externalizable来实现序列化和反序列化,需要重写writeExternal()和readExternal()方法

public interface Externalizable extends java.io.Serializable {void writeExternal(ObjectOutput out) throws IOException;void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

Java序列化常用API

java.io.ObjectOutputStream
java.io.ObjectInputStream
java.io.Serializable
java.io.Externalizable

java.io.ObjectOutputStream类

表示对象输出流,它的writeObject(Object obj)方法可以对指定obj对象参数进行序列化,再把得到的字节序列写到一个目标输出流中。

java.io.ObjectInputStream

表示对象输入流,它的readObject()方法,从输入流中读取到字节序列,反序列化成为一个对象,最后将其返回。

序列化ID

Java提供了两种方式来生成序列化ID:默认方式和自定义方式。
1.如果类没有显式声明serialVersionUID字段,Java会根据类的结构信息自动生成一个序列化ID。生成算法通常是基于类的名称、字段、方法等生成一个哈希值。
2.如果类显式声明了serialVersionUID字段,Java会使用该字段的值作为序列化ID。

import java.io.Serializable;class Person implements Serializable {
//默认方式生成序列化IDprivate static final long serialVersionUID = 1L;private String name;private int age;// constructor, getters, setters, etc.
}class Person implements Serializable {
//自定义方式生成IDprivate static final long serialVersionUID = 123456789L;private String name;private int age;// constructor, getters, setters, etc.
}

  实现Serializable接口时,不是必须要有Serializable id,但建议为每个可序列化的类都提供一个Serializable id。这个id可以保证在序列化和反序列化过程中,对象的唯一性和一致性。如果没有提供Serializable id,Java会自动生成一个id,但这样可能会导致在不同的JVM中生成的id不一致,从而导致序列化和反序列化失败。因此,为了保证可序列化类的兼容性和稳定性,建议为每个可序列化的类都显式地提供一个Serializable id。

在进行Java序列化时需要注意如下事项:

(1)类要实现序列化功能,只需实现java.io.Serializable接口即可
(2)在进行序列化和反序列化时必须保持序列化ID的一致,一般使用private static final long serialVersionUID定义序列化ID
(3)序列化并不保存静态变量
(4)在需要序列化父类变量时,父类也需要实现Serilizable接口
(5)使用Transient关键字可以阻止该变量被序列化,在被反序列化后,transient变量的值被设置为对应类型的初始值。例如,int类型变量的是0,Object类型变量的值是null
具体的序列化实现代码如下:

import java.io.Serializable;
//通过实现Serializable接口定义可序列化的Worker类
public class Worker implements Serializable{//定义序列化的IDprivate static final long serialVersionUID = 123456789L;//name属性将被序列化private String name;//transient修饰的变量不会被序列化private transient int salary;//静态变量属于类信息,不属于对象的状态,因此不会被序列化static int age=100;public String getName(){return name;}public void setName(String name){this.name = name;}}

注意:transient修饰的属性和static修饰的静态属性不会被序列化。
  对象通过序列化后在网络上传输,基于网络安全,我们可以在序列化前将一些敏感字段(用户名、密码、身份证号)使用密钥进行加密,在反序列化后再基于密钥对数据进行解密。这样即使数据在网络中被劫持,由于缺少密钥也无法对数据进行解析,这样可以在一定程度上保持序列化对象的数据安全。
  我们可以基于JDK原生的ObjectOutputStream和ObjectInputStream类实现对象的序列化及反序列化,并调用其writeObject()和readObject()方法实现自定义序列化策略。具体的实现代码如下:

import java.io.*;
import java.lang.reflect.*;
import java.util.*;public class Main {public static void main(String[] args) throws Exception {//序列化数据到磁盘long serializationstartTime = System.currentTimeMillis();FileOutputStream fos = new FileOutputStream("work.out");ObjectOutputStream oos = new ObjectOutputStream(fos);for(int i=0;i<5000000;i++){Worker testObject  = new Worker();testObject.setName("alex"+i);oos.writeObject(testObject);}oos.flush();oos.close();long serializationEndTime = System.currentTimeMillis();System.out.println(String.format("java serialization user time:%d",(serializationEndTime-serializationstartTime)));//反序列化磁盘数据并解析数据状态FileInputStream fis = new FileInputStream("work.out");ObjectInputStream ois = new ObjectInputStream(fis);Worker worker = null;try{while((worker = (Worker) ois.readObject())!=null){//worker为反序列化后的对象}}catch(EOFException e){ //在文件读取完成时会抛出EOFException}long deserializationEndTime = System.currentTimeMillis();System.out.println(String.format("java deserialization use timme:%d",(deserializationEndTime-serializationEndTime)));}}

实际开发中实现对象的序列化,通常使用的是第三方工具,而不是JDK原生的ObjectOutputStream和ObjectInputStream类。

序列化的应用:

1.序列化机制可以将对象保存到硬盘上,减轻内存压力,也起到了持久化的作用。
2.序列化机制是Java对象实现在RPC(远程过程调用)或者网络中传输。
注:序列化在实际使用过程中除了使用Java的序列化技术来实现,还可以使用FastJson等序列化框架来实现。

相关问题

1.serialVersionUID有什么用?

  JAVA序列化的机制是通过判断类的serialVersionUID来验证版本是否一致的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID和本地相应实体类的serialVersionUID进行比较,如果相同,反序列化成功,如果不相同,就抛出InvalidClassException异常。

2.为什么需要手动指定serialVersionUID

  在Java中,当一个类实现了Serializable接口并需要进行序列化和反序列化操作时,Java会自动生成一个默认的serialVersionUID。但是,由于默认的serialVersionUID是基于类的内部结构自动生成的,因此当类的内部结构发生改变时,serialVersionUID的值也会发生变化。这就会导致序列化和反序列化操作时版本不匹配的问题,从而无法正确地反序列化对象。
  为了避免这个问题,可以手动指定一个稳定的serialVersionUID。手动指定serialVersionUID可以确保在类的内部结构发生变化时,serialVersionUID的值不会改变,从而保证对象的序列化和反序列化操作的正确性。
  需要注意的是,如果两个类的serialVersionUID相同,但是它们的实现并不兼容(比如字段数量或类型不同),则在反序列化时也会出现问题。因此,即使serialVersionUID相同,也不能保证两个类可以相互转换。

注意:实际开发中不要随意修改serialVersionUID,阿里巴巴开发手册中,第四章OOP规约的第13条解释如下:

【强制】序列化类新增属性时,请不要修改serialVersionUID字段,避免反序列失败;如果 完全不兼容升级,避免反序列化混乱,那么请修改serialVersionUID值。说明:注意serialVersionUID不一致会抛出序列化运行时异常。

4.为什么不推荐jdk自带的序列化

  • 不支持跨语言调用 : 如果调用的是其他语言开发的服务的时候就不支持了。
  • 性能差:相比于其他序列化框架性能更低,主要原因是序列化之后的字节数组体积较大,导致传输成本加大。
  • 存在安全问题:序列化和反序列化本身并不存在问题。但当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码。

5.在 Java 中,Serializable 和 Externalizable 有什么区别

  Externalizable继承了Serializable,给我们提供 writeExternal() 和 readExternal() 方法, 让我们可以控制 Java的序列化机制, 不依赖于Java的默认序列化。正确实现 Externalizable 接口可以显著提高应用程序的性能。

6.序列化时,如何让某些成员不要序列化?

  可以用transient关键字修饰,它可以阻止修饰的字段被序列化到文件中,在被反序列化后,transient 字段的值被设为初始值,比如int型的值会被设置为 0,对象型初始值会被设置为null
  static静态变量和transient 修饰的字段是不会被序列化的。静态(static)成员变量是属于类级别的,而序列化是针对对象的。transient关键字修字段饰,可以阻止该字段被序列化到文件中。

7.如果要序列化的不同对象,其属性都指向了同一个对象,怎么办?
  对此,Java核心卷2的解释是:每个对象都是用一个序列号(serial number)来保存的。也就是说,序列化的每个对象关联的都是一个序列号,而不再是运行时的内存地址。
处理的具体算法为:
保存对象

  • 每个对象引用都关联一个序列号;
  • 对每个对象,第一次遇到时,保存其输出对象到输出流中;
  • 如果某个对象之前已经被保存过,那么只写出“与之前保存过的序列号为x的对象相同”;

恢复对象
通过读回恢复对象,整个过程反过来。

  • 对于输入流中的对象,在第一次遇到其序列号时,构建它,并使用流中数据初始化它,然后记录这个顺序号和新对象之间的关联。

  • 当遇到“与之前保存过的序列号为x的对象相同”标记时,获取与这个顺序号相关联的对象引用。

8.如果子类实现了子类实现了Serializable接口,父类没有实现Serializable接口的话,父类不会被序列化。反序列化时子类的父类属性就会丢失。
9.序列化是针对对象的,故static成员变量属于类级别不能被序列化。如果某个序列化类的成员变量是对象类型,则该对象类型的类必须实现序列化。
10.序列化机制提供了一种克隆对象的简单途径,只要对应的类是可序列化即可。做法很简单:直接将对象序列化到输出流中,然后将其读回。这样产生的新对象是对现有对象的一个深拷贝。在此过程中,我们不必将对象写出到文件中,因为可以用ByteArrayOutputStream将数据保存到字节数组中。虽然这个方法很灵巧,但它通常会比显示地构建新对象并复制或克隆数据域的克隆方法慢得多。

关于浅拷贝、深拷贝、序列化实现深拷贝的参考:
https://blog.csdn.net/demo_yo/article/details/116159275
https://blog.csdn.net/m0_37128231/article/details/81912327

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

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

相关文章

企业如何开展百科营销?需要创建哪些百科词条?

在营销工作实践中&#xff0c;小马识途营销顾问经常接到关于百科营销的咨询&#xff0c;现整理了最受关注的九个问题分享给热爱营销工作的小伙伴。 一、什么是百科营销&#xff1f; 百科营销是借助百科知识传播&#xff0c;可以将企业、品牌、人物所拥有的对用户有价值的信息&a…

Redis的优化

1 Redis的高可用 1.1 高可用的定义 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%、99.99%、99.999%等等&#xff09;。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&…

RTSP网络视频协议

一.RTSP网络视频协议介绍 RTSP是类似HTTP的应用层协议&#xff0c;一个典型的流媒体框架网络体系可参考下图&#xff0c;其中rtsp主要用于控制命令&#xff0c;rtcp主要用于视频质量的反馈&#xff0c;rtp用于视频、音频流从传输。 1、RTSP&#xff08;Real Time Streaming P…

【群晖NAS】记一次FRP报错:login to server failed: connection write timeout

报错如下&#xff1a; rongfuDS224plus:~/fff/frp$ ./frpc -c ./frpc.toml 2024/01/12 23:08:31 [I] [root.go:139] start frpc service for config file [./frpc.toml] 2024/01/12 23:08:41 [W] [service.go:131] login to server failed: i/o deadline reached 2024/01/12 2…

人工智能:未来智慧城市建设的“智慧大脑”与核心价值

目录 一、引言 二、人工智能在智慧城市中的应用实例 三、人工智能对智慧城市建设的核心价值 四、面临的挑战与未来展望 五、结语 六、附&#xff1a;智慧城市全套解决方案大合集 - 下载 一、引言 随着科技的飞速发展&#xff0c;智慧城市的概念逐渐深入人心。智慧城市利…

70、C++ - 仓库目录结构介绍

如上文所说,后面的优化基本都是基于 C++ 版本的代码来进行的,如果没有 C++ 的编程经验,可以顺便依托这个小的 C++ 项目来学一些 C++ 的基础知识。 后面涉及 C++ 部分的内容,我也会尽可能写的详细一些。 在进行 C++ 部分之前,先介绍一下 C++ 的代码仓库。 仓库链接还是在…

python爬虫实战(10)--获取本站热榜

1. 需要的类库 import requests import pandas as pd2. 分析 通过分析&#xff0c;本站的热榜数据可以直接通过接口拿到&#xff0c;故不需要解析标签&#xff0c;请求热榜数据接口 url "https://xxxt/xxxx/web/blog/hot-rank?page0&pageSize25&type" #本…

最全Linux驱动开发全流程详细解析(持续更新)

Linux驱动开发详细解析 一、驱动概念 驱动与底层硬件直接打交道&#xff0c;充当了硬件与应用软件中间的桥梁。 具体任务 读写设备寄存器&#xff08;实现控制的方式&#xff09;完成设备的轮询、中断处理、DMA通信&#xff08;CPU与外设通信的方式&#xff09;进行物理内存…

vim文本编辑器,常用命令

目录 1、常用模式 2、基本移动光标 3、插入和替换文本 4、删除和复制文本 5、搜索和替换 6、保存和退出 Vim是一款功能强大的文本编辑器&#xff0c;在Linux系统中被广泛使用。它提供了丰富的编辑和操作功能&#xff0c;适用于编程、文件编辑、配置文件修改等各种任务。 …

linux创建文件并分配权限

linux中对文件的定义 在Linux中&#xff0c;文件是一个具有符号名字的一组相关联元素的有序序列。文件可以包含的内容十分广泛&#xff0c;操作系统和用户都可以将具有一定独立功能的一个程序模块、一组数据或一组文字命名为一个文件。文件名是数据有序序列集合&#xff08;文…

聚焦老年生活与健康,“老有所依·情暖夕阳”元岗街社区微型养老博览会顺利开展

尊老敬老是中华民族的传统美德&#xff0c; 爱老助老是全社会的共同责任。 家有一老&#xff0c;如有一宝&#xff0c; 长者的生活情况是一个家庭的头等大事&#xff0c; 做好长者服务是街道和社区的重要工作。 2024年1月6日&#xff0c;由元岗街道党工委、元岗街道办事处、…

开源C语言库Melon:红黑树

本文对Melon库中的红黑树进行介绍&#xff0c;关于Melon库&#xff0c;这是一个开源的C语言库&#xff0c;它具有&#xff1a;开箱即用、无第三方依赖、安装部署简单、中英文文档齐全等优势。 Github repo 简介 红黑树是一种被应用的非常广泛的数据结构&#xff0c;用于快速搜…

MySQL 8.0中新增的功能(五)

改进哈希连接性能 MySQL 8.0.23重新实现了用于哈希连接的哈希表&#xff0c;从而改进了哈希连接的性能。这项工作包括修复了一个问题&#xff08;Bug&#xff03;31516149&#xff0c;Bug&#xff03;99933&#xff09;&#xff0c;在这个问题中&#xff0c;用于连接缓冲区&am…

PyQt5系列之核心模块与控件

一、模块介绍 1、QtCore:包含了核心的非GUI的功能。主要和时间、文件与文件夹、各种数据、流、URLs、mime类文件、进程与线程一起使用 2、QtGui:包含了窗口系统、事件处理、2D图像、基本绘画、字体和文字类 3、QtWidgets:包含了一些列创建桌面应用的UI元素 二、QtWidgets使用介…

真正的强大,原来是不动声色的

当一个人走过了绝境&#xff0c;他就会发现&#xff0c;真正的强大&#xff0c;原来是不动声色的。 他会停止一切自证&#xff0c;不再解释&#xff0c;话越来越少&#xff0c;眼神越来越坚定。 他不再模棱两可&#xff0c;唯唯诺诺&#xff0c;而是敢于断然拒绝&#xff0c;…

Veeam Backup12安装备份恢复ESXI7.0 U3虚拟机

介绍 只需单个平台即可保护并管理所有工作负载、应用及数据&#xff1a;云端、虚拟、物理、SaaS、Kubernetes、VMware、Hyper-V、Windows、Linux、UNIX、NAS、AWS、Azure、企业应用等。 个人主要用于备份ESXi上的虚拟机&#xff0c;可以实现单次完整备份&#xff0c;和定时的…

Vue3 的基本开发+新特性

Vue3 1.Vue3 1. Vue2 选项式 API vs Vue3 组合式API <script> export default {data(){return {count:0}},methods:{addCount(){this.count}} } </script> <script setup> import { ref } from vue const count ref(0) const addCount ()> count.val…

小H靶场笔记:Empire-Breakout

Empire&#xff1a;Breakout January 11, 2024 11:54 AM Tags&#xff1a;brainfuck编码&#xff1b;tar解压变更目录权限&#xff1b;Webmin&#xff1b;Usermin Owner&#xff1a;只惠摸鱼 信息收集 使用arp-scan和namp扫描C段存活主机&#xff0c;探测靶机ip&#xff1a;1…

作业--day45

定时播放 #include "mywidget.h" #include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent) :QWidget(parent),ui(new Ui::MyWidget) {ui->setupUi(this);ui->bg_lab->setPixmap(QPixmap(":/pictrue/shanChuan.jpg"));ui->bg_…

AJAX入门到实战,学习前端框架前必会的(ajax+node.js+webpack+git)(六)

《诗小雅小旻》&#xff1a;“战战兢兢&#xff0c;如临深渊&#xff0c;如履薄冰。” 01.Nodejs安装与使用 什么是 Node.js&#xff1f; 什么是前端工程化&#xff1f; Node.js 为何能执行 JS&#xff1f; 查看当前使用的Node.js版本&#xff1a;node -v 执行JS&#xff1a;no…