JavaSE|序列化流
概念
序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。对象 – 流数据(ObjectOutputStream)
反序列化流:把文本文件中的流对象数据或者网络中的流对象还原成对象。流数据 – 对象(ObjectInputStream)
操作例程
- ObjectOutputStream类的方法 void writeObject(Object obj) :
将指定的对象写入 ObjectOutputStream。
该对象必须被序列化,否则报错java.io.NotSerializableException - ObjectInputStream类的方法 Object readObject() :
从 ObjectInputStream 读取对象。 - java.io.Serializable 接口:
类通过实现 java.io.Serializable 接口以启用其序列化功能。
未实现此接口的类将无法使其任何状态序列化或反序列化。
可序列化类的所有子类型本身都是可序列化的。
序列化接口没有方法或字段,仅用于标识可序列化的语义。
类似于这种没有方法的接口被称为标记接口。
public class Person implements Serializable{
private String name;
private int age;
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class ObjectStreamDemo {
/**
* @param args
* @throws IOException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 由于我们要对对象进行序列化,所以我们先自定义一个类
// 序列化数据其实就是把对象写到文本文件
//write();
read();
}
private static void read() throws IOException, IOException, ClassNotFoundException {
// 创建反序列化对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt"));
Object obj = ois.readObject();
ois.close();
System.out.println(obj);
}
private static void write() throws IOException, IOException {
// 创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));
// 创建对象
Person p = new Person("林青霞",27);
oos.writeObject(p);
// 释放资源
oos.close();
}
}
例程改进:serialVersionUID
在上面的程序中,如果改变Person中的成员变量,而还想读取之前写的数据时,会产生异常java.io.InvalidClassException: cn.itcast_07.Person; local class incompatible……
为什么会产生问题?
Person类实现了序列化接口,那么它本身有一个序列化标记值。假设改变前这个值是100,则:
以前:
Person.class -- id = 100
write数据:oos.txt -- id = 100
read数据:oos.txt -- id = 100
改变后:
Person.class -- id = 200
write数据:oos.txt -- id = 100
read数据:oos.txt -- id = 100
读取文件时,会和class文件中的id进行匹配,故出现异常。
所以讲这个id设置成固定值,就不会出现这个问题了。
有了这个序列化值后,我们对类进行任何改动,它读取以前的数据是没有问题的。
对实现序列化接口的类,add generated serial version ID,如下所示:
public class Person implements Serializable{
private static final long serialVersionUID = -8345153069362641443L;
private String name;
private int age;
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
transient关键字
使用transient关键字关键字声明不需要序列化的成员变量
面试题
- 什么时候序列化
把对象写入文本文件或者在网络中传输 - 如何实现序列化
让被序列化对象所属的类实现序列化接口 - 什么是反序列化
把文本文件中的流对象数据或者网络中的流对象还原成对象。流数据 – 对象(ObjectInputStream)