您的位置:首页 > 编程语言 > Java开发

Head First Java笔记(五)

2016-07-19 19:49 411 查看

序列化和文件的输入/输出

保存对象
1.序列化:可以让你的程序读取序列化对象
2.写纯文本文件:数据需要被其他程序引用。

对象序列化的方法:
1.创建出FileOutputStream
FileOutputStream fileStream = new FileOutputStream("MyGame.ser");
2.创建ObjectOutputStream
ObjectOutputStream os = new ObjectOutputStream(fileStream);
3.写入对象
os.writeObject(characterOne);
os.writeObject(characterTwo);
4.关闭ObjectOutputStream
os.close();



数据在串流(stream)中流动,它代表来源于目的地之间的连接。

对象被序列化时发生了什么?
1.堆上的对象有状态——实例变量的值
2.被序列化的对象,保存了实例变量的值



当对象被序列化时,被该对象引用的实例变量也会被序列化。

让类能够被序列化:实现Serializable接口:Serializable接口又称为marker或tag类标记用接口,没有任何方法需要实现。

序列化是全有或全无的。
如果某实例变量不能/不应该被序列化,就把它标记为transient(瞬时)的,恢复对象时transient的引用实例变量会返回null
序列化可以分辨两个对象是否相同。如果两个对象都有引用实例变量指向相同的对象,只有一个对象会被存储。

解序列化(Deserialization):还原对象
1.创建FileInputStream
FileInputStream fileStream = new FileInputStream("MyGame.ser");//文件不存在会抛出异常
2.创建ObjectInputStream
ObjectInputStream os = new ObjectInputStream(fileStream);
3.读取对象
Object one = os.readObject();//每次调用readObject读取一个对象,读取顺序和写入顺序相同
Object two = os.readObject();
4.转换对象类型
GameCharacter elf = (GameCharacter) one;
GameCharacter  troll = (GameCharacter) two;
5.关闭ObjectInputStream
os.close();//FileInputStream会自动跟着关掉


解序列化时发生了什么?
1.对象从stream中读出来
2.JVM通过存储的信息判断出对象的class类型
3.JVM尝试寻找和加载对象的类,如果找不到或无法加载类,JVM会抛出异常
4.新的对象会被配置在堆上,但是构造函数不会执行。
5.如果对象在继承树上有个不可序列化的祖先类,该不可序列化类以及它之上的类的构造函数就会执行。从第一个不可序列化的父类开始,全部都会重新初始状态。
6.对象的实例变量会被还原成序列化时的状态值,transient变量会被赋值null或原始数据类型的默认0\、false等值。



Q:为什么类不会存储成对象的一部分?这样就不会出现找不到类的问题了?
A:这样非常浪费且有很多额外的工作。对于通过网络传送序列化对象来说,事实上有一种机制让类使用URL来定位,该机制用在Java的Remote Method Invocation(RMI,远程程序调用机制)

静态变量不会被序列化。static代表“每个类一个”而不是“每个对象一个”

将字符串写入文本文件

FileWriter writer = new FileWriter("Foo.txt");
writer.write("hello foo!");
writer.close();


java.io.File class:代表磁盘上的文件而不是文件的内容,或目录的路径名称。
可以对File做的事:
1.创建出代表现存盘文件的File对象
File f = new FIle("MyCode.txt");
2.建立新的目录
File dir = new File("Chapeter7");
dir.mkdir();
3.列出目录下的内容
if(dir.isDirectory()){
String[] dirContents = dir.list();
for(int i = 0;i < dirContents.length; i++){
System.out.println(dirContents[i]));
}
}
4.取得文件或目录的绝对路径
System.out.println(dir.getAbsolutePath());
5.删除文件或目录(成功返回true)
boolean isDeleted = f.delete();


缓冲区:让你暂时放一些东西直到满为止,效率更好:(每趟磁盘操作比内存操作要花费更多时间)从而减少对磁盘操作的次数。
BufferedWriter writer = new BufferedWriter (new FileWrite(aFile));
writer.write("Boulder");
writer.close();



要强制缓冲区立即写入:writer.flush();

读取文本文件

import java.io.*;

class ReadFile{
public static void main(String[] args){
try  {
File myFile = new File("MyTest.txt");
FileReader fileReader = new FileReader(myFile);//FileReader 是字符连接到文本文件的串流
BufferedReader reader = new BufferedReader (fileReader);//将FileReader链接到BufferedReader 以获取更高的效率。它只会在缓冲区读空的时候才会回去取磁盘读取。
String line = null;
while ((line = reader.readLine()) !=null){
System.out.println(line);
}
reader.close();
}
catch(Exception ex){
ex.printStackTrace();
}
}
}



VersionID:序列化的识别
每当对象被序列化的同时,该对象会被“盖”上一个类的版本识别ID,这个ID被称为serialVersionUID,它是根据类的结构信息计算出来的。在对象被解序列化时,如果在对象被序列化之后类有了不同的serialVersonUID,则还原操作会失败。
当Java尝试要还原对象时,它会比对对象与JVM上的类的serialVersionUID。若版本不相符,JVM会在还原过程中抛出异常。
解决方案:把serialVersionUID放在class中,让类在演化过程中维持相同的ID。
若想知道某个类的serialVersionUID,可以使用Java Development Kit里面所带的serialver工具来查询
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java IO