Was ist die serialVersionUID?

Was ist die serialVersionUID?

1. Überblick

Einfach ausgedrückt,the serialVersionUID is a unique identifier for Serializable classes.

Dies wird während der Deserialisierung eines Objekts verwendet, um sicherzustellen, dass eine geladene Klasse mit dem serialisierten Objekt kompatibel ist. Wenn keine übereinstimmende Klasse gefunden wird, wird einInvalidClassException ausgelöst.

2. Beispiel

Beginnen wir mit der Erstellung einer serialisierbaren Klasse und deklarieren den Bezeichner vonserialVersionUID:

public class AppleProduct implements Serializable {

    private static final long serialVersionUID = 1234567L;

    public String headphonePort;
    public String thunderboltPort;
}

Als Nächstes benötigen wir zwei Dienstprogrammklassen: eine zum Serialisieren einesAppleProduct-Objekts in einString, und eine zum Deserialisieren des Objekts von diesemString:

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;
    }
}

Wir beginnen mit der Ausführung vonSerializationUtility.java, wodurch dasAppleProduct-Objekt in einemString-Instanze, gespeichert (serialisiert) wird, wobei die Bytes mitBase64 codiert werden.

Dann führen wirString als Argument für die Deserialisierungsmethode aus und führenDeserializationUtility.java, aus, das dasAppleProduct-Objekt aus den angegebenenString. wieder zusammensetzt (deserialisiert)

Die generierte Ausgabe sollte ungefähr so ​​aussehen:

Serialized AppleProduct object to string:
rO0ABXNyACljb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkFwcGxlUHJvZHVjdAAAAAAAEta
HAgADTAANaGVhZHBob25lUG9ydHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wADmxpZ2h0ZW5pbmdQb3
J0cQB+AAFMAA90aHVuZGVyYm9sdFBvcnRxAH4AAXhwdAARaGVhZHBob25lUG9ydDIwMjBwdAATd
Gh1bmRlcmJvbHRQb3J0MjAyMA==
Deserializing AppleProduct...
Headphone port of AppleProduct:headphonePort2020
Thunderbolt port of AppleProduct:thunderboltPort2020

Now, let’s modify the serialVersionUIDconstant in AppleProduct.java, and reattempt to deserialize ist dasAppleProduct-Objekt aus demselben String, der zuvor erstellt wurde. Durch erneutes Ausführen vonDeserializationUtility.java sollte diese Ausgabe generiert werden.

Deserializing AppleProduct...
Exception in thread "main" java.io.InvalidClassException: com.example.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.example.deserialization.DeserializationUtility.deSerializeObjectFromString(DeserializationUtility.java:24)
    at com.example.deserialization.DeserializationUtility.main(DeserializationUtility.java:15)

Durch Ändern derserialVersionUID der Klasse haben wir ihre Version / ihren Status geändert. Infolgedessen wurden während der Deserialisierung keine kompatiblen Klassen gefunden, und einInvalidClassException wurde geworfen.

3. Beispiel - Hinzufügen eines neuen Felds zu einer vorhandenen Klasse

Angenommen, wir müssen unserer vorhandenenAppleProduct-Klasse ein neues FeldlightningPort hinzufügen:

public class AppleProduct implements Serializable {
//...
    public String lightningPort;
}

Da wir gerade ein neues Feld hinzufügen,no change in the serialVersionUID will be required. Dies liegt daran, dassduring the deserialization process, null will be assigned as the default value for the lightningPort field.

Ändern Sie dieDeserializationUtility-Klasse, um den Wert dieses neuen Felds zu drucken:

System.out.println("LightningPort port of AppleProduct:"
  + deserializedObj.getLightningPort());

Wenn wir nun dieDeserializationUtility-Klasse erneut ausführen, sehen wir eine Ausgabe ähnlich der folgenden:

Deserializing AppleProduct...
Headphone port of AppleProduct:headphonePort2020
Thunderbolt port of AppleProduct:thunderboltPort2020
Lightning port of AppleProduct:null

4. Fazit

In diesem kurzen Artikel haben wir die Verwendung der KonstanteserialVersionUIDdemonstriert, um die Versionierung serialisierter Daten zu erleichtern.

Wie immer finden Sie die in diesem Artikel verwendeten Codebeispiele inover on GitHub.