Head First Java笔记(五)

本文介绍了Java中对象序列化的基本概念与应用,包括对象序列化的步骤、序列化与反序列化的过程,以及如何实现文件的输入输出操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

保存对象
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工具来查询


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值