Apa itu serialVersionUID?

1. Gambaran keseluruhan

Ringkasnya, yang serialVersionUID adalah pengecam unik untuk Serializable kelas.

Ini digunakan semasa deserialisasi objek, untuk memastikan bahawa kelas yang dimuat sesuai dengan objek bersiri. Sekiranya tidak terdapat kelas yang sepadan, InvalidClassException akan dilemparkan.

2. UID Versi Bersiri

Mari mulakan dengan membuat kelas bersiri, dan nyatakan pengenal serialVersionUID :

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

Seterusnya, kita memerlukan dua kelas utiliti: satu untuk membuat siri objek AppleProduct menjadi String, dan yang lain untuk mendeserisasi objek dari String itu:

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

Kita mulakan dengan menjalankan SerializationUtility.java , yang menyimpan (bersiri) objek AppleProduct menjadi insting String , mengekod byte menggunakan Base64.

Kemudian, menggunakan String itu sebagai argumen untuk kaedah deserialization, kami menjalankan DeserializationUtility.java, yang memasang kembali (deserialized) objek AppleProduct dari String yang diberikan .

Output yang dihasilkan mestilah serupa dengan ini:

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

Sekarang, mari kita mengubah suai serialVersionUID berterusan dalam AppleProduct.java, dan cuba membuat untuk deserialize yang AppleProduct objek dari String sama yang dikeluarkan sebelum ini. Menjalankan semula DeserializationUtility.java harus menghasilkan output ini.

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

Dengan menukar serialVersionUID kelas, kami mengubahsuai versi / keadaannya. Akibatnya, tidak ada kelas yang sesuai dijumpai semasa deserialisasi, dan InvalidClassException dilemparkan.

3. Perubahan yang Sesuai

Katakan kita perlu menambah medan petir baru ke kelas AppleProduct yang ada :

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

Oleh kerana kita hanya menambah satu bidang baru, tiada perubahan dalam serialVersionUID akan diperlukan . Ini kerana, semasa proses deserialisasi, null akan ditetapkan sebagai nilai lalai untuk medan lightningPort .

Mari ubah kelas DeserializationUtility kami untuk mencetak nilai bidang baru ini:

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

Sekarang, apabila kita menjalankan semula kelas DeserializationUtility , kita akan melihat output yang serupa dengan:

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

4. Versi Bersiri Lalai

Sekiranya kita tidak menentukan keadaan serialVersionUID untuk kelas Serializable , maka Java akan menentukan satu berdasarkan beberapa sifat kelas itu sendiri seperti nama kelas, bidang contoh, dan sebagainya.

Mari tentukan kelas Serializable yang mudah :

public class DefaultSerial implements Serializable { }

Sekiranya kita membuat siri contoh kelas ini seperti berikut:

DefaultSerial instance = new DefaultSerial(); System.out.println(SerializationUtility.serializeObjectToString(instance));

Ini akan mencetak rangkuman Base64 binari bersiri:

rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz/mdAIAAHhw

Sama seperti sebelumnya, kita seharusnya dapat mendeserialisasikan contoh ini dari ringkasan:

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

Walau bagaimanapun, beberapa perubahan pada kelas ini boleh merosakkan keserasian siri. Contohnya, jika kita menambahkan medan peribadi ke kelas ini:

public class DefaultSerial implements Serializable { private String name; }

Dan kemudian cuba untuk mendeserialisasikan digest Base64 yang sama ke contoh kelas, kita akan mendapat InvalidClassException:

Exception in thread "main" java.io.InvalidClassException: com.baeldung.deserialization.DefaultSerial; local class incompatible: stream classdesc serialVersionUID = 9045863543269746292, local class serialVersionUID = -2692722436255640434

Kerana ketidaksesuaian yang tidak diingini, adalah idea yang baik untuk menyatakan serialVersionUID dalam kelas Serializable . Dengan cara ini kita dapat menyimpan atau mengembangkan versi seiring dengan perkembangan kelas itu sendiri.

5. Kesimpulan

Dalam artikel ringkas ini, kami menunjukkan penggunaan pemalar serialVersionUID untuk mempermudah pembuatan data bersiri.

Seperti biasa, contoh kod yang digunakan sepanjang artikel ini boleh didapati di GitHub.