美文网首页
serialVersionUID的作用

serialVersionUID的作用

作者: AD刘涛 | 来源:发表于2020-03-07 15:19 被阅读0次

前言

简单地说,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常量来简化序列化数据的版本控制。

原文出处

参考文档

知识扩展

相关文章

网友评论

      本文标题:serialVersionUID的作用

      本文链接:https://www.haomeiwen.com/subject/loycdhtx.html