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对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树