Java实现 Serializable 序列化

2024-04-25 13:38

本文主要是介绍Java实现 Serializable 序列化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

深度理解Java实现 Serializable 序列化

概念

把对象转换为直接序列的过程叫对象的序列化

把字节序列恢复为对象的过程叫对象的反序列化

用途

  1. 对象持久化
  2. 跨网络数据交换,远程过程调用

对象持久化意味着一个对象的生命周期可以不取决于程序是否运行,实现序列化的对象可以生存在程序的调用之间。通过一个序列化的对象写在磁盘中,然后再调用期间恢复这个对象就可以实现对象持久化的效果

序列化可以弥补不同操作系统之间的差异,在某台电脑上创建一个的对象,将其序列化。通过网络传输就可以将其发送到另一台不同操作系统的电脑上,然后在那里准确的组装出这个对象不必关心字节的顺序或者其他细节。所以在向远程对象发送消息时,必须通过对象序列化来传输参数和返回值。

内部实现

让要实现序列化的类实现java.io.Serializable接口

需要注意的是Serializable没有定义任何方法,只是一个标记接口。

对象序列化是基于字节的,因此需要OutputStream和InputStream继承层次结构。

序列化对象过程:在序列化一个对象的过程中,会创建某些OutPutStream对象,将其封装在一个ObjectOutputStream对象内,之后调用writeObject()方法序列化对象。

反序列化对象:创建某些InputStream对象,并将其封装在一个ObjectInputStream 对象内,之后调用readObject()方法反序列化对象。

反序列化最后得到的是一个指向Object的引用,所以必须向下转型为指定类型的对象

序列化控制

默认的序列化机制已经很强大了,它可以自动将对象中的所有字段自动保存和恢复,但这种默认行为有时候不是我们想要的。比如,对于有些字段,它的值可能与内存位置有关,比如默认的hashCode()方法的返回值,当恢复对象后,内存位置肯定变了,基于原内存位置的值也就没有了意义。还有一些字段,可能与当前时间有关,比如表示对象创建时的时间,保存和恢复这个字段就是不正确的。

还有一些情况,如果类中的字段表示的是类的实现细节,而非逻辑信息,那默认序列化也是不适合的。为什么不适合呢?因为序列化格式表示一种契约,应该描述类的逻辑结构,而非与实现细节相绑定,绑定实现细节将使得难以修改,破坏封装。

Java提供了多种定制序列化的机制,主要的有三种,一种是transient关键字,另外一种是实现Externalizable接口代替实现Serializable,还有一种是实现writeObject和readObject方法。

将字段声明为transient,默认序列化机制将忽略该字段,不会进行保存和恢复。
比如上面的第一个实例中,假设我们在进行序列化和反序列化时不需要保存和恢复no字段的信息,那么我们可以在no字段前面加上一个transient修饰符。

private transient String no;

运行程序我们会得到如下的结果:

------------------序列化前--------------
[HashCode:366712642 学号:001 姓名:Ron 班级:Class 001, HashCode:1829164700 学号:002 姓名:Ron2 班级:Class 002]
------------------反序列化后--------------
[HashCode:2133927002 学号:null 姓名:Ron 班级:Class 001, HashCode:1836019240 学号:null 姓名:Ron2 班级:Class 002]

我们可以到no字段的内容反序列化之后变成了null。将字段声明为transient,不是说就不保存该字段了,而是告诉Java默认序列化机制,不要自动保存该字段了。

利用Serializable定义数据类型

在阅读源码时,遇到一些比较抽象的方法,发现他们定义的数据类型都是用Serializable来定义,比如

public void deleteEntriesByIDS(Serializable[] tds);public void deleteEntry(Serializable id);

这样做的原因是它可以接受多种数据类型,比如String,Integer,Long等,他们都实现了Serizlizable接口。同时JDK1,.5以后有了自动拆装箱的特征,所以均可被以上Serializable定义参数方法接受,这样做的目的就是可以节省代码,提高代码利用率。

有的方法也会利用它做返回值,同理

serialVersionUID的作用

序列化的作用是将对象的状态信息转换为可存储过程或传输形式的过程。Java对象是保存在JVM的堆内存里的,也就是说如果JVM堆不存在了,那么对象也就消失。而序列化提供了一种方案是:即使JVM停机的情况下也能把对象保存下来(把Java对象序列化成可存储或传输的形式,比如保存在文件中。下次需要这个对象时就可以从文件中读取出二进制流,再从二进制流中反序列化出对象)

虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致。还有一个非常重要的点是对比两个类的序列化ID(serialVersionUID)是否一致。

如果两个类的serialVersionUID不一致,在反序列化时就会抛出java.io.InvalidClassException,并且指出serialVersionUID不一致。

java.io.InvalidClassException: com.hollis.User1; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

这是因为,在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException

所以在《阿里巴巴Java开发手册》中才会有:在兼容性升级中,在修改类的时候,不要修改serialVersionUID的原因。除非是完全不兼容的两个版本。所以,serialVersionUID其实是验证版本一致性的。

如果一个类实现了Serializable接口,就必须手动添加一个private static final long serialVersionUID变量,并且设置初始值。如果不添加的话,系统会自己添加一个serialVersionUID,只要类稍加改变,就会重新生成,导致版本不兼容

这篇关于Java实现 Serializable 序列化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/934832

相关文章

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

Python脚本实现自动删除C盘临时文件夹

《Python脚本实现自动删除C盘临时文件夹》在日常使用电脑的过程中,临时文件夹往往会积累大量的无用数据,占用宝贵的磁盘空间,下面我们就来看看Python如何通过脚本实现自动删除C盘临时文件夹吧... 目录一、准备工作二、python脚本编写三、脚本解析四、运行脚本五、案例演示六、注意事项七、总结在日常使用

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Java访问修饰符public、private、protected及默认访问权限详解

《Java访问修饰符public、private、protected及默认访问权限详解》:本文主要介绍Java访问修饰符public、private、protected及默认访问权限的相关资料,每... 目录前言1. public 访问修饰符特点:示例:适用场景:2. private 访问修饰符特点:示例:

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

使用Python实现在Word中添加或删除超链接

《使用Python实现在Word中添加或删除超链接》在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能,本文将为大家介绍一下Python如何实现在Word中添加或... 在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能。通过添加超

windos server2022里的DFS配置的实现

《windosserver2022里的DFS配置的实现》DFS是WindowsServer操作系统提供的一种功能,用于在多台服务器上集中管理共享文件夹和文件的分布式存储解决方案,本文就来介绍一下wi... 目录什么是DFS?优势:应用场景:DFS配置步骤什么是DFS?DFS指的是分布式文件系统(Distr

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服