Hva er serialVersionUID?

1. Oversikt

For å si det enkelt, de serialVersionUID er en unik identifikator for Serialiserbar klasser.

Dette brukes under deserialisering av et objekt for å sikre at en lastet klasse er kompatibel med det serieiserte objektet. Hvis det ikke finnes noen samsvarende klasse, vil en InvalidClassException blir kastet.

2. Seriell versjon UID

La oss starte med å lage en serie som kan serienummeres, og erklære en serialVersionUID identifikator:

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

Deretter trenger vi to verktøyklasser: en for å serieisere en AppleProdukt objekt i en Streng, og en annen for å deserialisere objektet fra det Streng:

public class SerializationUtility {public static void main (String [] args) {AppleProduct macBook = new AppleProduct (); macBook.headphonePort = "hodetelefonPort2020"; macBook.thunderboltPort = "thunderboltPort2020"; String serializedObj = serializeObjectToString (macBook); System.out.println ("Serialisert AppleProduct-objekt til streng:"); System.out.println (serializedObj); } offentlig statisk streng serializeObjectToString (Serializable o) {ByteArrayOutputStream baos = ny ByteArrayOutputStream (); ObjectOutputStream oos = ny ObjectOutputStream (baos); oos.writeObject (o); oos.close (); returner 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 ("Hodetelefonport til AppleProduct:" + deserializedObj.getHeadphonePort ()); System.out.println ("Thunderbolt-porten til AppleProduct:" + deserializedObj.getThunderboltPort ()); } offentlig statisk objekt deSerializeObjectFromString (String s) kaster IOException, ClassNotFoundException {byte [] data = Base64.getDecoder (). dekode (r); ObjectInputStream ois = new ObjectInputStream (ny ByteArrayInputStream (data)); Objekt o = ois.readObject (); ois.close (); retur o; }}

Vi begynner med å løpe SerializationUtility.java, som sparer (serialiserer) AppleProdukt objekt i en String instance, koding av byte ved hjelp av Base64.

Bruk deretter det String som et argument for deserialiseringsmetoden, kjører vi DeserializationUtility.java, som setter sammen (deserialiserer) AppleProdukt objekt fra det gitte String.

Produksjonen som genereres, skal være lik denne:

Serialisert AppleProduct objekt til strengen: rO0ABXNyACljb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkFwcGxlUHJvZHVjdAAAAAAAEta HAgADTAANaGVhZHBob25lUG9ydHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wADmxpZ2h0ZW5pbmdQb3 J0cQB + AAFMAA90aHVuZGVyYm9sdFBvcnRxAH4AAXhwdAARaGVhZHBob25lUG9ydDIwMjBwdAATd Gh1bmRlcmJvbHRQb3J0MjAyMA ==
Deserialisere AppleProduct ... Hodetelefonport til AppleProdukt: hodetelefonPort2020 Thunderbolt-port i AppleProdukt: thunderboltPort2020

La oss nå endre serialVersionUIDkonstant i AppleProduct.java, og prøv på nytt å deserialisere de AppleProdukt objekt fra samme streng produsert tidligere. Kjører på nytt DeserializationUtility.java skal generere denne produksjonen.

Deserialisering av AppleProduct ... Unntak 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) at java.io.ObjectInputStream.readNonProxyDesc (ObjectInputStream.java.16: ObjectInputStream.readClassDesc (ObjectInputStream.java:1521) på java.io.ObjectInputStream.readOrdinaryObject (ObjectInputStream.java:1781) på java.io.ObjectInputStream.readObject0 (ObjectInputStream.java:1353) ved java.io.Stream.InputStream.InputStream.InputStream.InputStream. .java: 373) ved com.baeldung.deserialization.DeserializationUtility.deSerializeObjectFromString (DeserializationUtility.java:24) på ​​com.baeldung.deserialization.DeserializationUtility.main (DeserializationUtility.java:15)

Ved å endre serialVersionUID av klassen endret vi versjonen / tilstanden. Som et resultat ble ingen kompatible klasser funnet under deserialisering, og en InvalidClassException ble kastet.

3. Kompatible endringer

La oss si at vi må legge til et nytt felt lynport til vår eksisterende AppleProdukt klasse:

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

Siden vi bare legger til et nytt felt, ingen endring i serialVersionUID vil være påkrevd. Dette er fordi, under deserialiseringsprosessen, null vil bli tildelt som standardverdi for lynport felt.

La oss endre vår DeserializationUtilility klasse for å skrive ut verdien av dette nye feltet:

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

Nå, når vi kjører om DeserializationUtilility klasse, vil vi se utdata som ligner på:

Deserialisere AppleProduct ... Hodetelefonport til AppleProdukt: hodetelefonPort2020 Thunderbolt-port til AppleProdukt: ThunderboltPort2020 Lightning-port til AppleProdukt: null

4. Standard serieversjon

Hvis vi ikke definerer en serialVersionUID stat for en Serialiserbar klasse, så definerer Java en basert på noen egenskaper i selve klassen, for eksempel klassenavn, forekomstfelt og så videre.

La oss definere en enkel Serialiserbar klasse:

offentlig klasse DefaultSerial implementerer Serializable {}

Hvis vi serierer en forekomst av denne klassen slik:

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

Dette vil skrive ut Base64-fordøyelsen av den serielle binæren:

rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz / mdAIAAHhw

Akkurat som før, skal vi kunne deserialisere denne forekomsten fra fordøyelsen:

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

Imidlertid kan noen endringer i denne klassen bryte serialiseringskompatibiliteten. For eksempel hvis vi legger til en privat felt til denne klassen:

offentlig klasse DefaultSerial implementerer Serializable {private strengnavn; }

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

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

På grunn av denne typen uønsket inkompatibilitet er det alltid en god ide å erklære et serialVersionUID i Serialiserbar klasser. På denne måten kan vi beholde eller utvikle versjonen etter hvert som klassen utvikler seg.

5. Konklusjon

I denne raske artikkelen demonstrerte vi bruken av serialVersionUID konstant for å lette versjonering av seriell data.

Som alltid kan kodeeksemplene som brukes i denne artikkelen finnes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found