Wat is de serialVersionUID?

1. Overzicht

Simpel gezegd, de serialVersionUID is een unieke identificatie voor Serialiseerbaar klassen.

Dit wordt gebruikt tijdens de deserialisatie van een object om ervoor te zorgen dat een geladen klasse compatibel is met het geserialiseerde object. Als er geen overeenkomende klasse wordt gevonden, wordt een InvalidClassException wordt gegooid.

2. Seriële versie UID

Laten we beginnen met het maken van een klasse die kan worden geserialiseerd en een serialVersionUID identificatie:

public class AppleProduct implementeert Serializable {private static final long serialVersionUID = 1234567L; openbare String headphonePort; openbare String thunderboltPort; }

Vervolgens hebben we twee hulpprogramma-klassen nodig: een om een AppleProduct object in een Draad, en een ander om het object daarvan te deserialiseren Draad:

public class SerializationUtility {public static void main (String [] args) {AppleProduct macBook = nieuw AppleProduct (); macBook.headphonePort = "headphonePort2020"; macBook.thunderboltPort = "thunderboltPort2020"; String serializedObj = serializeObjectToString (macBook); System.out.println ("Geserialiseerd AppleProduct-object naar string:"); System.out.println (serializedObj); } openbare statische String serializeObjectToString (serialiseerbare o) {ByteArrayOutputStream baos = nieuwe ByteArrayOutputStream (); ObjectOutputStream oos = nieuwe ObjectOutputStream (baos); oos.writeObject (o); oos.close (); retourneer Base64.getEncoder (). encodeToString (baos.toByteArray ()); }}
openbare klasse DeserializationUtility {public static void main (String [] args) {String serializedObj = ... // ommited voor de duidelijkheid System.out.println ("Deserializing AppleProduct ..."); AppleProduct deserializedObj = (AppleProduct) deSerializeObjectFromString (serializedObj); System.out.println ("Hoofdtelefoonpoort van AppleProduct:" + deserializedObj.getHeadphonePort ()); System.out.println ("Thunderbolt-poort van AppleProduct:" + deserializedObj.getThunderboltPort ()); } openbaar statisch object deSerializeObjectFromString (String s) genereert IOException, ClassNotFoundException {byte [] data = Base64.getDecoder (). decode (s); ObjectInputStream ois = new ObjectInputStream (nieuwe ByteArrayInputStream (data)); Object o = ois.readObject (); ois.close (); terug o; }}

We beginnen met rennen SerializationUtility.java, die het AppleProduct object in een Draad instance, het coderen van de bytes met Base64.

Gebruik dat dan Draad als argument voor de deserialisatiemethode voeren we uit DeserializationUtility.java, die het AppleProduct bezwaar maken van het gegeven Draad.

De gegenereerde output zou er ongeveer zo uit moeten zien:

Geserialiseerde AppleProduct object naar een string: rO0ABXNyACljb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkFwcGxlUHJvZHVjdAAAAAAAEta HAgADTAANaGVhZHBob25lUG9ydHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wADmxpZ2h0ZW5pbmdQb3 J0cQB + AAFMAA90aHVuZGVyYm9sdFBvcnRxAH4AAXhwdAARaGVhZHBob25lUG9ydDIwMjBwdAATd Gh1bmRlcmJvbHRQb3J0MjAyMA ==
Deserialiseren van AppleProduct ... Hoofdtelefoonpoort van AppleProduct: headphonePort2020 Thunderbolt-poort van AppleProduct: thunderboltPort2020

Laten we nu het serialVersionUIDconstant in AppleProduct.java, en probeer opnieuw te deserialiseren de AppleProduct object uit dezelfde String die eerder is geproduceerd. Opnieuw draaien DeserializationUtility.java zou deze output moeten genereren.

Deserialiseren van AppleProduct ... Uitzondering in thread "hoofd" java.io.InvalidClassException: com.baeldung.deserialization.AppleProduct; lokale klasse niet compatibel: stream classdesc serialVersionUID = 1234567, lokale klasse serialVersionUID = 7654321 op java.io.ObjectStreamClass.initNonProxy (ObjectStreamClass.java:616) op java.io.ObjectInputStream.readNonProxyDescio. ObjectInputStream.readClassDesc (ObjectInputStream.java:1521) op java.io.ObjectInputStream.readOrdinaryObject (ObjectInputStream.java:1781) op java.io.ObjectInputStream.readObject0 (ObjectInputStream.javaInputStream.java.1353 .java: 373) op com.baeldung.deserialization.DeserializationUtility.deSerializeObjectFromString (DeserializationUtility.java:24) op com.baeldung.deserialization.DeserializationUtility.main (DeserializationUtility.java:15)

Door de serialVersionUID van de klasse, hebben we de versie / staat gewijzigd. Als gevolg hiervan werden geen compatibele klassen gevonden tijdens deserialisatie en een InvalidClassException is gegooid.

3. Compatibele wijzigingen

Laten we zeggen dat we een nieuw veld moeten toevoegen bliksempoort aan onze bestaande AppleProduct klasse:

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

Omdat we net een nieuw veld aan het toevoegen zijn, geen verandering in de serialVersionUID zal vereist zijn. Dit is zo omdat, tijdens het deserialisatieproces, nul wordt toegewezen als de standaardwaarde voor de bliksempoort veld-.

Laten we onze Deserialisatie Utility class om de waarde van dit nieuwe veld af te drukken:

System.out.println ("LightningPort-poort van AppleProduct:" + deserializedObj.getLightningPort ());

Nu, wanneer we het Deserialisatie Utility class, zullen we een output zien die lijkt op:

Deserialiseren van AppleProduct ... Hoofdtelefoonpoort van AppleProduct: headphonePort2020 Thunderbolt-poort van AppleProduct: thunderboltPort2020 Lightning-poort van AppleProduct: null

4. Standaard seriële versie

Als we een serialVersionUID staat voor een Serialiseerbaar klasse, dan zal Java er een definiëren op basis van enkele eigenschappen van de klasse zelf, zoals de klassenaam, instantievelden, enzovoort.

Laten we een simpele definiëren Serialiseerbaar klasse:

openbare klasse DefaultSerial implementeert Serializable {}

Als we een instantie van deze klasse als volgt serialiseren:

DefaultSerial instantie = nieuwe DefaultSerial (); System.out.println (SerializationUtility.serializeObjectToString (instantie));

Hiermee wordt de Base64-samenvatting van het geserialiseerde binaire bestand afgedrukt:

rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz / mdAIAAHhw

Net als voorheen zouden we deze instantie uit de samenvatting moeten kunnen deserialiseren:

String digest = "rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpY" + "WxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz / mdAIAAHhw"; DefaultSerial instantie = (DefaultSerial) DeserializationUtility.deSerializeObjectFromString (overzicht);

Sommige wijzigingen in deze klasse kunnen echter de compatibiliteit van de serialisatie verstoren. Als we bijvoorbeeld een privaat veld voor deze klasse:

openbare klasse DefaultSerial implementeert Serializable {private String-naam; }

En probeer dan dezelfde Base64-samenvatting te deserialiseren naar een klasse-instantie, we krijgen een InvalidClassException:

Uitzondering in thread "hoofd" java.io.InvalidClassException: com.baeldung.deserialization.DefaultSerial; lokale klasse incompatibel: stream classdesc serialVersionUID = 9045863543269746292, lokale klasse serialVersionUID = -2692722436255640434

Vanwege dit soort ongewenste incompatibiliteit is het altijd een goed idee om een serialVersionUID in Serialiseerbaar klassen. Op deze manier kunnen we de versie behouden of evolueren naarmate de klasse zelf evolueert.

5. Conclusie

In dit korte artikel hebben we het gebruik van de serialVersionUID constant om versiebeheer van geserialiseerde gegevens te vergemakkelijken.

Zoals altijd zijn de codevoorbeelden die in dit artikel worden gebruikt, te vinden op GitHub.