Pengenalan Serialisasi Java

1. Pengenalan

Serialisasi adalah penukaran keadaan objek menjadi aliran bait; deserialisasi melakukan sebaliknya. Dinyatakan secara berbeza, serialisasi adalah penukaran objek Java menjadi aliran statis (urutan) byte yang kemudian dapat disimpan ke pangkalan data atau dipindahkan melalui jaringan.

2. Serialisasi dan Deserialisasi

Proses serialisasi tidak bergantung pada contoh, iaitu objek dapat diselaraskan pada satu platform dan terdeseralisasikan pada platform lain. Kelas yang layak untuk bersiri perlu melaksanakan antara muka penanda khas Serializable.

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

Kaedah yang paling penting dalam ObjectOutputStream adalah:

public final void writeObject(Object o) throws IOException;

Yang mengambil objek bersiri dan menukarnya menjadi urutan (aliran) bait. Begitu juga, kaedah yang paling penting dalam ObjectInputStream adalah:

public final Object readObject() throws IOException, ClassNotFoundException;

Yang dapat membaca aliran byte dan mengubahnya kembali menjadi objek Java. Ini kemudian boleh dilemparkan kembali ke objek asal.

Mari kita gambarkan bersiri dengan kelas Orang . Perhatikan bahawa medan statik tergolong dalam kelas (berbanding objek) dan tidak bersiri . Juga, perhatikan bahawa kita boleh menggunakan kata kunci sementara untuk mengabaikan bidang kelas semasa bersiri:

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 }

Ujian di bawah menunjukkan contoh menyimpan objek jenis Orang ke fail tempatan kemudian baca semula nilai ini:

@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 keadaan objek ini ke file menggunakan FileOutputStream . Fail "yourfile.txt" dibuat dalam direktori projek. Fail ini kemudian dimuat menggunakan FileInputStream. ObjectInputStream mengambil aliran ini dan mengubahnya menjadi objek baru yang disebut p2 .

Akhirnya, kami menguji keadaan objek yang dimuat, dan ia sepadan dengan keadaan objek asal.

Perhatikan bahawa objek yang dimuat harus dilemparkan secara eksplisit ke jenis Orang .

3. Kaveat Serialisasi Jawa

Ada beberapa peringatan yang menyangkut serialisasi di Jawa.

3.1. Warisan dan Komposisi

Apabila kelas menggunakan antara muka java.io.Serializable , semua sub-kelasnya juga boleh diselaraskan. Sebaliknya, apabila objek mempunyai rujukan ke objek lain, objek ini mesti melaksanakan antara muka Serializable secara berasingan, jika tidak, NotSerializableException akan dilemparkan:

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

Sekiranya salah satu bidang dalam objek bersiri terdiri daripada pelbagai objek, maka semua objek ini mesti disenaraikan juga, jika tidak, NotSerializableException akan dilemparkan.

3.2. UID Versi Bersiri

JVM mengaitkan nombor versi ( panjang ) dengan setiap kelas bersiri. Ia digunakan untuk mengesahkan bahawa objek yang disimpan dan dimuat mempunyai atribut yang sama dan dengan itu serasi pada siri.

Nombor ini dapat dihasilkan secara automatik oleh kebanyakan IDE dan berdasarkan nama kelas, atributnya dan pengubah akses yang berkaitan. Sebarang perubahan menghasilkan nombor yang berbeza dan boleh menyebabkan InvalidClassException .

Sekiranya kelas bersiri tidak mengisytiharkan serialVersionUID , JVM akan menghasilkan satu secara automatik pada waktu berjalan. Walau bagaimanapun, sangat disarankan agar setiap kelas menyatakan serialVersionUIDnya kerana kelas yang dihasilkan bergantung pada penyusun dan dengan demikian boleh mengakibatkan Pengecualian Tidak SahClass yang tidak dijangka .

3.3. Serialisasi Custom di Java

Java menentukan cara lalai di mana objek dapat diselaraskan. Kelas Java boleh mengatasi tingkah laku lalai ini. Serialisasi khusus dapat sangat berguna ketika berusaha untuk membuat siri objek yang mempunyai beberapa atribut yang tidak dapat disaring. Ini dapat dilakukan dengan menyediakan dua kaedah di dalam kelas yang ingin kita buat bersiri:

private void writeObject(ObjectOutputStream out) throws IOException;

dan

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

Dengan kaedah ini, kita dapat menyusun atribut-atribut yang tidak dapat diselaraskan ke dalam bentuk lain yang dapat diselaraskan:

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 }

Ujian unit berikut menguji siri bersiri 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 kod ini, kita melihat bagaimana untuk menyimpan beberapa atribut yang tidak dapat diselaraskan dengan membuat siri Alamat dengan siri bersesuaian . Perhatikan bahawa kita mesti menandakan atribut yang tidak dapat diserami sebagai sementara untuk mengelakkan NotSerializableException.

4. Kesimpulan

Dalam tutorial ringkas ini, kami telah mengkaji serialisasi Java, membincangkan perkara-perkara penting yang perlu diingat dan telah menunjukkan cara melakukan serialisasi khusus.

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