详解Java的IO流Part6:对象序列化流/反序列化流和transient瞬态关键字

限时加码!20+主AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

Java提供了一种对象序列化的机制:
用一个字节序列可以表示一个对象 该字节序列包含该对象的数据 类型 和 对象中存储的属性等信息
字节序列写出到文件之后 相当于文件中持久保存了一个对象的信息

反之 该字节序列还可以从文件中读取回来 重构对象 对它进行反序列化
对象的数据 对象的类型和对象中存储的数据信息 都可以用来在内存中创建对象
例:Person p=new Person("陈涛",18)


一、ObjectOutputStream 对象序列化流

ObjectOutputStream类将Java对象的原始数据类型写出到文件 实现对象的持久存储
java.io.ObjectOutputStream对象序列化流继承了OutputStream
将对象以流的方式写入到文件中保存

构造方法:

public ObjectOutputStream(OutputStream out):创建一个指定OutputStream的ObjectOutputStream
参数:OutputStream out 字节输出流

特有的成员方法:

writeObject(Object obj):将指定的对象写入ObjectOutputStream

使用步骤:

1创建ObjectOutputStream对象 构造方法中传递字节输出流
2、使用ObjectOutputStream对象对象中的writeObject()方法 将对象写入到文件中
3释放资源

慢着!怎么出现了这个异常 咋回事啊

NotSerializableException异常处理:

Exception in thread “main” java.io.NotSerializableException: objectStream.Person
在这里插入图片描述
java.io.Serializable接口:未实现此接口的类将无法使其任何状态序列化或反序列化

Serializable 是一个标记接口 里面没有任何方法 仅仅起到一个标记的作用
不实现此接口的类将不会使任何状态序列化或反序列化 会抛出NotSerializableException

当进行序列化和反序列化操作的时候 会检测类上是否有这个标记
若有:可以序列化和反序列化
若没有:抛出NotSerializableException异常

public class Person implements Serializable {
    private String name;
    private int age;
    ...
}
public static void main(String[] args) throws IOException {
    // 创建ObjectOutputStream对象 构造方法中传递字节输出流
    ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("F:\\IdeaProjects\\filetest\\person.txt"));
    // 使用ObjectOutputStream对象对象中的writeObject()方法 将对象写入到文件中
    oos.writeObject(new Person("陈涛",18));
    // 释放资源
    oos.close();
}

二、ObjecInputStream 对象反序列化流

ObjectInputStream反序列化流 可将之前使用ObjectOutputStream序列化的原始数据恢复为对象

构造方法:

public ObjectInputStream(InputStream in):创建一个指定InputStream的ObjectInputStream
参数:
InputStream in 字节输入流

特有的成员方法:

Object readObject():从ObjectInputStream读取对象
readObject()方法会抛出ClassNotFoundException异常(Class文件找不到异常)
当不存在对象的class文件时 会抛出此异常
因此 反序列化的前提:
1、该类必须实现java.io.Serializable接口
2、必须存在该类对应的class文件

使用步骤:

1、创建ObjectInputStream对象 构造方法中传递字节输入流
2、使用ObjectInputStream对象中的readObject()方法 读取保存对象的文件
3、释放资源
4、使用读取出的对象

public static void main(String[] args) throws IOException, ClassNotFoundException {
    // 创建ObjectInputStream对象 构造方法中传递字节输入流
    ObjectInputStream ois=new ObjectInputStream(new FileInputStream("F:\\IdeaProjects\\filetest\\person.txt"));
    // 使用ObjectInputStream对象中的readObject()方法 读取保存对象的文件
    Object object = ois.readObject();
    // 释放资源
    ois.close();
    // 使用读取出的对象
    System.out.println(object);
    System.out.println(((Person)object).getName()+((Person)object).getAge());
}

transient 瞬态关键字

static关键字:静态关键字
优先于非静态加载到内存中 因此 被static修饰的成员变量是不能被序列化
因为只能对对象进行序列化操作 而被静态关键字修饰后不属于对象

transient关键字:瞬态关键字
当读取的属性为静态属性时 序列化后会无法正常反序列化 会读取不到数据 使用该属性的默认值
被transient修饰的成员变量不能被序列化 只是没有静态的功能 仅仅只是不能被序列化而已
例:private transient int age


总结:反序列化的前提

