本文目标:开发人员,在了解serialVersionUID作用的条件下,进行序列化相关类的定义操作,达到版本可控的程度。
文章目录
1 场景
Java中的序列化主要应用于以下3个场景:
(1)对象状态持久化 - 将对象保存到文件或数据库中
(2)网络传输优化 - 通过序列化减少网络传输数据量
(3)RPC等的应用基础 - 远程过程调用需要以流的形式处理请求和响应
本文以将对象保存到文件举例,说明serialVersionUID在序列化、反序列化中,如何起到版本控制的作用。
首先一起来看正常情况下,Apple对象如何进行序列化,得到二进制数据存入文件;以及如何读取文件,将二进制数据反序列化得到Apple对象。
1.1 Apple类定义
要进行序列化的对象,对应类需要实现Serializable接口,未实现该接口,无法进行序列化。
serialVersionUID的1L,也会参与序列化,表示版本。
package maplegam.com;
import java.io.Serializable;
public class Apple implements Serializable {
private static final long serialVersionUID = 1L;
String name;
String weight;
public Apple(String name, String weight) {
this.name = name;
this.weight = weight;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getWeight() {
return this.weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
}
1.2 apple对象序列化并存入文件
使用java io库的ObjectOutputStream进行序列化处理,并将结果存入“abc.txt”文件。
package maplegam.com;
import java.io.*;
public class SerialzableTest {
public static void main(String[] args) throws Exception {
String writerPath = "D:\\abc.txt";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(writerPath, true));
oos.writeObject(new maplegam.com.Apple("aaa", "3.78"));
oos.close();
}
}
abc.txt文件内容如下图所示:
1.3 读取文件反序列化得到apple对象
使用java io库的ObjectInputStream进行反序列化处理,并将得到的apple对象内容打印出来。
package maplegam.com;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class SerialzableReadTest {
public static void main(String[] args) throws Exception {
String writerPath = "D:\\abc.txt";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(writerPath));
Object oj = ois.readObject();
Apple apple = (Apple) oj;
System.out.println("Apple name:"+apple.getName());
System.out.println("Apple weight:"+apple.getWeight());
ois.close();
}
}
反序列化为对象后,打印内容如下:
2 要点
2.1 类要实现Serializable接口
进行序列化的类,没有实现Serializable接口时,会出现报错“java.io.NotSerializableException”。
2.2 类中的serialVersionUID版本要一致
serialVersionUID版本如果不一致(比如序列化时客户端引用的该类版本为1L,服务端引用的该类版本为2L),会出现报错“java.io.InvalidClassException: maplegam.com.Apple; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2”。
3 总结/练习
在需要序列化的类中,声明serialVersionUID是一个好习惯,能提高代码阅读效率。
在代码走查阶段,如果发现客户端、服务端该值不一样,就能提前发现问题,不用等到上线报错后,从日志中看出是该问题。
可以参照前“1 场景”、“2 要点”内容,尝试在序列化过程中,声明serialVersionUID,查看版本一致、不一致的不同处理结果。