序列化流 把对象以指定的格式写入到文件中保存和读取
序列化流
java提供了一种对象序列化的机制,用一个字节序列可以表示一个对象,该字节序列包含该对象的数据,对象的类型和对象中存储的属性等信息,字节序列写入到文件中后,就相当于在文件中保存了文件对象信息.
反之,该字节序列还可以从文件中读取出来,重构对象.对他进行反序列化.对象的数据,对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象,
ObjectOutputStream类
java.io.ObjectOutputStream类,将java对象的原始数据类型写入到文件中,实现对象的持久化存储.
构造方法
-
public ObjectPutputStream(OutputStream out):创建一个指定的OutputStream的的ObjectOutputStream类对象
独有的方法
-
void writeObject(Object obj):将指定的对象写入到对象序列化中
备注:
当某个类对象需要进行序列化时,没有实现序列化接口时会抛出该 java.io.NotSerializableException 序列化异常 解决:让该类实现Serializable接口,启用序列化功能,为实现此接口的类将无法使其 任何状态序列化或者进行反序列化. java.io.Serializable接口, 此接口内部什么也没有,这类接口也可称为标记性接口. 要进行序列化和反序列化的时候,给该类添加一个标记,实现序列化接口,此时该类就有标记了. 当程序要进行序列化和反序列化的时候,首先会检测该类是否有序列化标记. 有:就可以进行序列化和反序列化 没有:就会抛出java.io.NotSerializableException 就好比大家上超市买产品,需要看产品上的生产日期
序列化操作
1.一个对象想要能够序列化和反序列化,必须满足两个条件:
-
该类必须实现java.io.Serializable接口,Serializable接口是一个标记性接口,如果该类没有实现Serializable接口,将会抛出NotSerializableException.
-
该类的所有属性必须是可以实现序列化或者反序列化,如果有一个属性不想让他参与序列化,则该属性必须标明是 瞬态的,瞬时的,这个关键字是transient,被他修饰的成员变量是没有值的.为默认值.
public class Student implements Serializable{
private String name;
private transient int age;//让age属性不参与序列化
ObjectinputStream类
ObjectInputStream类是反序列化流,将之前使用ObjectOutputStream序列化流的原始数据恢复为对象.
构造方法
-
public ObjectunputStream(inmputStream in):创建一个指定的inputStream的对象反序列化流对象.
特有的方法:
-
public final Object readObject():从反序列化流中读取对象
做好了一个类继承了可序列化标记好,虚拟机可以给它一个序列号.序列化存储对象文件之后,更改了类源代码,那么这个类会更新另一个序列号,那么对象文件在反序列化的时候就会报错.
所以我们面对类的序列号进行锁定,自定义一个
//可以手动自定义一个序列化版本号
private static final long serialVersionUID=1L;
锁定了序列号之后,对类进行了修改,那么反编译会通过,但是他会属性对照,类中此时还在的属性才会被抓取,而类中新增的成员变量此时不存在.
对于JVM来说,能够进行反序列的对象,前提条件是必须能够找到class文件的类,如果找不到该类的class文件,则会跑出一个ClassNotFoundException异常.
另外,当JVM序列化对象时,能找找到class文件,但是class文件再序列化对象时,发生了修改,那么反序列化操作会抛出invalidClassException异常.原因如下:
-
该类的序列化版本号与从流中读取出来描述该类的版本号不一致.
-
该类包含了位置数据类型.
-
该类没有可访问的无参构造方法.
Serializable接口给需要序列化的类,提供了一个序列化版本号,seriaIVersionUID改版本号的目的就在于验证序列化的对象和对应的类是否是版本一致.
//可以手动自定义一个序列化版本号
private static final long serialVersionUID=11231L;