1、该类必须实现java.io.Serializable接口
Serializable是一个标记接口 里面没有任何方法 仅仅起到一个标记的作用
不实现此接口的类将不会使任何状态序列化或反序列化 会抛出 NotSerializableException异常
2、该类的所有属性必须是可序列化的
若有一个属性不需要可序列化的 则该属性必须注明是瞬态的 使用transient关键字修饰


为啥又出现异常了?

InvalidClassException异常

当JVM反序列化对象时 若能找到class文件 但class文件在序列化对象之后发生了修改 那么反序列化操作也会失败
此时会抛出一个InvalidClassException异常
例:Exception in thread "main" java.io.InvalidClassException: objectStream.Person; local class incompatible: stream classdesc serialVersionUID = 1120242798634133694, local class serialVersionUID = 8382704104194838558

造成该异常的可能原因:

1、该类的序列版本号与从流中读取的类描述符的版本号不匹配
2、该类包含未知数据类型
3、该类没有可访问的无参数构造方法

原理:

编译器(javac)会将java文件编译成class文件
当类实现了Serializable接口 会根据类里定义的属性和方法给class文件添加一个名为serialVersionUID序列号
当序列化保存到文本中的时候 文本中也会添加这条序列号

当进行反序列化操作的时候 会使用class文件和txt文件中的序列号进行比较
若两个序列号相匹配 则反序列化成功
若两个序列号不匹配 则抛出InvalidClassException序列化冲突异常

每次修改类的定义都会重新为class文件生成一个全新的序列号

解决方式:

可以手动给类添加一个序列号

可序列化类可以通过声明名为serialVersionUID的字段显式声明其自己的serialVersionUID
(该字段必须为static final的long类型字段)
例:
该serialVersionUID属性的值可以任意填入

public class Person implements Serializable {
	private static final long serialVersionUID = 1L;
	private String name;
	public int age;
	...
}

Unity 升级引擎版本后构建报错:script class layout is incompatible between the editor and the player Unity升级引擎版本后,项目报错:script class layout is incompatible between the editor and the player。 阅读详情

相关推荐

在已有win10系统下安装Ubuntu,最后出现执行‘grub-install/dev/nvme0n1p5‘失败的致命错误的解决方案

本人电脑型号戴尔灵越,两个SSD512G固态硬盘,c盘为系统盘. Ubuntu版本为20.04LTS,在官网下载https://ubuntu.com/download/desktop/thank-you?version=20.04.3&architecture=amd64 系统盘制作工具为Rufus-3.15http://rufus.ie/zh/ 安装过程网上很多,在这里就不赘述了. 其他安装过程都很顺利,直至安装最后出现这个 本来安装了到最后还以为成了,结果又不行...... 后.

XiaoChen_gugugu的博客 1万+

java传送对象序列化遇到的问题

https://blog.csdn.net/ouyang_peng/article/details/46448877 我的Java开发学习之旅------>Java使用ObjectOutputStreamObjectInputStream序列号对象java.io.EOFException异常的解决方法 预防丢失,但是问题没有完全解决 问题: java.io.EOFExce...

wordpython 303

AI幻觉缓解的成本效益分析:投入产出比优化

在当今AI技术飞速发展的时代,AI幻觉成为了一个不容忽视的问题。AI幻觉就像是AI在“做梦”,会给出一些不符合实际或者错误的答案。我们这篇文章的目的就是要分析缓解AI幻觉所需要投入的成本能够获得的效益,看看怎么能让投入产出的比例达到最优。范围涵盖了常见的AI应用场景,比如智能客服、自动驾驶等领域。接下来,我们会先介绍一些AI幻觉、成本效益分析相关的术语。然后用一个有趣的故事引出核心概念,解释什么是AI幻觉、成本效益分析等,以及它们之间的关系。

AI 原生应用开发的博客 914

Servlet 3.0之Part对象(文件上传)

之前使用Java处理文件上传需要引用各种库,但在servlet3.0之后java提供了文件上传对象,使用更加简单。 这里提供一个Servlet版本对照: 文件上传API HttpServletRequest 提供了两个方法用于从请求中解析上传的文件: Part getPart(String name): 用于获取请求中指定name的文件 Coolection< Part > getP...

凌风子夜 1万+

Java中的实体类--Serializable接口、transient 关键字

  在java中,实体类是一个非常重要的概念,我们可以在实体类中封装对象、设置其属性方法等。关于实体类,也经常涉及到适配器模式、装饰者模式等设计模式。那么在实际代码开发中,关于实体类的注意事项有哪些呢? 1. Serializable接口   实现该接口可以实现序列化,Serializable接口没有方法或字段,仅用于标识可序列化的语义。但是,如果一个类没有实现这个接口,想要...

