2)添加一个随机生成的不重复的序列化 ID。
private static final long serialVersionUID = -2095916884810199532L;3)添加 @SuppressWarnings 注解。
@SuppressWarnings("serial")怎么选择呢?
首先,我们采用第二种办法,在被序列化类中添加一个随机生成的序列化 ID。
class Wanger implements Serializable {private static final long serialVersionUID = -2095916884810199532L;
private String name;
private int age;
// 其他代码忽略
}
然后,序列化一个 Wanger 对象到文件中。
// 初始化Wanger wanger = new Wanger();
wanger.setName("王二");
wanger.setAge(18);
System.out.println(wanger);
// 把对象写到文件中
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("chenmo"));) {
oos.writeObject(wanger);
} catch (IOException e) {
e.printStackTrace();
}
这时候,我们悄悄地把 Wanger 类的序列化 ID 偷梁换柱一下,嘿嘿。
// private static final long serialVersionUID = -2095916884810199532L;private static final long serialVersionUID = -2095916884810199533L;
好了,准备反序列化吧。
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("chenmo")));) {Wanger wanger = (Wanger) ois.readObject();
System.out.println(wanger);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
哎呀,出错了。
java.io.InvalidClassException: local class incompatible: stream classdescserialVersionUID = -2095916884810199532,
local class serialVersionUID = -2095916884810199533
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
at com.cmower.java_demo.xuliehua1.Test.main(Test.java:27)
异常堆栈信息里面告诉我们,从持久化文件里面读取到的序列化 ID 和本地的序列化 ID 不一致,无法反序列化。
那假如我们采用第三种方法,为 Wanger 类添加个 @SuppressWarnings("serial") 注解呢?
@SuppressWarnings("serial")class Wanger implements Serializable {
// 省略其他代码
}
好了,再来一次反序列化吧。可惜依然报错。
java.io.InvalidClassException: local class incompatible: stream classdescserialVersionUID = -2095916884810199532,
local class serialVersionUID = -3818877437117647968
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
at com.cmower.java_demo.xuliehua1.Test.main(Test.java:27)
异常堆栈信息里面告诉我们,本地的序列化 ID 为 -3818877437117647968,和持久化文件里面读取到的序列化 ID 仍然不一致,无法反序列化。这说明什么呢?使用 @SuppressWarnings("serial") 注解时,该注解会为被序列化类自动生成一个随机的序列化 ID。
由此可以证明,Java 虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,还有一个非常重要的因素就是序列化 ID 是否一致。
也就是说,如果没有特殊需求,采用默认的序列化 ID(1L)就可以,这样可以确保代码一致时反序列化成功。
class Wanger implements Serializable {private static final long serialVersionUID = 1L;
// 省略其他代码
}
06、再来点总结
写这篇文章之前,我真没想到:“空空其身”的Serializable 竟然有这么多可以研究的内容!
写完这篇文章之后,我不由得想起理科状元曹林菁说说过的一句话:“在学习中再小的问题也不放过,每个知识点都要总结”——说得真真真真的对啊!