Java默认的序列化流
序列化流
序列化是什么?
序列化:把对象以流的方式写入到文件中保存,叫做写对象,也叫作对象的序列化
对象中包含的不仅仅是字符,还有字节,所以要用字节流
反序列化:把文件中保存的对象,以流的方式读取出来,叫做读对象,也叫作对象的反序列化
读取的文件保存的都是字节,使用字节流
实现序列化和反序列化的核心就是要使用:ObejctOutputStream
与ObjectInputStream
ObejctOutputStream
构造方法
1 | ObjectOutputStream(OutputStream out); |
核心API
1 | public final void writeObject(Object obj)throws IOException |
步骤
1 | ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\a.txt")); |
运行报错NotSerializableException
,这个错是未序列化报错,序列化和反序列化会抛出这个错误
我们必须实现一个标记性接口来启动这个序列化
标记性接口:实现这个接口不需要实现其任何方法
要进行序列化和反序列化的接口必须实现Serializable
接口,就会给类添加一个标记
1 | public class Person implements Serializable{ |
这样就可以运行了,输出的文件如下
1 | aced 0005 7372 001d 636e 2e69 7463 6173 |
ObejctInputStream
核心API
构造方法:ObjectInputStream(InputStream in)
传入一个字节输入流
反序列化:readObject()
,从输入流的位置读入文件,返回一个对象
小demo
1 | ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\a.txt")); |
注意:
可能会报出ClassNotFoundException
这个错误,是因为不存在对象的class
文件时抛出异常
所以反序列化必须实现两个东西
- 类必须实现
Serializable
- 必须存在对应的
Class
文件
transient关键字
static
关键字:被
static
修饰的成员变量不能被序列化的transient
关键字:被
transient
修饰的成员变量,不能被序列化
以后不想要成员变量被序列化,我们可以使用transient
关键字修饰
InvalidClassException异常
当JVM反序列化对象时,能找到
class
对象,但是还会抛出一个InvalidClassException
的异常,为什么?
有可能是因为
- 更改了
class
的内容,使得该类的序列版本号与读取到的类描述的版本号不匹配 - 该类包含未知数据类型
- 该类没有可访问的无参数构造
原理:实现了Serializable
接口,就会根据类的定义,给该类一个接口的序列号,反序列化时会比照两者的序列号,如果曾更改了类,会使得他们没有匹配序列号,导致报错
解决方法:
- 无论是否对类的定义进行修改都不重新生成新的序列号
- 可以手动给类增加一个序列号
Serializable
接口规定:可序列化类可以通过声明名为
serialVersionUID
的字段
(该字段必须是static final long serialVersionUID
型字段)
在类中定义一个如下的成员变量即可
1 | private static final long serialVersionUID = 1L; |
序列化多个对象
当我们想在文件中保存多个对象的时候,我们可以把多个对象存储到一个集合中,然后对集合进行序列化和反序列化
分析:
1 | //1 定义一个存储Person对象的ArrayList集合 |