320

对象专属、序列化反序列化、Serializable接口、transient关键字

文章目录序列化反序列化的理解通过对象专属实现序列化 序列化反序列化的理解 什么是序列化? 序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将转换为对象。这两个过程结合起来,可以轻松地存储传输数据 通过对象专属实现序列化 一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才能被序列化。 参与序列化反序列化对象,必须实现Serializable接口 注意: 通过源码发现,Serializeable接口只是一个标志接口: public in

大白的成长之路 756

对象序列化的细节,Static属性不参与对象的序列化

定义一个学生信息类    身高tall为静态属性输出为99   static属性定义在类文件中之后,在其他类中调用该属性,并更改了tall的值,只是更改了内存中tall的值,类文件中定义的tall并没有受到影响,在调用时,先把类文件加载到内存中 ,修改得只是内存中tall的值,类文件定义的信息没有发生改变。当重新创建一个类去调用tall时 这时把类文件重新加载到内存中, 输出的还是类文件中的值。所...

可爱的程序yuan 4099

Javase-day19-IO(缓冲,转换,序列化、transient关键字、打印

IO(缓冲,转换,序列化、transient、打印

流星的博客 444

java序列化(ObjectOutputStream)输出到反序列化(ObjectInputStream)及注意事项。

java序列化(ObjectOutputStream)输出到反序列化(ObjectInputStream)。 序列化(ObjectOutputStream) writeObject() 完成操作。 对象序列化,把Java对象转换为字节序列的过程称为对象的序列化。简单来说就是将内存中的对象存储到硬盘上或进行网络传输。 反序列化(ObjectInputStream) readObject()完成操作。 对象反序列化,把字节序列恢复为Java对象的过程称为对象反序列化。简单来说是将硬盘上的对象(或网络中)读

weixin_44854918的博客 411

[NettyRpc]-序列化框架的选型

序列化实现方式简介 序列化:将对象的状态信息转换为可存储或传输形式的过程,简言之,就是把对象转换为字节序列的过程就是对象的序列化 反序列化的过程:序列化的逆过程,将字节数组反序列化回复为对象的过程就是对象反序列化 使用序列化能够帮助我们解决如下几个问题 通过将对象序列化为字节数组,使得不共享内存网络的能够进行对象的传输 能够将对象永久存储到存储设备 解决了远程接口调用JVM之间内存无法共享的问...

weixin_41927235的博客 267

Java的File过滤器(FileFilterFilenameFilter)

public File[] listFiles() :返回一个File数组 表示该File目录中的所有的子文件或目录 listFiles()方法可传入两种参数实现文件的过滤 listFiles(FileFilter filter)listFiles(FilenameFilter filter) 1、FileFilter文件过滤器 java.io.FileFilter接口:用于抽象路径名(File...

"✧treasure mountain✧" 1万+

Java8的Lambda表达式(箭头函数)

函数式编程思想 在数学中 函数就是有输入量输出量的一套计算方案 也就是“拿什么东西做什么事情” 相对而言 面向对象过分强调必须通过对象的形式来做事情 而函数式思想则尽量忽略面向对象的复杂语法——强调做什么 而不是以什么形式做 面向对象的思想: 做一件事情 找一个能解决这个事情的对象 调用对象的方法 完成事情 函数式编程思想: 只要能获取到结果 谁去做的 怎么做的都不重要,重视的是结果 不重视过...

"✧treasure mountain✧" 1万+

SnowFlake雪花算法的介绍及Java实现(工具类)

一、概念 ❄ 什么是雪花算法 SnowFlake算法是Twitter公司出品的开源的分布式id生成算法 其特点为 使用一个64 bit的long型的数字作为全局唯一 id 雪花算法在分布式系统中的应用十分广泛 且引入了时间戳 基本保持自增的 ❄ 雪花算法字符串各部分的含义 第1位是符号位 始终为0 (这是因为生成的id都是正数 而在二进制中第一个bit若为0则不为负数) 后面是41位的时间戳 精确到毫秒级 41位的长度可以表示2^41-1个毫秒值 也就是说可以使用69年 时间戳还有一个很重要的作用 可以

"✧treasure mountain✧" 1万+

Java的抽象、接口(interface)与实现(implement)

一、abstract抽象类 抽象是什么?顾名思义,抽象就是很抽象…(废话 抽象类是一种思想 反映了很多类共有的一些特征 抽象方法在定义方法时不写方法体 不包含方法体 必须用abstract关键字来修饰 例: abstract void shout(); 1、抽象方法没有方法体 不能被调用 2、包含抽象方法的类必须声明为抽象类 但抽象类可以不包含任何抽象方法 3、抽象类不能被实例化 4、抽象类的子...

"✧treasure mountain✧" 9831

详解Java的File类(成员变量、构造方法及常用方法)

一、概述 java.io.File 类是文件目录路径名的抽象表示 主要用于文件目录的创建 查找删除等操作 Java将电脑中的文件文件夹目录封装为了一个File类 可以使用File类对文件文件夹进行操作 可以使用File的方法来: 创建一个文件/文件夹 删除文件/文件夹 获取文件/文件夹 判断文件/文件夹是否存在 对文件夹进行遍历 获取文件的大小 File类是一个与系统无关的类 任何操...

"✧treasure mountain✧" 9716

Java日期格式与文本格式的互相转化

一、将日期【格式化】地转化为String文本 1、先有日期,通过Date获取日期对象 Date date1=new Date(); 2、创建格式器对象DateFormat 创建日期格式化对象 DateFormat dateFormat1=DateFormat.getDateInstance(DateFormat.LONG);//可传入FULL LONG MEDIUM SHORT 四种参数 各有不...

"✧treasure mountain✧" 9211

Java的一维数组、二维数组及数组复制(arraycopy)

一维数组 ★定义一个数组 ☆方法1: 格式: int(数组格式)[](两个方括号) test(数组名) = new(表示初始化) int(数组格式) [(数字)例:100](表示数组里可以存放多少数据) 意思是创建新的100个存放int的数组交给test数组变量 例:定义a[10] 注意:此方法数组里的数据仓库编号是从0开始的 即 a[0]、a[1]…、a[10] ☆方法2: 格式: int(...

"✧treasure mountain✧" 9211

Java的字符串变量

创建 new = 创建 ☆方法1: String s = new String("a string"); 创建了一个String的对象 用"a string"初始化这个对象 创建管理这个对象的变量s 让s管理这个对象 ☆方法2: String s = "a string" 编译器自动创建一个String类的变量交给s管理 字符串的连接 用加号"+"连接 当"+"的一边是字符串而另一边不是时...

"✧treasure mountain✧" 9192

详解JavaIOPart1:字节输入(InputStream)字节输出(OutputStream)

计算机上数据的传输可以看做是一种数据的动 按照动的方向 以内存为基准 分为 输入input 输出output 即 向内存是输入 出内存的输出 :数据(字符 字节) 1个字符=2个字节 1个字节=8个二进制位 Java中I/O操作是使用 java.io 包下的内容进行输入输出操作 输入也叫做读取数据 将硬盘中的数据读取到内存中使用 输出也叫做作写出数据 将内存中的数据写入到硬盘中...

"✧treasure mountain✧" 9188

Java函数、静态(static)、类变量类函数

一、函数 在函数中可以直接写成员变量的名字来访问成员变量 那么究竟访问的是哪个对象的呢? 函数是通过对象来调用的 v.insertMoney() 此次调用临时简历了insertMoney()v之间的关系 让insertMoney()内部的成员变量指向的是v的成员变量 this this.XX==XX this是成员函数的一个特殊的固有的本地变量 它表达了调用这个函数的那个对象 static静...

"✧treasure mountain✧" 8946

Java的异常捕捉(Exception)

异常的概念:在Java当中 它是把所有异常信息封装起来 放在一个类里 当遇到异常时 会创建异常类对象 并且抛出 ExceptionError的区别: Exception:异常信息 - 发生异常的原因位置 是可以处理的 处理完之后 程序是可以继续执行的 在编译 运行时期都可能发生 Error:必须修改源程序才能解决(有些问题修改了源程序也未必能解决) 只有在运行的时候发生 无法解决 什么能扔(抛...

"✧treasure mountain✧" 8915
上一篇: SpringSecurity在SSM项目中的简单使用
下一篇: 详解Java的IO流Part7:PrintStream打印流【完结】
Piconjo_Official
博客等级 码龄8年 132粉丝 310原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值