Apa itu serialVersionUID?

1. Ikhtisar

Sederhananya, yang serialVersionUID adalah sebuah identifikasi unik untuk Serializable kelas.

Ini digunakan selama deserialisasi objek, untuk memastikan bahwa kelas yang dimuat kompatibel dengan objek serial. Jika tidak ada kelas yang cocok ditemukan, InvalidClassException akan muncul.

2. Versi Serial UID

Mari kita mulai dengan membuat kelas yang dapat bersambung, dan mendeklarasikan pengenal serialVersionUID :

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

Selanjutnya, kita memerlukan dua kelas utilitas: satu untuk membuat serial objek AppleProduct menjadi String, dan satu lagi untuk menghilangkan 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 mulai dengan menjalankan SerializationUtility.java , yang menyimpan (membuat serial) objek AppleProduct ke dalam instans String , mengenkode byte menggunakan Base64.

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

Output yang dihasilkan harus 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 memodifikasi serialVersionUID konstan dalam AppleProduct.java, dan mencoba kembali deserialize yang AppleProduct objek dari String yang sama yang diproduksi sebelumnya. Menjalankan kembali DeserializationUtility.java akan menghasilkan keluaran 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 mengubah serialVersionUID kelas, kami mengubah versi / statusnya. Akibatnya, tidak ada kelas yang kompatibel yang ditemukan selama deserialization, dan InvalidClassException muncul.

3. Perubahan Kompatibel

Katakanlah kita perlu menambahkan bidang baru lightningPort ke kelas AppleProduct yang ada :

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

Karena kami hanya menambahkan bidang baru, tidak ada perubahan dalam serialVersionUID yang diperlukan . Ini karena, selama proses deserialisasi, null akan ditetapkan sebagai nilai default untuk bidang lightningPort .

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

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

Sekarang, ketika kita menjalankan kembali kelas DeserializationUtility , kita akan melihat keluaran yang mirip dengan:

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

4. Versi Serial Default

Jika kita tidak mendefinisikan status serialVersionUID untuk kelas Serializable , maka Java akan mendefinisikan satu berdasarkan beberapa properti kelas itu sendiri seperti nama kelas, bidang instance, dan sebagainya.

Mari tentukan kelas Serializable sederhana :

public class DefaultSerial implements Serializable { }

Jika kita membuat serial instance kelas ini seperti berikut:

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

Ini akan mencetak intisari Base64 dari biner berseri:

rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz/mdAIAAHhw

Sama seperti sebelumnya, kita harus dapat menghilangkan contoh ini dari intisari:

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

Namun, beberapa perubahan pada kelas ini dapat merusak kompatibilitas serialisasi. Misalnya, jika kita menambahkan bidang privat ke kelas ini:

public class DefaultSerial implements Serializable { private String name; }

Dan kemudian coba deserialisasi intisari Base64 yang sama ke instance kelas, kita akan mendapatkan InvalidClassException:

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

Karena jenis ketidakcocokan yang tidak diinginkan ini, sebaiknya deklarasikan serialVersionUID dalam kelas Serializable . Dengan cara ini kami dapat mempertahankan atau mengembangkan versinya seiring dengan berkembangnya kelas itu sendiri.

5. Kesimpulan

Dalam artikel singkat ini, kami mendemonstrasikan penggunaan konstanta serialVersionUID untuk memfasilitasi pembuatan versi data serial.

Seperti biasa, contoh kode yang digunakan di seluruh artikel ini dapat ditemukan di GitHub.