Panduan untuk Antara Muka yang Boleh Diluar di Java

1. Pengenalan

Dalam tutorial ini, kita akan melihat pantas antara muka antara muka java.io.Java.Externalizable . Matlamat utama antara muka ini adalah untuk mempermudah serialisasi dan deserialisasi.

Sebelum kita teruskan, pastikan anda melihat penyirian dalam artikel Java. Bab seterusnya adalah mengenai bagaimana membuat siri objek Java dengan antara muka ini.

Selepas itu, kita akan membincangkan perbezaan utama berbanding antara muka java.io.Serializable .

2. Antara Muka Yang Boleh Diluar

Externalizable meluas dari antara muka penanda java.io.Serializable . Mana-mana kelas yang melaksanakan Externalizable antara muka perlu mengatasi writeExternal () , readExternal () kaedah . Dengan cara itu kita dapat mengubah tingkah laku serialisasi lalai JVM.

2.1. Serialisasi

Mari kita lihat contoh ringkas ini:

public class Country implements Externalizable { private static final long serialVersionUID = 1L; private String name; private int code; // getters, setters @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(name); out.writeInt(code); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.name = in.readUTF(); this.code = in.readInt(); } }

Di sini, kami telah menentukan Negara kelas yang menerapkan antara muka Externalizable dan melaksanakan dua kaedah yang disebutkan di atas.

Dalam kaedah writeExternal () , kami menambahkan sifat objek ke aliran ObjectOutput . Ini mempunyai kaedah standard seperti writeUTF () untuk String dan writeInt () untuk nilai int.

Seterusnya, untuk deserialisasi objek, kita membaca dari aliran ObjectInput menggunakan kaedah readUTF (), readInt () untuk membaca sifat dalam urutan tepat yang sama dengan yang ditulis.

Adalah amalan yang baik untuk menambahkan serialVersionUID secara manual. Sekiranya ini tidak hadir, JVM akan menambahkannya secara automatik.

Nombor yang dihasilkan secara automatik bergantung kepada penyusun. Ini bermaksud ia boleh menyebabkan InvalidClassException yang tidak mungkin .

Mari kita uji tingkah laku yang kita laksanakan di atas:

@Test public void whenSerializing_thenUseExternalizable() throws IOException, ClassNotFoundException { Country c = new Country(); c.setCode(374); c.setName("Armenia"); FileOutputStream fileOutputStream = new FileOutputStream(OUTPUT_FILE); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); c.writeExternal(objectOutputStream); objectOutputStream.flush(); objectOutputStream.close(); fileOutputStream.close(); FileInputStream fileInputStream = new FileInputStream(OUTPUT_FILE); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); Country c2 = new Country(); c2.readExternal(objectInputStream); objectInputStream.close(); fileInputStream.close(); assertTrue(c2.getCode() == c.getCode()); assertTrue(c2.getName().equals(c.getName())); }

Dalam contoh ini, pertama-tama kita membuat objek Negara dan menulisnya ke fail. Kemudian, kami menyahpusatkan objek dari fail dan mengesahkan nilainya betul.

Keluaran objek c2 yang dicetak :

Country{name='Armenia', code=374}

Ini menunjukkan bahawa kita berjaya mendeseralisasikan objek.

2.2. Warisan

Apabila kelas mewarisi dari antara muka Serializable , JVM secara automatik mengumpulkan semua bidang dari sub-kelas juga dan menjadikannya bersiri.

Perlu diingat bahawa kami juga dapat menerapkannya pada Externalizable . Kita hanya perlu melaksanakan kaedah membaca / menulis untuk setiap sub-kelas hierarki pewarisan.

Mari lihat kelas Wilayah di bawah yang meluaskan kelas Negara kita dari bahagian sebelumnya:

public class Region extends Country implements Externalizable { private static final long serialVersionUID = 1L; private String climate; private Double population; // getters, setters @Override public void writeExternal(ObjectOutput out) throws IOException { super.writeExternal(out); out.writeUTF(climate); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { super.readExternal(in); this.climate = in.readUTF(); } }

Di sini, kami menambah dua sifat tambahan dan membuat siri yang pertama.

Perhatikan bahawa kami juga memanggil super.writeExternal (out), super.readExternal (in) dalam kaedah serializer untuk menyimpan / memulihkan medan kelas induk juga .

Mari jalankan ujian unit dengan data berikut:

Region r = new Region(); r.setCode(374); r.setName("Armenia"); r.setClimate("Mediterranean"); r.setPopulation(120.000);

Inilah objek deserialized:

Region{ country="Country{ name="Armenia', code=374}' climate="Mediterranean", population=null }

Perhatikan bahawa kerana kita tidak membuat siri populasi dalam kelas Wilayah , nilai harta tanah itu adalah nol.

3. Externalizable vs Serializable

Mari kita perhatikan perbezaan utama antara kedua-dua antara muka:

  • Tanggungjawab Serialisasi

Perbezaan utama di sini adalah bagaimana kita menangani proses bersiri. Apabila kelas menggunakan antara muka java.io.Serializable , JVM bertanggungjawab sepenuhnya untuk membuat siri kelas. Sekiranya Externalizable, pengaturcara harus mengurus keseluruhan siri dan proses deserialisasi.

  • Gunakan Kes

Sekiranya kita perlu membuat siri keseluruhan objek, antara muka Serializable lebih sesuai. Sebaliknya, untuk serialisasi tersuai, kita dapat mengawal proses menggunakan Externalizable .

  • Persembahan

Antara muka java.io.Serializable menggunakan pantulan dan metadata yang menyebabkan prestasi agak perlahan. Sebagai perbandingan, antara muka Externalizable memberi anda kawalan penuh terhadap proses bersiri.

  • Pesanan Membaca

Semasa menggunakan Externalizable , wajib membaca semua keadaan bidang mengikut urutan yang tepat seperti yang ditulis. Jika tidak, kami akan mendapat pengecualian.

For example, if we change the reading order of the code and name properties in the Country class, a java.io.EOFException will be thrown.

Meanwhile, the Serializable interface doesn't have that requirement.

  • Custom Serialization

We can achieve custom serialization with the Serializable interface by marking the field with transient keyword. The JVM won't serialize the particular field but it'll add up the field to file storage with the default value. That's why it's a good practice to use Externalizable in case of custom serialization.

4. Conclusion

Dalam panduan ini singkat ke Externalizable antara muka, kita membincangkan ciri-ciri utama, kebaikan dan contoh menunjukkan penggunaan mudah. Kami juga membuat perbandingan dengan antara muka Serializable .

Seperti biasa, kod sumber penuh tutorial terdapat di GitHub.