当前位置: 首页 > news >正文

【老白学 Java】对象序列化

对象序列化

码老白
文章来源:《Head First Java》修炼感悟。

前几篇文章主要讨论了 GUI 方面的一些内容,如果对游戏设计情有独钟的话,可以仔细研究一下 API 文档。 今天我们要讨论的是文件读写方面的相关操作,比如如何写入序列化对象,如何恢复序列化对象等等。

一、什么是对象序列化

假如你正在对某个闯关类游戏发起挑战,每次失败后就要从新开始,数十次后你是否会放弃? 假如可以保存当前所有状态,从失败处恢复,你会不会愿意去做更多尝试? 以上情形主要涉及到了文件存取问题。

我们知道,对象有行为和状态两种属性。 上述情景中从失败处重新恢复,实际上就是恢复对象某一时刻的状态,前提是已经保存过对象状态。 主要有两种方式用来保存状态:

  1. 对象序列化并写入文件中,需要时再读取文件反序列化恢复对象;
  2. 写入纯文本文件,方便其它程序解析。

对象序列化也被形象的称作「扁平化」处理,就好比抽空充气娃娃时的样子没了支撑,但还保留着基本特征;而反序列化则是重新充气的操作,可以完好地恢复原状。

序列化对象写入文件后,哪怕你想修改点什么也无从下手,一般人很难阅读理解,因为它是专门用于类加载器的。 所以说对象序列化相对比较安全,并且比纯文本文件更容易恢复。

二、把序列化对象写入文件中

将对象写入文件可分为四个基本步骤:

2.1、创建文件输出流 FileOutputStream

你可以把 FileOutputStream 对象理解为用来输送字节的管道,一端被连接到了文件上准备写入,另一端连接上游序列化对象,暂时还没连接。

FileOutputStream fs = new FileOutputStream("Save.ser");

2.2、创建对象输出流 ObjectOutputStream

ObjectOutputStream 可以理解为对象连接下游文件流的管道。

ObjectOutputStream os = new ObjectOutputStresam(fs);

2.3、写入序列化数据

两段管道都连接好了,开始写入数据,字节会源源不断地流进文件中。

os.writeObject(states);

2.4、关闭对象输出流

最后,关闭对象输出流,相当于关闭上游管道阀门。

os.close();

结果上面的处理,states 对象就会写入 Save.ser 文件中,结束写入过程。

三、保存对象状态

对象状态,即对象实例变量的值,可以是基本数据类型,也可以是引用数据类型。 基本数据类型只要保存变量值就可以,引用类型变量要如何处理呢? 如果引用类型变量又带有其他的引用类型变量呢?

实际情况就是,对象序列化操作时,与之关联的所有引用变量都会被序列化。 这个过程就像树根一样向外延伸,只要被波及到都会被执行这个操作。 过程看起来相当复杂,但你也没必要过分担心,因为这一切都是由虚拟机处理的,你只要坐享其成就可以了。

实现 Serializable 接口

如果想要序列化一个对象,这个对象就必须实现 Serializable 接口。 该接口没有定义任何方法,只作为一个序列化标识,就是说,实现了Serializable 接口即表示该类可以被序列化。

可以想象一下,当你上线后发现强10武器变成了没有任何属性的白武器,你会不会抓狂? 所以必须确保序列化完整,否则就会出现残缺不全的数据结构,必定会出乱子。 Serializable 接口就是为此制定的强制遵守的协议,你不遵守就不允许序列化。

下面请看一个例子:

import java.io.*;
// 演示如何进行对象的序列化操作
public class Swordsman implements Serializable {private Weapon weapon = new Weapon();public static void main(String[] args) {Swordsman sm = new Swordsman();try {FileOutputStream fs = new FileOutputStream("swordsman.ser");ObjectOutputStream os = new ObjectOutputStream(fs);os.writeObject(sm);os.close();} catch (Exception e) {e.printStackTrace();}}
}
// 该类没有实现 Serializable 接口
class Weapon {// TODO:
}

编译、运行结果:
序列化异常
上面代码可通过编译,但运行时抛出了序列化异常。 原因就是序列化 Swordsman 实例对象时,同时也会序列化 Weapon 的实例变量,而 Weapon 并没有实现 Serializble 接口。

解决这个问题也很简单,Weapon 实现 Serializable 接口即可。 此时类文件目录中应该多出了一个 swordsman.ser 文件,内容如下:

swordsman.ser

使用 transient 忽略序列化

假如你不想让某个实例变量被序列化,或者该变量本就不应该被序列化,可以使用 transient 关键字修饰,从而忽略该变量的序列化。 比如:

// 使用关键字 transient 忽略序列化操作
public class Swordsman implements Serializable {String userName = "Gioliye";			// 可以被序列化transient Weapon weapon = new Weapon(); // 不会被序列化public static void main(String[] args) {// TODO:}
}
// 并没有实现 Serializable 接口
class Weapon {// TODO:
}

内容预告

下一篇文章再来了解一下反序列化操作,尝试从文件中恢复对象到原始状态。


《 上一篇 Box 布局管理器下一篇 对象反序列化 》

http://www.mrgr.cn/news/82555.html

相关文章:

  • 前端学习-操作元素属性(二十三)
  • IDEA 撤销 merge 操作(详解)
  • 《深度剖析:开源与闭源模型,AI舞台上的不同角色》
  • PDF2Audio - 阅读 PDF 的新方式
  • DVWA 命令注入写shell记录
  • ModuleNotFoundError: No module named XXX
  • Qt:子线程在程序退出时的操作
  • 使用 PyTorch 自定义数据集并划分训练、验证与测试集
  • 第十一章 图论
  • C语言 - 理解函数栈帧
  • 服务器信息整理
  • Rosbag常见使用汇总
  • 一文讲清楚HTTP常见的请求头和应用
  • 【算法不挂科】算法期末考试【选择题专项练习】<多单元汇总>
  • C++例程:使用其I/O模拟IIC接扣(2)
  • SAP SD销售模块常见BAPI函数
  • pandas-栗子
  • Arduino UNO 驱动1.8 TFT屏幕显示中文
  • 软件逆向之标志位
  • 公共数据授权运营系统建设手册(附下载)
  • Tableau数据可视化与仪表盘搭建-数据连接
  • C语言:结构体
  • 【Rust自学】10.4. trait Pt.2:trait作为参数和返回类型、trait bound
  • 每天你好20250105(距离春节24天!!!)
  • 「C++笔记」unordered_map:哈希化的无序映射函数(键值对)
  • BerOS 文件系统路径归一化问题及其 Python 实现