Head First Java学习笔记(14):序列化和文件的输入/输出

对象可以被序列化也可以展开
对象序列化的步骤:

1.创建出FileOutputStream
FileOutputStream fileStream = new FileOutputStream("MyGame.ser");//如果文件不存在,它会自动创建出来
2.创建ObjectOutputStream
ObjectOutputStream os = new ObjectOutputStream(fileStream);
3.写入对象
os.writeObject(characterOne);
os.writeObject(characterTwo);
os.writeObject(characterThree);//将变量所引用的对象序列化并写入MyGame.ser这个文件
4.关闭ObjectOutputStream
os.close();

串流

将串流连接起来代表来源与目的地(文件或网络端口)的连接。串流必须要连接到某处才能算是个串流。Java的输入输出API带有连接类型的串流,它代表来源与目的地之间的连接,连接串流即把串流与其它串流连接起来。
在这里插入图片描述

对象序列化

1.在堆上的对象有状态——实例变量的值。这些值让同一类的不同实例有不同的意义。
2.序列化后的对象保存了实例变量的值,因此之后可以在堆上带回一模一样的实例。
3.序列化程序会将对象版图上的所有东西存储起来。被对象的实例变量所引用的所有对象都会被序列化。
4.静态变量不会被序列化,因为所有对象都是共享同一份静态变量值。

如果要让类能够被序列化,就实现Serializable接口。
如果某类是可序列化的,则它的子类也自动地可以序列化。
如果某实例变量不能或不应该被序列化,就把它标记为transient的。

import java.net.*;
class Chat implements Serializable {
	transient String currentID;
	String userName;
	// more code
}

解序列化

1.创建FileInputStream
FileInputStream fileStream = new FileInputStream(“MyGame.ser”);//文件不存在会抛出异常
2.创建ObjectInputStream
ObjectInputStream os = new ObjectInputStream(fileStream);
3.读取对象
Object one = os.readObject();
Object two = os.readObject();
Object three = os.readObject();//每次调用都会从stream中读取下一个对象
4.转换对象类型
GameCharacter elf = (GameCharacter) one;
GameCharacter troll = (GameCharacter) two;
GameCharacter magician = (GameCharacter) three;
5.关闭ObjectInputStream
os.close();

**解序列化时发生的事:
1.对象从流中读取
2.JVM通过存储的信息判断对象的class类型。
3.JVM尝试查找并加载对象的类。如果JVM无法找到或加载类,JVM抛出一个异常和反序列化失败。
4.在堆上给一个新对象空间,但构造函数不执行!显然,对象的状态会被抹去又变成全新的,而那不是我们想要的。我们希望还原对象到存储时的状态。
5.如果对象在它的继承树的某个地方有一个不可序列化的父类,该不可序列化类的构造函数将与它上面的类的构造函数一起执行。一旦构造函数连锁启动后无法停止,这意味着从第一个不可序列化的父类开始,全部都会重新初始化。
6.对象的实例变量会被还原为序列化时的状态值。transient变量会被值为null的对象引用或primitive主数据类型的默认值(0,false,等等)。
在这里插入图片描述

写入文本文件

import java.io.*;
class WriteFile {
	public static void main(String[] args) {
		try {
			FileWriter writer = new FileWriter("Foo.txt");
			writer.write("hello foo!");
			writer.close();
		} catch(IOException ex) {
			ex.printStackTrace();
		}
	}
}

java.io.File class

File对象代表磁盘上的文件或目录的路径名称,但它并不能读取或代表文件中的数据。

可以对File做的事情:
1.创建出代表现存盘文件的File对象:
File f = new File("MyCode.txt");
2.建立新的目录:
File dr = new File("Chapter14");
dir.mkdir();
3.列出目录下的内容:
if(dir.isDirectory()) {
	String[] dirContents = dir.list();
	for(int i =0;i<dirContents.length;i++) {
		System.out.println(dirContents[i]);
	}
}

缓冲区

缓冲区的好处在于使用缓冲区比不使用缓冲区的效率要好。

BufferedWriter writer = new BufferedWriter(new FileWriter(aFile));

只有调用writer.flush()就可以要求缓冲区马上把内容写下去。
在这里插入图片描述
读取文本文件:

import java.io.*;
class ReadAFile {
	public static void main (String[] args) {
		try {
			File myFile = new File(“MyText.txt”);
			FileReader fi leReader = new FileReader(myFile);
			BufferedReader reader = new BufferedReader(fi leReader);
			String line = null;
			while ((line = reader.readLine()) != null) {
				System.out.println(line);
			}
				reader.close();
		} catch(Exception ex) {
				ex.printStackTrace();
		}
	}
}

解析字串

String的split()会用参数所指定的字符把字符串拆开成String的数组。

序列化的识别

1.每当对象被序列化的同时,该对象都会盖上上一个类的版本识别ID,这个ID被称为serialVersionUID。当对象解序列化时,如果对象序列化后类被修改,导致有了不同的serialVersionUID,则还原会失败。
2.如果你认为类有可能会演化,就把版本识别ID放在类中,让类在演化的过程中维持相同的ID。
3.JDK中的serialver工具可以查询类的serialVersionUID。

当类有可能演化时:
1.使用serialver工具取得版本ID。
在这里插入图片描述
2.把输出拷贝到类上

public class Dog {
	static final long serialVersionUID = -6849794470754667710L;
	private String name;
	private int size;
	// method code here
}

3.在修改类的时候要确定修改程序的后果。例如新的类要能够处理旧的对象解序列化后新加入变量的默认值。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值