保存对象
对象可以被序列化也可以展开
对象有状态和行为属性,行为存在于类中,而状态存在于个别的对象中。当需要存储对象的状态时,一是可以对每个对象逐个把每项变量值写到特定格式的文件中或采用面向对象方式,把对象经过一系列流程保存,再逆过程恢复,但有时要来硬的,特别是程序所存储的文件需要给非Java的应用程序所读取。
存储状态的选择
只有自身Java程序会用到数据(序列化)
将被序列化的对象写入到文件中,然后可以让自己程序去文件中读取序列化的对象并将其恢复原状。
需要被其他程序引用
写一个纯文本文件,用其他程序可解析的特殊字符写入文件,比如用tab字符来分隔的档案一边数据库应用程序能应用。
当然存在其余选择,把数据存入任何格式,如将数据用字节而不是字符写入,或者将数据额写成主数据类型(某些方法提供主数据类型的写入功能)
存储状态
设想角色扮演类游戏,需要存储人物状态,假设有三种人物
第一种选择
创建一个文件,让序列化的三种对象写到此文件中,该文本在以文本形式阅读时无意义
第二种选择
写入纯文本文件,创建文件,写入三行文字,每种人物一行,以逗点分开属性
序列化对象写入文件
1)创建FileOutputStream
FileOutputStream filestream = new FileOutputStream("Mygame")
//如文件不存在则自动创建
2)创建ObjectOutputStream
ObjectOutputStream os = new ObjectOutputStream(fileStream);
//让你能写入对象,但需要通过参数指引才能连接文件
3)写入对象
//将变量所引用的对象序列化写入文件
os.writeObject(characterOne);
4)关闭ObjectOutputStream
os.close();
数据在串流中移动
输入输出API带有连接类型的串流,连接类型的串流与其他串流连接起来(串流需要相互连接)。串流需要两两连接才能有意义,其中一个表示连接,另一个表示要被调用方法的,两两连接的原因在于串流通常是很低层的。例如FileOutputStream,有可以写入字节的方法,但通常不采用,而是以对象层次观点写入,需要高层次的连接串流。
当对象被序列化时,被该对象引用的实例变量也会被序列化,且所有被引用(引用的引用)的对象也会被序列化,且这些操作自动进行。序列化的程序会将对象版图上的所有东西存储。
FileOutputStream把字节写入文件,ObjectOutputStream通过writeObject把对象转化为
可以写入串流的数据,再送到FileOutputStream来写入文件。通过上述的组合,完成数据的存储。
Object->ObjectOutputStream->FileOutputStream->file
探究对象序列化
1.堆上的对象
堆上的对象有状态,即实例变量
2.被序列化的对象
序列化对象保存实例变量的值,而序列化对象和类的名称又存储在文件中。
当对象被序列化时,被该对象的实例变量所引用的所有对象也会被序列化,且所有被引用的对象也会被序列化,且所有操作自动进行。
如kennel对象带有对dog数组对象的引用,dog数组有两个dog对象的引用,每个dog对象带有string和collar对象的引用,string对象维护字符集合,而collar对象具有int类型实例变量。当保存kennel对象时,所有对象都会保存。
通过实现Serializable接口,让类序列化
Serializable接口又被称为market或tag类的标记用接口,因为该接口无任何方法要实现,唯一的目的就是声明有实现它的类可以被序列化的,即允许该类的对象通过序列化来存储。若某类可序列化,则其子类也自动地可以序列化。
objectOutputStream.writeObject(myBox);
//myBox位置的对象必须要实现序列化,否则error
public class Box implements Serializable{ //告诉JVM可以被序列化
private int width;
private int height;
//以上实例变量值会被保存
整个对象版图都必须正确地序列化,不然会全部失败,即序列化是全有或全无的状态,因此要求对象的实例变量所引用的对象也要实现Serializable接口,以此类推。
若某实例变量不能或不应该被序列化,则将其标记为transient,表示该变量不需要序列化,这样的话序列化程序会跳过该实例变量。
不需要实例化的原因可能是动态数据只可以在执行中求出而不能或不必存储,如网络联机之类的东西得在执行期当场创建才有意义。