学习序列化时随手记录一下,便于以后的复习

程序运行时,实例化出的对象信息是加载到内存中的,当程序结束后,对象信息也就不存在了,怎么将对象信息保存到磁盘中呢?这就要用到对象序列化

先看代码:

定义了一个用户类User:

1 class User{
 2     String userName;
 3     String passWord;
 4 
 5     public User(String userName, String passWord) {
 6         this.userName = userName;
 7         this.passWord = passWord;
 8     }
 9 
10     @Override
11     public String toString() {
12         return "用户名:" + this.userName + " 密码:" + this.passWord;
13     }
14 }

java为我们提供了对象序列化的操作流:ObjectOutputStream,我们把user对象的信息保存到F:\\obj.txt文件中去。

1  public static void main(String[] args) throws IOException{
 2         //对象的序列化
 3         User user = new User("admin", "123");
 4         File file = new File("F:\\obj.txt");
 5         FileOutputStream fileOutputStream = new FileOutputStream(file);
 6         ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutputStream);
 7 
 8         objectOutput.writeObject(user);
 9         objectOutput.close();
10 
11     }

此时运行main程序,你会惊喜的发现,报错了!(Exception in thread "main" java.io.NotSerializableException),为什么会出现这个错误呢?原因是我们所写的User类没有实现Serializable(可序列化的)接口,将User实现此接口后,运行程序可将user对象实例化。查看F:\\obj.txt文件,里面确实有内容了(但是一堆乱码)。这说明实例化成功了。

 如果我们想从磁盘中读取前面我们序列化的对象呢(这个过程叫做反序列化),so easy!java也为我们反序列化提供了ObjectInputStream,读取F:\\obj.txt:

1  public static void main(String[] args) throws IOException{
 2         File file = new File("F:\\obj.txt");
 3 
 4         FileInputStream fileInputStream = new FileInputStream(file);
 5 
 6         ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
 7         User user = (User) objectInputStream.readObject();
 8         objectInputStream.close();
 9         System.out.println(user);
10 
11     }

控制台打印输出:用户名:admin 密码:123

反序列化成功!

继续深入一下,关于序列化问题,还有一些要说一说的东西。。

java中的集合类全部都实现了Serializable接口,观察它们的源代码,你会发现这些集合类中都会有这样一条语句(右边的数字会有所不同):

private static final long serialVersionUID = 876323262645176354L;

那么,这个serialVersionUID 有何作用呢?实现Serializable接口的类必须都要写吗?(显然不是,因为我们前面写的User类,里面就没有这玩意。。)

 serialVersionUID字面意思是序列版本号,到底是个什么玩意呢,咱们接着看。

前面我们通过序列化,将user信息保存到了F:\\obj.txt中,现在对User类的结构做一些改变,比如增加一个age字段:

1 class User implements Serializable {
 2     String userName;
 3     String passWord;
 4     int age;
 5     
 6     public User(String userName, String passWord) {
 7         this.userName = userName;
 8         this.passWord = passWord;
 9     }
10 
11     @Override
12     public String toString() {
13         return "用户名:" + this.userName + " 密码:" + this.passWord;
14     }
15 }

 此时我们直接读取obj.txt进行反序列化会发生什么呢?运行程序,编译器会报出如下错误信息:

java.io.InvalidClassException; local class incompatible: stream classdesc serialVersionUID = -4401750438685317474, local class serialVersionUID = 3946011404892452386

事实上,我们的User类中并没有定义出serialVersionUID 的值,是java自动为我们计算出来的,java根据一个类的字段信息、包信息等计算出serialVersionUID 字段的值,所以,如果我们对类结构做出了改变,那么serialVersionUID 的值一定会随之改变,所以在反序列化的时候,就会出现上面那条错误信息。

如果想在改变类结构的情况下,又不影响反序列化的执行,应该怎么做呢?很简单,我们可以在User类中显示定义serialVersionUID 的值,并加上final关键字。这样就可以轻松解决上述问题。