Što je serialVersionUID?

1. Pregled

Jednostavno rečeno, the serialVersionUID je jedinstveni identifikator za Serijalizirati razreda.

To se koristi tijekom deserializacije objekta kako bi se osiguralo da je učitana klasa kompatibilna sa serializiranim objektom. Ako nije pronađena odgovarajuća klasa, prikazat će se InvalidClassException baca se.

2. UID serijske verzije

Počnimo sa stvaranjem klase koja se može serirati i proglasimo a serialVersionUID identifikator:

javna klasa AppleProduct implementira Serializable {private static final long serialVersionUID = 1234567L; javni String slušalice; javni String thunderboltPort; }

Dalje, trebat će nam dvije korisne klase: jedna za serializaciju an AppleProduct objekt u a Niz, a drugi da deserijalizira objekt iz toga Niz:

javna klasa SerializationUtility {public static void main (String [] args) {AppleProduct macBook = novi AppleProduct (); macBook.headphonePort = "port za slušalice2020"; macBook.thunderboltPort = "thunderboltPort2020"; Niz serializedObj = serializeObjectToString (macBook); System.out.println ("Serijalizirani objekt AppleProduct u niz:"); System.out.println (serializedObj); } javni statički niz serializeObjectToString (Serializable o) {ByteArrayOutputStream baos = new ByteArrayOutputStream (); ObjectOutputStream oos = novi ObjectOutputStream (baos); oos.writeObject (o); oos.close (); vratiti Base64.getEncoder (). encodeToString (baos.toByteArray ()); }}
javna klasa DeserializationUtility {public static void main (String [] args) {String serializedObj = ... // ommited for clarity System.out.println ("Deserializiranje AppleProduct ..."); AppleProduct deserializedObj = (AppleProduct) deSerializeObjectFromString (serializedObj); System.out.println ("Port za slušalice AppleProduct:" + deserializedObj.getHeadphonePort ()); System.out.println ("Thunderbolt port AppleProduct:" + deserializedObj.getThunderboltPort ()); } javni statični objekt deSerializeObjectFromString (String s) baca IOException, ClassNotFoundException {byte [] data = Base64.getDecoder (). decode (s); ObjectInputStream ois = novi ObjectInputStream (novi ByteArrayInputStream (podaci)); Objekt o = ois.readObject (); ois.close (); povratak o; }}

Počinjemo trčanjem SerializationUtility.java, koji sprema (serializira) AppleProduct objekt u a Niz instance, kodiranje bajtova pomoću Base64.

Zatim, koristeći to Niz kao argument za metodu deserializacije pokrećemo DeserializationUtility.java, koji ponovno sastavlja (deserializira) AppleProduct objekt iz zadanog Niz.

Izlazni rezultat trebao bi biti sličan ovome:

Serijaliziranom AppleProduct objekt string: rO0ABXNyACljb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkFwcGxlUHJvZHVjdAAAAAAAEta HAgADTAANaGVhZHBob25lUG9ydHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wADmxpZ2h0ZW5pbmdQb3 J0cQB + AAFMAA90aHVuZGVyYm9sdFBvcnRxAH4AAXhwdAARaGVhZHBob25lUG9ydDIwMjBwdAATd Gh1bmRlcmJvbHRQb3J0MjAyMA ==
Deserializacija AppleProduct ... Luka za slušalice AppleProduct: headphonePort2020 Thunderbolt port AppleProduct: thunderboltPort2020

Sada, izmijenimo serialVersionUIDkonstantan u AppleProduct.java, i ponoviti pokušaj deserializacije the AppleProduct objekt iz istog Stringa proizvedenog ranije. Ponovno pokretanje DeserializationUtility.java treba generirati ovaj izlaz.

Deserijaliziranje AppleProduct ... Iznimka u niti "main" java.io.InvalidClassException: com.baeldung.deserialization.AppleProduct; lokalna klasa nekompatibilna: tok classdesc serialVersionUID = 1234567, lokalna klasa serialVersionUID = 7654321 na java.io.ObjectStreamClass.initNonProxy (ObjectStreamClass.java:616) na java.io.ObjectInputStream.readNonProxyDavput.ReadNonProxy.JavDejVextNavProject.Jav.ReadNonProxy.Jav. ObjectInputStream.readClassDesc (ObjectInputStream.java:1521) na java.io.ObjectInputStream.readOrdinaryObject (ObjectInputStream.java:1781) na java.io.ObjectInputStream.readObject0 (ObjectInputStream.jav.InputInputStream.java .java: 373) na com.baeldung.deserialization.DeserializationUtility.deSerializeObjectFromString (DeserializationUtility.java:24) na com.baeldung.deserialization.DeserializationUtility.main (DeserializationUtility.java:15)

Promjenom serialVersionUID razreda, izmijenili smo njegovu verziju / stanje. Kao rezultat, tijekom deserializacije nisu pronađene kompatibilne klase, a an InvalidClassException bio bačen.

3. Kompatibilne promjene

Recimo da moramo dodati novo polje munjaPort našem postojećem AppleProduct razred:

javna klasa AppleProduct implementira Serializable {// ... public String lightningPort; }

Budući da samo dodajemo novo polje, nema promjene u serialVersionUID bit će potrebno. Ovo je zbog, tijekom postupka deserializacije, null bit će dodijeljena kao zadana vrijednost za munjaPort polje.

Izmijenimo svoj DeserializationUtility class za ispis vrijednosti ovog novog polja:

System.out.println ("LightningPort priključak AppleProduct:" + deserializedObj.getLightningPort ());

Sad, kad ponovimo DeserializationUtility klase, vidjet ćemo izlaz sličan:

Deserializacija AppleProduct ... Luka za slušalice AppleProduct: headphonePort2020 Thunderbolt port AppleProduct: thunderboltPort2020 Lightning port AppleProduct: null

4. Zadana serijska verzija

Ako ne definiramo a serialVersionUID država za a Serijalizirati klase, tada će Java definirati jednu na temelju nekih svojstava same klase, kao što su naziv klase, polja instance itd.

Definirajmo jednostavan Serijalizirati razred:

javna klasa DefaultSerial implementira Serializable {}

Ako serializiramo primjerak ove klase na sljedeći način:

Primjer DefaultSerial = novi DefaultSerial (); System.out.println (SerializationUtility.serializeObjectToString (instanca));

Ovo će ispisati Base64 sažetak serializirane binarne datoteke:

rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz / mdAIAAHhw

Kao i prije, i ovu bismo instancu trebali moći deserializirati iz sažetka:

Stvarni sažetak = "rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpY" + "WxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz / mdAIAAHhw"; Primjer DefaultSerial = (DefaultSerial) DeserializationUtility.deSerializeObjectFromString (sažetak);

Međutim, neke promjene ove klase mogu prekinuti kompatibilnost serializacije. Na primjer, ako dodamo a privatni polje za ovu klasu:

javna klasa DefaultSerial implementira Serializable {private String name; }

A zatim pokušajte deserializirati isti Base64 sažetak na instancu klase, dobit ćemo InvalidClassException:

Iznimka u niti "main" java.io.InvalidClassException: com.baeldung.deserialization.DefaultSerial; lokalna klasa nekompatibilna: stream classdesc serialVersionUID = 9045863543269746292, lokalna klasa serialVersionUID = -2692722436255640434

Zbog ove vrste neželjene nekompatibilnosti, uvijek je dobro proglasiti a serialVersionUID u Serijalizirati razreda. Na taj način možemo zadržati ili razvijati verziju kako se razvija i sama klasa.

5. Zaključak

U ovom kratkom članku pokazali smo upotrebu serialVersionUID konstanta kako bi se olakšalo izrađivanje verzija serializiranih podataka.

Kao i uvijek, uzorci koda korišteni u ovom članku mogu se naći na GitHubu.