Java序列化进阶:Java内置序列化的三种方式

Java序列化就是把Java对象按照一定的格式存到文件或者磁盘当中

序列化的进阶:即三种方式,任何一种方式都可以进行序列化和反序列化

如果将数据读写到文档,

一般通过 ObjectOutputStream 将数据写入到文件当中,就是一种序列化的过程;
通过 ObjectInputStream 将数据从文件中读出来,就是一种反序列化的过程

如果对数据不进行序列化系统就会抛出异常信息:java.io.NotSerializableException

查看ObjectOutputStream 的 writeObject0() 方法源码:

// 判断对象是否为字符串类型,如果是,则调用 writeString 方法进行序列化
if (obj instanceof String) {writeString((String) obj, unshared);
}
// 判断对象是否为数组类型,如果是,则调用 writeArray 方法进行序列化
else if (cl.isArray()) {writeArray(obj, desc, unshared);
}
// 判断对象是否为枚举类型,如果是,则调用 writeEnum 方法进行序列化
else if (obj instanceof Enum) {writeEnum((Enum<?>) obj, desc, unshared);
}
// 判断对象是否为可序列化类型,如果是,则调用 writeOrdinaryObject 方法进行序列化
else if (obj instanceof Serializable) {writeOrdinaryObject(obj, desc, unshared);
}
// 如果对象不能被序列化,则抛出 NotSerializableException 异常
else {
if (extendedDebugInfo) {throw new NotSerializableException(cl.getName() + "\n" + debugInfoStack.toString());
} else {throw new NotSerializableException(cl.getName());
}
}

 ObjectOutputStream 在序列化的时候,会判断被序列化的对象是哪一种类型,字符串?数组?枚举?还是 Serializable,如果全都不是的话,抛出 NotSerializableException

1、实现Serializable接口

使用默认的序列化机制,即实现Serializable接口即可,不需要实现任何方法。

该接口没有任何方法,只是一个标记而已,告诉Java虚拟机该类可以被序列化了。然后利用ObjectOutputStream进行序列化和用ObjectInputStream进行反序列化。

注意:

该方式下序列化机制会自动保存该对象的成员变量static成员变量transient关键字修饰的成员变量不会被序列化保存。如:

import java.io.Serializable;
import java.util.List;public class SerializeTest implements Serializable {private static final long serialVersionUID = 213424233;private String name;private static String teacher;private final int bornYear;private static final String mother="mother";private transient int age;private transient List<String> friends;SerializeTest(){bornYear  = 2010;}
@Overridepublic String toString() {return "SerializeTest{" +"name='" + name + '\'' +", bornYear=" + bornYear +", teacher=" + teacher +", age=" + age +", friends=" + friends +'}';}
}

要序列化的对象

