前言
简单地说,serialVersionUID
是可序列化类( Serializable classes
)的唯一标识符。
这在对象反序列化期间使用,以确保加载的类
与序列化的对象
兼容。当你添加或修改类中的任何字段
时,已序列化类
将无法恢复
,因为新类
和旧序列化对象生成的 serialVersionUID
将有所不同
。
Java 序列化的过程是依赖于正确的序列化对象恢复状态的,并在序列化对象序列版本
不匹配的情况下引发java.io.InvalidClassException
无效类异常。
案例1:
让我们从创建一个serializable
类开始,并声明一个serialVersionUID
常量。
public class AppleProduct implements Serializable {
private static final long serialVersionUID = 1234567L;
public String headphonePort;
public String thunderboltPort;
}
接下来,我们创建两个工具类:一个用于将AppleProduct
对象序列化为字符串,另一个用于从字符串反序列化为对象。
public class SerializationUtility {
public static void main(String[] args) {
AppleProduct macBook = new AppleProduct();
macBook.headphonePort = "headphonePort2020";
macBook.thunderboltPort = "thunderboltPort2020";
String serializedObj = serializeObjectToString(macBook);
System.out.println("Serialized AppleProduct object to string:");
System.out.println(serializedObj);
}
public static String serializeObjectToString(Serializable o) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
return Base64.getEncoder().encodeToString(baos.toByteArray());
}
}
public class DeserializationUtility {
public static void main(String[] args) {
String serializedObj = ... // ommited for clarity
System.out.println(
"Deserializing AppleProduct...");
AppleProduct deserializedObj = (AppleProduct) deSerializeObjectFromString(
serializedObj);
System.out.println(
"Headphone port of AppleProduct:"
+ deserializedObj.getHeadphonePort());
System.out.println(
"Thunderbolt port of AppleProduct:"
+ deserializedObj.getThunderboltPort());
}
public static Object deSerializeObjectFromString(String s)
throws IOException, ClassNotFoundException {
byte[] data = Base64.getDecoder().decode(s);
ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(data));
Object o = ois.readObject();
ois.close();
return o;
}
}
我们首先运行SerializationUtility.java
。它将AppleProduct
对象保存(序列化)到一个字符串实例中,使用Base64
对字节进行编码。然后,使用该字符串作为反序列化方法的参数,运行DeserializationUtility.java
文件,它从给定的字符串重新组装(反序列化)AppleProduct
对象。
打印的输出应该与此类似:
Serialized AppleProduct object to string:
rO0ABXNyACljb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkFwcGxlUHJvZHVjdAAAAAAAEta
HAgADTAANaGVhZHBob25lUG9ydHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wADmxpZ2h0ZW5pbmdQb3
J0cQB+AAFMAA90aHVuZGVyYm9sdFBvcnRxAH4AAXhwdAARaGVhZHBob25lUG9ydDIwMjBwdAATd
Gh1bmRlcmJvbHRQb3J0MjAyMA==
Deserializing AppleProduct...
Headphone port of AppleProduct:headphonePort2020
Thunderbolt port of AppleProduct:thunderboltPort2020
现在,让我们修改AppleProduct
中的serialVersionUID
常量,重新使用前面生成的字符串反序列化AppleProduct
对象。重新运行DeserializationUtility.java
。打印结果如下:
Deserializing AppleProduct...
Exception in thread "main" java.io.InvalidClassException: com.baeldung.deserialization.AppleProduct; local class incompatible: stream classdesc serialVersionUID = 1234567, local class serialVersionUID = 7654321
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1630)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1521)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1781)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
at com.baeldung.deserialization.DeserializationUtility.deSerializeObjectFromString(DeserializationUtility.java:24)
at com.baeldung.deserialization.DeserializationUtility.main(DeserializationUtility.java:15)
通过更改类的serialVersionUID
,我们修改了该类的版本/状态。 结果,在反序列化期间未找到兼容的类,因此引发了InvalidClassException
。
案例2:在现有类上添加新字段
假设我们需要向现有的AppleProduct
类中添加一个新的字段lightningPort
。
public class AppleProduct implements Serializable {
//...
public String lightningPort;
}
因为我们只是添加了一个新字段,所以不需要更改serialVersionUID
。这是因为在反序列化过程中,lightningPort
字段将使用null
作为默认值。
让我们修改DeserializationUtility
类来打印这个新字段的值。
System.out.println("LightningPort port of AppleProduct:"
+ deserializedObj.getLightningPort());
现在,当我们重新运行DeserializationUtility
类时,我们将看到类似的输出:
Deserializing AppleProduct...
Headphone port of AppleProduct:headphonePort2020
Thunderbolt port of AppleProduct:thunderboltPort2020
Lightning port of AppleProduct:null
结论
在这篇教程中,我们演示了如何使用serialVersionUID
常量来简化序列化数据的版本控制。
网友评论