Hvad er den serielle versionUID?

1. Oversigt

Kort fortalt, det serialVersionUID er en unik identifikator for Serialiserbar klasser.

Dette bruges under deserialisering af et objekt for at sikre, at en indlæst klasse er kompatibel med det serieiserede objekt. Hvis der ikke findes nogen matchende klasse, an InvalidClassException kastes.

2. Seriel version UID

Lad os starte med at oprette en serie, der kan serienummeres, og erklære en serialVersionUID identifikator:

offentlig klasse AppleProduct implementerer Serialiserbar {privat statisk endelig lang serialVersionUID = 1234567L; offentlige String hovedtelefonerPort; offentlig String thunderboltPort; }

Derefter har vi brug for to hjælpeklasser: en til at serieisere en AppleProduct objekt i en Snor, og en anden til at deserialisere objektet ud fra det Snor:

public class SerializationUtility {public static void main (String [] args) {AppleProduct macBook = new AppleProduct (); macBook.headphonePort = "hovedtelefonPort2020"; macBook.thunderboltPort = "thunderboltPort2020"; String serializedObj = serializeObjectToString (macBook); System.out.println ("Serialiseret AppleProduct-objekt til streng:"); System.out.println (serializedObj); } offentlig statisk streng serializeObjectToString (Serialiserbar o) {ByteArrayOutputStream baos = ny ByteArrayOutputStream (); ObjectOutputStream oos = ny ObjectOutputStream (baos); oos.writeObject (o); oos.close (); returner Base64.getEncoder (). encodeToString (baos.toByteArray ()); }}
offentlig klasse DeserializationUtility {public static void main (String [] args) {String serializedObj = ... // ommitted for klarhed System.out.println ("Deserialisering af AppleProduct ..."); AppleProduct deserializedObj = (AppleProduct) deSerializeObjectFromString (serializedObj); System.out.println ("Hovedtelefonport til AppleProduct:" + deserializedObj.getHeadphonePort ()); System.out.println ("AppleProduct Thunderbolt-port:" + deserializedObj.getThunderboltPort ()); } offentligt statisk objekt deSerializeObjectFromString (String s) kaster IOException, ClassNotFoundException {byte [] data = Base64.getDecoder (). afkode (r); ObjectInputStream ois = ny ObjectInputStream (ny ByteArrayInputStream (data)); Objekt o = ois.readObject (); ois.close (); returnere o; }}

Vi begynder med at løbe SerializationUtility.java, som gemmer (serialiserer) AppleProduct objekt i en Snor instance, kodning af bytes ved hjælp af Base64.

Brug derefter det Snor som et argument for deserialiseringsmetoden kører vi DeserializationUtility.java, der samles (deserialiserer) AppleProduct objekt fra det givne Snor.

Det genererede output skal svare til dette:

Føljeton AppleProduct objekt til streng: rO0ABXNyACljb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkFwcGxlUHJvZHVjdAAAAAAAEta HAgADTAANaGVhZHBob25lUG9ydHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wADmxpZ2h0ZW5pbmdQb3 J0cQB + AAFMAA90aHVuZGVyYm9sdFBvcnRxAH4AAXhwdAARaGVhZHBob25lUG9ydDIwMjBwdAATd Gh1bmRlcmJvbHRQb3J0MjAyMA ==
Deserialisering af AppleProduct ... Hovedtelefonport til AppleProdukt: hovedtelefonPort2020 Thunderbolt-port til AppleProdukt: thunderboltPort2020

Lad os nu ændre serialVersionUIDkonstant i AppleProduct.java, og forsøg igen at deserialisere det AppleProduct objekt fra samme streng produceret tidligere. Genkører DeserializationUtility.java skulle generere dette output.

Deserialisering af AppleProduct ... Undtagelse i tråden "main" java.io.InvalidClassException: com.baeldung.deserialization.AppleProduct; lokal klasse inkompatibel: stream classdesc serialVersionUID = 1234567, local class serialVersionUID = 7654321 at java.io.ObjectStreamClass.initNonProxy (ObjectStreamClass.java:616) på java.io.ObjectInputStream.readNonProxyDesc (ObjectInputStream.java.16: ObjectInputStream.readClassDesc (ObjectInputStream.java:1521) på java.io.ObjectInputStream.readOrdinaryObject (ObjectInputStream.java:1781) ved java.io.ObjectInputStream.readObject0 (ObjectInputStream.java:1353) ved java.io.ObjectInputStream.putStream.put .java: 373) ved com.baeldung.deserialization.DeserializationUtility.deSerializeObjectFromString (DeserializationUtility.java:24) på ​​com.baeldung.deserialization.DeserializationUtility.main (DeserializationUtility.java:15)

Ved at ændre serialVersionUID af klassen ændrede vi dens version / tilstand. Som et resultat blev der ikke fundet nogen kompatible klasser under deserialisering, og en InvalidClassException blev kastet.

3. Kompatible ændringer

Lad os sige, at vi skal tilføje et nyt felt lynport til vores eksisterende AppleProduct klasse:

offentlig klasse AppleProduct implementerer Serializable {// ... public String lightningPort; }

Da vi lige tilføjer et nyt felt, ingen ændring i serialVersionUID kræves. Dette er fordi, under deserialiseringsprocessen nul tildeles som standardværdien for lynport Mark.

Lad os ændre vores DeserializationUtility klasse for at udskrive værdien af ​​dette nye felt:

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

Nu, når vi kører igen DeserializationUtility klasse, vil vi se output svarende til:

Deserialisering af AppleProduct ... Hovedtelefonport til AppleProdukt: hovedtelefonPort2020 Thunderbolt-port af AppleProdukt: thunderboltPort2020 Lightning-port til AppleProdukt: null

4. Standard serieversion

Hvis vi ikke definerer en serialVersionUID stat for en Serialiserbar klasse, så definerer Java en baseret på nogle egenskaber for selve klassen, såsom klassens navn, forekomstfelter og så videre.

Lad os definere en simpel Serialiserbar klasse:

offentlig klasse DefaultSerial implementerer Serializable {}

Hvis vi serierer en forekomst af denne klasse som følger:

DefaultSerial forekomst = ny DefaultSerial (); System.out.println (SerializationUtility.serializeObjectToString (forekomst));

Dette udskriver Base64-fordøjelsen af ​​den serielle binær:

rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz / mdAIAAHhw

Ligesom før, skal vi være i stand til at deserialisere denne forekomst fra fordøjelsen:

Strengfordøjelse = "rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpY" + "WxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz / mdAIAAHhw"; DefaultSerial forekomst = (DefaultSerial) DeserializationUtility.deSerializeObjectFromString (fordøjelse);

Dog kan nogle ændringer i denne klasse bryde seriekompatibiliteten. For eksempel, hvis vi tilføjer en privat felt til denne klasse:

offentlig klasse DefaultSerial implementerer Serialiserbar {privat strengnavn; }

Og prøv derefter at deserialisere den samme Base64-fordøjelse til en klasseinstans, vi får en InvalidClassException:

Undtagelse i tråden "main" java.io.InvalidClassException: com.baeldung.deserialization.DefaultSerial; lokal klasse inkompatibel: stream classdesc serialVersionUID = 9045863543269746292, local class serialVersionUID = -2692722436255640434

På grund af denne form for uønsket inkompatibilitet er det altid en god ide at erklære en serialVersionUID i Serialiserbar klasser. På denne måde kan vi beholde eller udvikle versionen, når klassen selv udvikler sig.

5. Konklusion

I denne hurtige artikel demonstrerede vi brugen af serialVersionUID konstant for at lette versionering af serielle data.

Som altid kan kodeeksemplerne, der bruges i denne artikel, findes på GitHub.