看看序列化和反序列化效果:

 SerializeTest test = new SerializeTest();test.setName("myName");test.setAge(18);List<String> friends = new ArrayList<String>();friends.add("friendOne");friends.add("friendTwo");test.setFriends(friends);test.setTeacher("myTeacher");try {//序列化到文件ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\user\\serialTest")));oos.writeObject(test);System.out.println("序列化:"+test.toString());test.setTeacher("myTeacher2");//从文件反序列化ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\user\\serialTest")));SerializeTest objRead = (SerializeTest) ois.readObject();System.out.println("序列化后:"+objRead.toString());} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}

序列化和反序列化结果

序列化:SerializeTest{name='myName', bornYear=2000, teacher=myTeacher, age=18, friends=[friendOne, friendTwo]}
序列化后:SerializeTest{name='myName', bornYear=2000, teacher=myTeacher2, age=0, friends=null}

transient 的中文字义为“临时的”(论英语的重要性),它可以阻止字段被序列化到文件中,在被反序列化后,transient 字段的值被设为初始值,比如 int 型的初始值为 0,对象型的初始值为 null

这是最简单的一种方式,因为这种方式让序列化机制看起来很方便(然后,我们在进行对象序列化时,只需要使用ObjectOutputStream和ObjectInputStream的writeObject(object)方法和readObject()方法,就可以把传入的对象参数序列化和反序列化了,其他不用管)。有时候想自己来控制序列化哪些成员,还有如何保存static和transient成员?

再注意:

该方式下,反序列化时不会调用该对象的构造器,但是会调用父类的构造器,如果父类没有默认构造器则会报错。static字段是类共享的字段,当该类的一个对象被序列化后,这个static变量可能会被另一个对象改变,所以这就决定了静态变量是不能序列化的,但如果再加上final修饰,就可以被序列化了,因为这是一个常量,不会改变。

2、实现Externalizable接口

Externalizable接口是继承自Serializable接口的,我们在实现Externalizable接口时,必须实现writeExternal(ObjectOutput)和readExternal(ObjectInput)方法,在这两个方法下我们可以手动的进行序列化和反序列化那些需要保存的成员变量。

public class SerializeExternalTest implements Externalizable {private static final long serialVersionUID = 213424233;private String name;private static String teacher;private final int bornYear;private static final String mother="mother";private transient int age;private transient List<String> friends;SerializeExternalTest(){bornYear  = 2000;}@Overridepublic void writeExternal(ObjectOutput out) throws IOException {out.writeUTF(name);out.writeUTF(teacher);out.writeInt(bornYear);out.writeUTF(mother);out.writeInt(age);out.writeObject(friends);}@Overridepublic void readExternal(ObjectInput in) throws ClassNotFoundException, IOException {this.name = in.readUTF();this.teacher = in.readUTF();//this.bornYear = in.readInt();final的不能改变值//this.mother = in.readUTF();final的不能改变值in.readInt();in.readUTF();this.age= in.readInt();this.friends = (List<String>) in.readObject();}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getTeacher() {return teacher;}public void setTeacher(String teacher) {SerializeExternalTest.teacher = teacher;}public int getBornYear() {return bornYear;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public List<String> getFriends() {return friends;}public void setFriends(List<String> friends) {this.friends = friends;}}

Externalizable

public void externalizableT(){SerializeExternalTest test = new SerializeExternalTest();test.setName("myName");test.setAge(18);List<String> friends = new ArrayList<String>();friends.add("friendOne");friends.add("friendTwo");test.setFriends(friends);test.setTeacher("myTeacher");try {//序列化到文件ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:\\user\\serialTest")));oos.writeObject(test);//从文件反序列化ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:\\user\\serialTest")));SerializeTest objRead = (SerializeTest) ois.readObject();} catch (IOException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}

Externalizable结果

反序列化时,首先会调用对象的默认构造器(没有则报错,如果默认构造器不是public的也会报错),然后再调用readExternal方法。

这种方式一定要显式的序列化成员变量,使得整个序列化过程是可控制的,可以自己选择将哪些部分序列化。

3、实现Serializable接口并添加writeObject和readObject方法

实现Serializable接口,在该实现类中再增加writeObject方法和readObject方法。该方式要严格遵循以下两个方法的方法签名:

writeObject和readObject

在这两个方法里面需要使用stream.defaultWriteObject()序列化那些非static和非transient修饰的成员变量,static的和transient的变量则用stream.writeObject(object)显式序列化。

在序列化输出的时候,writeObject(object)会检查object参数,如果object拥有自己的writeObject()方法,那么就会使用它自己的writeObject()方法进行序列化。readObject()也采用了类似的步骤进行处理。如果object参数没有writeObject()方法,在readObject方法中就不能调用stream.readObject(),否则会报错。

public class SeriCtrolTest implements Serializable {private String a;private String b;private transient String c;SeriCtrolTest(String a,String b ,String c){this.a = "非瞬时默认实现"+a;this.b = "非顺时非默认实现"+b;this.c = "瞬时实现:"+c;}private void writeObject(ObjectOutputStream stream) throws IOException {stream.defaultWriteObject();stream.writeObject(b);stream.writeObject(c);}private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {stream.defaultReadObject();stream.readObject();b="null";c = stream.readObject().toString();}@Overridepublic String toString() {return "SeriCtrolTest{" +"a='" + a + '\'' +", b='" + b + '\'' +", c='" + c + '\'' +'}';}public static void main(String[] args){SeriCtrolTest sCtrl = new SeriCtrolTest("test1","test2","test3");System.out.println("序列化之前");System.out.println(sCtrl);ByteArrayOutputStream out = new ByteArrayOutputStream();try {ObjectOutputStream oos = new ObjectOutputStream(out);oos.writeObject(sCtrl);} catch (IOException e) {throw new RuntimeException(e);}System.out.println("反序列化操作之后");ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());}
}

参考文献:

浅谈一下Java的Serializable 接口(序列化与反序列化)-CSDN博客

Java序列化进阶:Java内置序列化的三种方式-腾讯云开发者社区-腾讯云

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

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

相关文章

数据分析python基础实战分析

数据分析python基础实战分析 安装python&#xff0c;建议安装Anaconda 【Anaconda下载链接】https://repo.anaconda.com/archive/ 记得勾选上这个框框 安装完后&#xff0c;然后把这两个框框给取消掉再点完成 在电脑搜索框输入"Jupyter"&#xff0c;牛马启动&am…

简单聊聊云硬盘的规格

云硬盘类型及对应性能介绍 衡量云硬盘性能的指标有很多种&#xff0c;例如IOPS&#xff0c;吞吐量&#xff0c;读写时延&#xff1a; IOPS&#xff1a;云硬盘每秒进行读写的操作次数&#xff0c;可以细分到单盘最大IOPS&#xff0c;基线IOPS&#xff0c;IOPS突发上限等等。吞…

司美格鲁肽在中国获批!深度解析报告附上

在中国&#xff0c;肥胖问题日益严重&#xff0c;但有效的治疗方法却相对匮乏。然而&#xff0c;这一现状随着国家药品监督管理局&#xff08;NMPA&#xff09;对诺和诺德公司研发的司美格鲁肽注射液&#xff08;商品名&#xff1a;诺和盈&#xff09;的批准而得到改变。6月25日…

LabVIEW中卡尔曼滤波的作用与意义

卡尔曼滤波&#xff08;Kalman Filter&#xff09;是一种在控制系统和信号处理领域广泛应用的递推滤波算法&#xff0c;能够在噪声环境下对动态系统的状态进行最优估计。其广泛应用于导航、目标跟踪、图像处理、经济预测等多个领域。本文将详细介绍卡尔曼滤波在LabVIEW中的作用…

pytorch基础知识Tensor算术运算

1、Tensor的基本概念 标量是零维的张量&#xff0c;向量是一维的张量&#xff0c;矩阵是二维的张量 2、Tensor的创建 import torch"""常见的几个tensor创建""" a torch.Tensor([[1,2],[3,4]]) #2行2列的 print(a, a.type()) print(torch.on…

大数据平台需要存算分离吗?某保险集团:以 ZBS 优化资源利用率,缩短业务用时超一半

金融机构普遍采用“存算一体”架构支撑基于 Hadoop 框架的大数据平台。而随着金融业务的多元化发展&#xff0c;不同业务对计算和存储的需求差异较大&#xff0c;由于“存算一体”架构共享存储与计算资源&#xff0c;经常会出现资源需求不均衡、资源利用率低下、难以灵活调度等…

c++网络通信

TCP/IP协议 OSI参考模型采用分层划分原则&#xff0c;将网络中的数据传输划分为7层&#xff0c;其中&#xff0c;物理层居于最下层&#xff0c;是最基础、核心的网络硬件层&#xff1b;应用层居于最上层&#xff0c;负责应用资源的管理。每一层使用下层的服务&#xff0c;并向…

程序设计语言前言

1.机器语言及特点 2.编译语言及特点 3.高级语言及特点 4.编译和解释 5.IPO编程方式 一、机器语言 机器语言&#xff0c;也被称为二进制代码语言&#xff0c;是计算机硬件能够直接识别的程序语言或指令代码。它是由一系列由0和1组成的二进制指令码构成&#xff0c;每一条指令码…

【JavaScript脚本宇宙】轻松搞定代码调试和日志记录,你需要的都在这里!

掌握这几个JavaScript调试和日志库&#xff0c;让你的开发事半功倍&#xff01; 前言 在软件开发过程中&#xff0c;调试和日志记录是必不可少的环节。本文将介绍几个常用的JavaScript调试和日志记录库&#xff0c;包括debug、loglevel、Winston、Bunyan、Pino和Morgan&#…

drozer中文乱码解决方法

drozer简介 drozer 是 Android 的安全测试框架。 drozer 允许您通过扮演应用的角色并与 Android 运行时、其他应用的 IPC 端点和底层操作系统进行交互来搜索应用和设备中的安全漏洞。 drozer 提供了一些工具来帮助您使用、分享和理解公共 Android 漏洞。 drozer 是开源软件…

ESP32-C2模组数据透传模式配置详细教程

文章目录 1. 背景2. 关键步骤2.1 烧录AT指令固件2.2 配置透传模式2.3 如何退出透传模式重新配置3. 思考1. 背景 最近做的项目中,有蓝牙+WIFI的数据透传的需求,即系统A和系统B之间的通讯通过无线的方式,其实在实际项目中有很多这种场景比如无线调试手柄、无线数据终端、无线…

虚拟机热迁移详解:概念、架构、原理、搭建过程、常用命令与实战案例

一、虚拟机热迁移概述 1.1 虚拟机热迁移的定义 虚拟机热迁移&#xff08;Live Migration&#xff09;是指在不停止虚拟机运行的情况下&#xff0c;将其从一台物理主机迁移到另一台物理主机的过程。这一过程对用户和应用透明&#xff0c;几乎不会造成服务中断。热迁移技术在数…

状态压缩动态规划(State Compression DP)算法详解

状态压缩动态规划&#xff08;State Compression DP&#xff09;是一种高效解决组合优化问题的技术&#xff0c;特别适用于那些状态空间较大且可以用二进制表示的情况。本文将详细讲解状态压缩DP的原理、常用的位运算技巧、以及具体的例题分析。 原理概述 状态压缩DP的核心思…

【D3.js in Action 3 精译】1.2 D3 生态系统——入门须知

1.2 D3 生态系统——入门须知 D3.js 从不单打独斗&#xff0c;而是作为 D3 生态系统的一员&#xff0c;与生态内的一系列技术和工具相结合来创建丰富的 Web 界面。与其他网页一样&#xff0c;D3 项目也是充分利用 HTML5 的强大功能在 DOM 内构建出来的。尽管 D3 也可以创建并操…

大数据面试题之MapReduce(3)

reduce任务什么时候开始? 在Hadoop MapReduce中&#xff0c;Reduce任务的开始时间取决于几个关键因素&#xff1a;1、Map任务的完成情况&#xff1a; Reduce任务不能在所有相关的Map任务完成之前开始处理。但是&#xff0c;Hadoop允许在Map任务完成一定比例后就开始 执行Redu…

ElementUI搭建

概述 Element&#xff0c;一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组 件库. 安装 ElementUI npm 安装 推荐使用 npm 的方式安装&#xff0c;它能更好地和 webpack 打包工具配合使用。 npm i element-ui -S 在控制台输入此命令来安装ElementUI 在 main.j…

Leetcode 力扣 125. 验证回文串 (抖音号:708231408)

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s&#xff0c;如果它是 回文串 &#xff0c;返回 true &#xff1b;否则&#…

MyPostMan:按照项目管理接口,基于迭代生成接口文档、执行接口自动化联合测试

MyPostMan 是一款类似 PostMan 的接口请求软件&#xff0c;不同于 PostMan 的是&#xff0c;它按照 项目&#xff08;微服务&#xff09;、目录来管理我们的接口&#xff0c;基于迭代来管理我们的接口文档&#xff0c;可导出或者在局域网内共享&#xff0c;按照迭代编写自动化测…

netmiko_ssh_华为防火墙

from netmiko import ConnectHandlerip 防火墙ip地址hw_fw {device_type: huawei,host: ip, # 使用 host 字段同时指定 IP 和端口号username: 用户名,password: 密码,port: 50022 # 直接设置 port 字段 }net_connect ConnectHandler(**hw_fw)ou net_connect.send_command…

西安国际医学中心医院 多学科联合创新白癜风治疗法取得进展

近日&#xff0c;西安国际医学中心医院“自体头皮毛囊裂解物混悬液移植治疗白癜风”项目&#xff0c;备受瞩目。据悉&#xff0c;在白癜风和白发的研究及治疗上&#xff0c;均有望取得显著进展。 卢涛主任高分通过医院新技术新业务立项 “白癜风”——是由于皮肤黑素细胞被破坏…