Head First Java学习:第十四章-序列化和文件
第十四章 序列化和文件的输入输出
保存对象
1、什么是序列化和反序列化
在编程的世界当中,常常有这样的需求:我们需要将本地已经实例化的某个对象,通过网络传递到其他机器当中,为了满足这种需求,就有了所谓的序列化和反序列化。
序列化就是,把内存中的某个对象压缩成字节流的形式;
反序列化就是,把字节流转换成内存中的对象。
2、把序列化对象写入文件
四部曲:
// 创建出 FileOutputStream
FileOutputStream fs = new FileOutputStream("foo.ser");
// 创建ObjectOutputStream
ObjectOutputStream os = new ObjectOutputStream(fs);
// 写入对象
os.writeObject(myBox);
// 关闭ObjectOutputStream
os.close();
说明:
stream 串流,把stream连接起来代表源和目的地的连接,即文件和网络端口的连接。串流 必须要连接到某处才能算是个串流。
串流一般要俩俩连接才能做出有意义的事情,一个表示连接,一个要被调用方法。
按照单一设计原则,每个类做一件事情。
FileOutputStream 把字节写入文件。
ObjectOutputStream 把对象转换成可以写入串流的数据。
调用ObjectOutputStream的writeObject时,对象会被打成stream 送到FileOutputStream,来写入文件。
3、对象被序列化发生了什么?
在堆上的对象,有状态即实例变量的值。这些值让同一类的不同实例有不同意义。
被序列化的对象,保存了实例变量的值因此之后可以在堆上带回一模一样的实例。
实例变量的值和java虚拟机所需要的信息会被保存到文件中,一般是字节码或者xml编码格式文件。
对象的状态时什么,有什么需要保存?
对象的状态 –—— 实例变量的值
- 如果是 primitive 主数据类型,直接保存
- 如果是引用其他对象,那所有对象都被保存。
当对象被序列化,该对象引用的实例变量也会被序列化。且所有被引用的对象也会被序列化。这些操作都是自动进行的。
4、类要被序列化,就要实现 Serializable
objectOutputStream.writeObject(myBox);
myBox必须要实现序列化,否则执行会出问题。
如果序列化的类中,实例变量引用了非序列化的类,执行会报错。
Serializable接口没有任何方法需要实现,唯一目的是申明有实现它的类是可以被序列化的。某个类被序列化,其子类自动可以序列化。
举例:
package chap14;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Box implements Serializable {
private int width;
private int heigh;
public void setWidth(int w){
width = w;
}
public void setHeigh(int h){
heigh = h;
}
public static void main(String[] args) {
Box myBox = new Box();
myBox.setWidth(6);
myBox.setHeigh(7);
try{
// 创建出 FileOutputStream
FileOutputStream fs = new FileOutputStream("foo.ser");
// 创建ObjectOutputStream
ObjectOutputStream os = new ObjectOutputStream(fs);
// 写入对象
os.writeObject(myBox);
// 关闭ObjectOutputStream
os.close();
}catch (Exception ex){
ex.printStackTrace();
}
}
}
5、实例变量不想被序列化,标记为 transient 。
实例变量被标记为 transient ,序列化会跳过;
反序列化会设置为数据类型初始值,如primitive类型是0/0.0/false,引用类型是null。
6、反序列化步骤
举例:
// 1 创建FileInputStream
FileInputStream fileStream = new FileInputStream("foo.ser");
// 2 创建ObjectInputStream
ObjectInputStream os = new ObjectInputStream(fileStream);
// 3 读取对象
Object one = os.readObject();
Object two = os.readObject();
// 4 转换对象类型
GameCharacter elf = (GameCharacter) one;
GameCharacter troll = (GameCharacter) two;
// 5 关闭ObjectInputStream
os.close();
说明:
- 对象从stream中读出来
- java虚拟机通过存储的信息判断出对象的class类型
- java虚拟机尝试寻找和加载对象的类,如果虚拟机找不到或无法加载该类,则java虚拟机会抛出异常
- 新的对象会被分配带堆上,但是构造函数不会执行。因为执行构造函数,会把对象的状态抹去又变成全新,而这不是我们想要的结果。我们需要的是对象回到存储时的状态。
- 如果对象在继承树上有个不可序列化的祖先类,则该不可序列化类以及在它之上的类的构造函数(就算是可序列化)都会执行。一旦构造函数连锁启动之后将无法停止。也就是说,从第一个不可序列化的父类开始,全部都会重新初始状态。
- 对象的实例变量会被还原成序列化时点的状态值。transient变量会被赋值null的对象引用,primitive主数据类型的默认为0/0.0/false等值。
7、FileWriter 将字符串写入文本文件
用FileWritrer替代FileOutputStream,但是不会把它连接到 ObjectOutputStream上。
FileWriter b = new FileWriter(“FOO.txt”);
b.write(“hello foo@”);
b.close();
8、io.File class
File 对象代表磁盘上的文件或目录的路径名称,不代表读取或代表文件中的数据
如:/Users/Kathy/Data/GameFile.txt
File对象可以做的事情
- 创建出代表现存盘文件的File对象
举例:
File f = new File(“mycode.txt”);
- 建立新的目录
举例:
File dir = new File(“Chapter7”);
dir.mkdir();
- 列出目录下的内容
举例:
if(dir.isDirectoy){
String[] dirContents = dir.list();
for(int i=0;i<dirContents.length;i++){
sout(dirContents[i])
}
}
- 取得文件或目录的绝对路径
举例:
sout(dir.getAbsolutePath());
- 删除文件或目录(成功会返回true)
Boolean isDeleted = f.delete();
9、缓冲区
缓冲区的好处是同时把多个字符串写入文件,提高效率,节省了磁盘操作的时间。
举例:
BufferedWriter writer = new BufferedWriter(new FileWriter(aFile));
强制刷新缓冲区数据:writer.flush()
10、FileReader 读取文本文件
以File对象表示文件,以FileReader来执行实际的读取,并用BufferedReader 来让读取效率更高。
读取以while 循环来逐行进行,一直到readLine()的结果为null 为止。
举例:
package chap14;
import java.io.*;
public class ReadFile {
public static void main(String[] args) {
try{
// File 对象
File myFile = new File("/Users/huqiqi/Desktop/JavaStudy/JavaStudyCode/HeadFirstJavaMaster/src/main/java/chap14/MyText.txt");
// FileReader 是字符的连接到文本文件的串流
FileReader fileReader = new FileReader(myFile);
// 将FileReader 链接到BufferedReader 以获取更高的效率。
// 它只会在缓冲区读空的时候,才会回头区磁盘读取
BufferedReader reader = new BufferedReader(fileReader);
// 承接所读取的结果
String line = null;
// 读一行列一行直到没有东西可读取
while ((line = reader.readLine())!=null){
System.out.println(line);
}
reader.close();
}catch (Exception ex){
ex.printStackTrace();
}
}
}
结果:
hello
this is a file
test FileReader
11、String的split()
举例:
String toTest = "what is blue + yellow?/green?";
String[] result = toTest.split("/");
for(String token:result){
System.out.println(token);
}
结果:
what is blue + yellow?
green?
说明:String的split() 可以把字符串按照指定参数拆成两部分。
12、VersionID:序列化的识别
目的:做版本控制。
13、使用serialVersionUID
序列化是将对象的状态信息转换成可存储或传输的形式的过程。Java的对象保存在JVM的堆内存中,如果JVM堆不存在了,那么对象也就跟着消失了。
序列化提供了一种方案,可以让你在即使JVM停机的情况下也能把对象保存下来的方案。把Java对象序列化成可存储或传输的形式(如二进制流),比如保存到文件中。这样,当再次需要这个对象的时候,从文件中读取出二进制流,再从二进制流中反序列化对象。
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点就是 两个类的序列化ID是否一致,这个所谓的序列化ID,就是代码中定义的serialVersionUID。
Head First Java学习:第十四章-序列化和文件的更多相关文章
- “全栈2019”Java多线程第二十四章:等待唤醒机制详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第十四章:线程与堆栈详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java异常第十四章:将异常输出到文本文件中
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- “全栈2019”Java第八十四章:接口中嵌套接口详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第七十四章:内部类与静态内部类相互嵌套
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第六十四章:接口与静态方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第五十四章:多态详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第三十四章:可变参数列表
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- Java 学习笔记 ------第四章 认识对象
本章学习目标: 区分基本类型与类类型 了解对象与参考的关系 从打包器认识对象 以对象观点看待数组 认识字符串的特性 一."=" 和 "==" 当=用于基本类型时 ...
- JAVA学习第十四课(接口:implements及其基本应用)
接口: 我们知道抽象类中能够定义抽象方法,也能够定义非抽象方法.当一个抽象类中的方法都是抽象方法的时候,我们就能够定义还有一种表现方式:接口(interface),所以接口是一种特殊的抽象类 接口的出 ...
随机推荐
- 在 Android Studio Java 项目里混合 Kotlin 编程
首先,先搞明白一个概念,这里的 Java 混合 Kotlin 是指文件层级的混合,即 Java 代码还是写在 .java 文件中,Kotlin 代码还是写在 .kt 文件中,只不过是可以在 Java ...
- Mysql高级11-后台进程
一.前言 MySQL的服务实现通过后台多个线程.内存池.文件交互来实现对外服务的,不同线程实现不同的资源操作,各个线程相互协助,共同来完成数据库的服务.MySQL常用的后台线程概括如下,分为Maste ...
- Tomcat--文件上传--文件包含--(CVE-2017-12615)&&(CVE-2020-1938)
Tomcat--文件上传--文件包含--(CVE-2017-12615)&&(CVE-2020-1938) 复现环境 采用Vulfocus靶场环境进行复现,搭建操作和文章参考具体搭建教 ...
- scnhealthcheck
在CPU补丁中,Oracle提供了一个脚本 scnhealthcheck.sql 用于检查数据库当前SCN的剩余情况.该脚本的算法和以上描述相同,最终将最大合理SCN 减去当前数据库SCN,计算得出一 ...
- [SUCTF 2019]CheckIn 1
看到字符upload 就想到了文件上传漏洞 就先上传一个一句话木马试试 似乎直接上传不成功,可能是有什么过滤 再上传一个包含一句话木马的图片试试 发现提示不能是图片,这时候就不会了,在网上找了一下wp ...
- 数字时代的自我呈现:探索个人形象打造的创新工具——FaceChain深度学习模型工具
数字时代的自我呈现:探索个人形象打造的创新工具--FaceChain深度学习模型工具 1.介绍 FaceChain是一个可以用来打造个人数字形象的深度学习模型工具.用户仅需要提供最低一张照片即可获得独 ...
- .Net核心级的性能优化(GC篇)
1.前言 大部分人对于.Net性能优化,都停留在业务层面.或者简单的.Net框架配置层面.本篇来看下.Net核心部分GC垃圾回收配置:保留VM,大对象,独立GC,节省内存等.Net8里面有很多的各种G ...
- 12. 用Rust手把手编写一个wmproxy(代理,内网穿透等), TLS的双向认证信息及token验证
12. 用Rust手把手编写一个wmproxy(代理,内网穿透等), TLS的双向认证信息及token验证 项目 ++wmproxy++ gite: https://gitee.com/tickbh/ ...
- SQL还是NoSQL?架构师必备选型技能
很多时候我们都会有这样的疑问. 如果这时候直接去看MySQL.Mongo.HBase.Redis等数据库的用法.特点.区别,其实有点太着急了. 这时候,最好从「数据模型」开始讨论. 1.SQL vs ...
- 如何通过代码混淆绕过苹果机审,解决APP被拒问题
目录 iOS代码混淆 功能分析 实现流程 类名修改 方法名修改 生成垃圾代码 替换png等静态资源MD5 info.plist文件添加垃圾字段 功能分析 实现流程 类名修改 方法名修改 生成垃圾代码 ...