对象序列化
为什么需要对象序列化 ? 在谈这个问题之前, 我们首先先来认识这两种流 : 对象的输出流: ObjectOutputStream , 对象的输入流: ObjectInputStream
这两个流的作用是 : 用于写入对象信息与读取对象信息。 对象信息一旦写到文件上那么对象的信息就可以做到持久化了
可以看到, 它们的作用是将对象信息保存到文件中从而达到持久保存的效果 ,那么这个过程就叫做对象的序列化, 通过ObjectOutputStream(也是处理流的一种)来完成,示例如下
try {
//先使用文件输出流
FileOutputStream out = new FileOutputStream("D:/demo/abc.txt");
//使用ObjectOutputStream流包装
ObjectOutputStream ObjectOut = new ObjectOutputStream(out);
Date date = new Date(); //new 一个日期类对象
ObjectOut.writeObject(date); //将对象序列保存进文件
} catch (Exception e) {
e.printStackTrace();
}
结果 :
被保存的对象信息如上图
谈到这里, 那么反序列化也就不难理解了,就是我们将保存进文件的对象还原回来,示例如下
try {
//文件输入流
FileInputStream in = new FileInputStream("D:/demo/abc.txt");
//对象输入处理流包装
ObjectInputStream objectIn = new ObjectInputStream(in);
//获取文件中的对象
Object o = objectIn.readObject();
//判断 o 是否是一个Date类的对象
if (o instanceof Date){
//强制转换为Date类型
Date date = (Date) o;
System.out.println(date);
}
} catch (Exception e) {
e.printStackTrace();
}
结果 :
可见,反序列化完成
我们上述的例子, 是将java已经实现好的类(例如Date类) 序列化到文件中的, 这些能被序列化的类都有一个共同特征 , 那就是实现了Serializable接口, 我们可以去看他们的jdk源码 ,例(Date类如下):
所以 , 当我们想把我们自己写的类序列化的时候, 那么就必须去实现Serializable接口才可以
另外, Date类里还存在这样一个常量
这叫做序列化id号,当一个类实现了Serializable接口后就会默认在类中生成这样一个序列号(隐式的), 但如果我们改变了类中的信息,这个id号就会发生改变 , 这样反序列化的时候就会报错, 所以一般我们会向上述那样显式的声明这个序列号
这里我们设计一个可以序列化的学生类,如下
public class Student implements Serializable {
//显式生成序列号id号
private static final long serialVersionUID = 6006442119571252031L;
private Integer num;
private String name;
private Integer age;
public Student(Integer num, String name, Integer age) {
this.num = num;
this.name = name;
this.age = age;
}
}
这里就不去演示效果了, 需要注意的是,如果不显式的写出序列化id号,这样也是会报错的
最后介绍一个关键字 : transient(被修饰的属性在序列化时被忽略)
这个关键字的用法是 : 如果我们在序列化的时候, 不想让类的一些变量被写入进去,那么我们用
transient关键字修饰这个属性 即可