39 序列化和反序列化
一张解释序列化和反序列化,如上,我们创建Person类实例,想把它存储到文件中,可以使用流方式写入,叫做序列化,因为对象不仅包括字符,所以要用字节流写,这里使用ObjectOutputStream,即按对象输出序列化,有方法,writeObject(Object obj)写入到某文件中,因为是字节流,我们看不懂,流存储就需要流读取,使用ObjectInputStream反序列化输入流,读取来的对象我们不知道是什么类,因为类型不一定固定,所以用Object对象接收
ObjectOutputStream序列化输出流
既然说完了,那就来学习怎么使用
2其继承自字节输出流,将对象以流的方式写入文件
3构造方法2个,视频推荐后者,传入字节输出流参数
4其特有成员方法是将对象写入到序列号流中,
5然后我们就信誓旦旦的去写代码了,就发现了错误,提示未序列化异常,果然还是不能简单实用Person对象来直接使用,而序列化接口是java.io.Serializable中,我们需要implements它,所有需要序列化或者反序列化的类都必须实现它,实现后,该类就添加了标记,我们进行序列化或者反序列化就可以正常进行,否则就会报错(就像肉盖有检疫章一样)
6修改后,运行正常
ObjectInputStream反序列化输入流
7将文件中保存的对象以流方式读出来,继承自字节输入流
8其自身方法readObject()获取文件对象
8代码如上,注意的是,readObject需要抛出未找到类异常,为了使用对象需要强转类型
瞬态关键字transient
我们知道静态关键字static,修饰成员变量时,优先于对象加载到内存中,所以被static修饰的成员变量时不能被序列化的
9我们给Person的age修改为static,则其序列化后,再用另一个文件反序列化,运行发现年龄不是13而是默认值,(但是当我用一个文件调用2个函数是可以得到序列化的值的)
10同样,将属性设置为transient也是不可序列化的
InvalidClassException异常
我们之前反序列化需要注意IO异常,和类未找到异常,还有新的异常,如果我们按Person类进行序列化并存储到文件,但是反序列化前,将Person类修改,例如某个属性设置为private->public
11反序列化后就会报错,提示序列化编号不匹配
12我们因为类实现了Serializable接口,所以编译后会给你其添加序列号,我们序列化后文件就会存储序列化号,当我们反序列化,就会比对文件序列化号和类序列化是否一致,如果我们修改了,那就会编译导致类序列化号不一致报错,我们如果频繁修改类,那序列化就会很麻烦,可序列化类可以通过声明名为"serialVersionUID"的字段(该字段必须是静态 (static)、最终 (final) 的long型字段)显式声明其自己的 serialVersionUID:
static final long serialVersionUID = 42L; 给Person类添加这个序列化号字段,则这个序列化号就是指定不变的
练习DEMO
序列化集合,集合可以序列化多个对象,我们如此存储
13序列化部分如上
14反序列化读取如上