Pengantar Serialisasi Java

1. Perkenalan

Serialisasi adalah pengubahan status suatu objek menjadi aliran byte; deserialization melakukan yang sebaliknya. Dinyatakan secara berbeda, serialisasi adalah konversi objek Java menjadi aliran statis (urutan) byte yang kemudian dapat disimpan ke database atau ditransfer melalui jaringan.

2. Serialisasi dan Deserialisasi

Proses serialisasi adalah instance-independent, yaitu objek dapat diserialkan pada satu platform dan deserialisasi pada platform lain. Kelas yang memenuhi syarat untuk serialisasi perlu menerapkan antarmuka penanda khusus yang dapat diserialisasi.

Baik ObjectInputStream dan ObjectOutputStream adalah kelas tingkat tinggi yang memperluas java.io.InputStream dan java.io.OutputStream masing-masing. ObjectOutputStream dapat menulis tipe primitif dan grafik objek ke OutputStream sebagai aliran byte. Aliran ini selanjutnya dapat dibaca menggunakan ObjectInputStream .

Metode terpenting dalam ObjectOutputStream adalah:

public final void writeObject(Object o) throws IOException;

Yang mengambil objek serializable dan mengubahnya menjadi urutan (aliran) byte. Demikian pula, metode terpenting dalam ObjectInputStream adalah:

public final Object readObject() throws IOException, ClassNotFoundException;

Yang dapat membaca aliran byte dan mengubahnya kembali menjadi objek Java. Ini kemudian dapat dikembalikan ke objek aslinya.

Mari kita ilustrasikan serialisasi dengan kelas Person . Perhatikan bahwa bidang statis milik kelas (sebagai lawan dari objek) dan tidak serial . Juga, perhatikan bahwa kita dapat menggunakan kata kunci sementara untuk mengabaikan bidang kelas selama serialisasi:

public class Person implements Serializable { private static final long serialVersionUID = 1L; static String country = "ITALY"; private int age; private String name; transient int height; // getters and setters }

Tes di bawah ini menunjukkan contoh menyimpan objek bertipe Person ke file lokal kemudian membaca nilai ini kembali:

@Test public void whenSerializingAndDeserializing_ThenObjectIsTheSame() () throws IOException, ClassNotFoundException { Person person = new Person(); person.setAge(20); person.setName("Joe"); FileOutputStream fileOutputStream = new FileOutputStream("yourfile.txt"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(person); objectOutputStream.flush(); objectOutputStream.close(); FileInputStream fileInputStream = new FileInputStream("yourfile.txt"); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); Person p2 = (Person) objectInputStream.readObject(); objectInputStream.close(); assertTrue(p2.getAge() == p.getAge()); assertTrue(p2.getName().equals(p.getName())); }

Kami menggunakan ObjectOutputStream untuk menyimpan status objek ini ke file menggunakan FileOutputStream . File "yourfile.txt" dibuat di direktori proyek. File ini kemudian dimuat menggunakan FileInputStream. ObjectInputStream mengambil aliran ini dan mengubahnya menjadi objek baru yang disebut p2 .

Akhirnya, kami menguji status objek yang dimuat, dan itu cocok dengan status objek asli.

Perhatikan bahwa objek yang dimuat harus secara eksplisit dilemparkan ke tipe Person .

3. Peringatan Serialisasi Jawa

Ada beberapa peringatan terkait serialisasi di Jawa.

3.1. Warisan dan Komposisi

Ketika sebuah kelas mengimplementasikan antarmuka java.io.Serializable , semua sub-kelasnya juga dapat diserialkan. Sebaliknya, ketika sebuah objek memiliki referensi ke objek lain, objek ini harus mengimplementasikan antarmuka Serializable secara terpisah, atau NotSerializableException akan muncul:

public class Person implements Serializable { private int age; private String name; private Address country; // must be serializable too } 

Jika salah satu bidang dalam objek yang dapat diserialkan terdiri dari larik objek, semua objek ini juga harus dapat diserialkan, atau NotSerializableException akan ditampilkan .

3.2. Versi Serial UID

JVM mengaitkan nomor versi ( panjang ) dengan setiap kelas yang dapat serial. Ini digunakan untuk memverifikasi bahwa objek yang disimpan dan dimuat memiliki atribut yang sama dan dengan demikian kompatibel pada serialisasi.

Nomor ini dapat dibuat secara otomatis oleh sebagian besar IDE dan didasarkan pada nama kelas, atributnya, dan pengubah akses terkait. Setiap perubahan menghasilkan angka yang berbeda dan dapat menyebabkan InvalidClassException .

Jika kelas yang dapat bersambung tidak mendeklarasikan serialVersionUID , JVM akan menghasilkannya secara otomatis pada waktu proses. Namun, sangat disarankan agar setiap kelas mendeklarasikan serialVersionUID -nya karena yang dihasilkan bergantung pada kompiler dan dengan demikian dapat mengakibatkan InvalidClassExceptions yang tidak terduga .

3.3. Serialisasi Kustom di Jawa

Java menetapkan cara default di mana objek dapat diserialkan. Kelas Java bisa mengganti perilaku default ini. Serialisasi kustom dapat sangat berguna saat mencoba membuat serial objek yang memiliki beberapa atribut yang tidak dapat diserialisasi. Ini dapat dilakukan dengan menyediakan dua metode di dalam kelas yang ingin kita buat serialnya:

private void writeObject(ObjectOutputStream out) throws IOException;

dan

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;

Dengan metode ini, kita dapat membuat serial atribut unserializable ke dalam bentuk lain yang dapat diserialkan:

public class Employee implements Serializable { private static final long serialVersionUID = 1L; private transient Address address; private Person person; // setters and getters private void writeObject(ObjectOutputStream oos) throws IOException { oos.defaultWriteObject(); oos.writeObject(address.getHouseNumber()); } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); Integer houseNumber = (Integer) ois.readObject(); Address a = new Address(); a.setHouseNumber(houseNumber); this.setAddress(a); } }
public class Address { private int houseNumber; // setters and getters }

Tes unit berikut menguji serialisasi kustom ini:

@Test public void whenCustomSerializingAndDeserializing_ThenObjectIsTheSame() throws IOException, ClassNotFoundException { Person p = new Person(); p.setAge(20); p.setName("Joe"); Address a = new Address(); a.setHouseNumber(1); Employee e = new Employee(); e.setPerson(p); e.setAddress(a); FileOutputStream fileOutputStream = new FileOutputStream("yourfile2.txt"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(e); objectOutputStream.flush(); objectOutputStream.close(); FileInputStream fileInputStream = new FileInputStream("yourfile2.txt"); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); Employee e2 = (Employee) objectInputStream.readObject(); objectInputStream.close(); assertTrue( e2.getPerson().getAge() == e.getPerson().getAge()); assertTrue( e2.getAddress().getHouseNumber() == e.getAddress().getHouseNumber()); }

Dalam kode ini, kita melihat cara menyimpan beberapa atribut yang tidak dapat diserialisasi dengan membuat serial Alamat dengan serialisasi khusus. Perhatikan bahwa kita harus menandai atribut unserializable sebagai sementara untuk menghindari NotSerializableException.

4. Kesimpulan

Dalam tutorial singkat ini, kami telah meninjau serialisasi Java, membahas hal-hal penting yang perlu diingat dan telah menunjukkan cara melakukan serialisasi kustom.

Seperti biasa, kode sumber yang digunakan dalam tutorial ini tersedia di GitHub.