CodeGym/Java Blog/Acak/Antarmuka eksternal di Jawa
John Squirrels
Level 41
San Francisco

Antarmuka eksternal di Jawa

Dipublikasikan di grup Acak
anggota
Hai! Hari ini kita akan terus mengenal serialisasi dan deserialisasi objek Java . Dalam pelajaran terakhir, kita mengenal antarmuka penanda Serializable , mengulas contoh penggunaannya, dan juga mempelajari cara menggunakan kata kunci sementara untuk mengontrol proses serialisasi. Yah, mengatakan bahwa kita 'mengendalikan proses' mungkin melebih-lebihkan. Kami memiliki satu kata kunci, satu pengidentifikasi versi, dan itu saja. Proses selanjutnya disembunyikan di dalam Java, dan kami tidak dapat mengaksesnya. Tentunya dari segi kenyamanan, ini bagus. Tetapi seorang programmer seharusnya tidak hanya dibimbing oleh kenyamanannya sendiri, bukan? :) Ada faktor lain yang perlu Anda pertimbangkan. Itu sebabnya Serializablebukan satu-satunya mekanisme serialisasi-deserialisasi di Jawa. Hari ini kita akan berkenalan dengan antarmuka Externalizable . Namun sebelum kita mulai mempelajarinya, Anda mungkin memiliki pertanyaan yang masuk akal: mengapa kita membutuhkan mekanisme lain? Serializablemelakukan tugasnya, dan apa yang tidak disukai tentang penerapan otomatis seluruh proses? Dan contoh yang kami lihat juga tidak rumit. Jadi apa masalahnya? Mengapa kita membutuhkan antarmuka lain untuk tugas yang pada dasarnya sama? Faktanya adalah bahwa Serializablememiliki beberapa kekurangan. Kami mencantumkan beberapa di antaranya:
  1. Pertunjukan. Antarmuka Serializablememiliki banyak keunggulan, tetapi kinerja tinggi jelas bukan salah satunya.

    Memperkenalkan antarmuka Externalizable - 2

    Pertama, Serializable implementasi internal menghasilkan sejumlah besar informasi layanan dan semua jenis data sementara.

    Kedua, Serializable bergantung pada API Refleksi (Anda tidak perlu mendalami ini sekarang; Anda dapat membaca lebih lanjut di waktu luang, jika Anda tertarik). Hal ini memungkinkan Anda melakukan hal-hal yang tampaknya mustahil di Jawa: misalnya, mengubah nilai bidang privat. CodeGym memiliki artikel bagus tentang Reflection API . Anda dapat membacanya di sana.

  2. Fleksibilitas. Kami tidak mengontrol proses serialisasi-deserialisasi saat kami menggunakan antarmuka Serializable.

    Di satu sisi, ini sangat nyaman, karena jika kita tidak terlalu peduli dengan kinerja, sepertinya bagus untuk tidak menulis kode. Tetapi bagaimana jika kita benar-benar perlu menambahkan beberapa fitur kita sendiri (kami akan memberikan contohnya di bawah) ke logika serialisasi?

    Pada dasarnya, yang kita miliki untuk mengontrol proses adalah transientkata kunci untuk mengecualikan beberapa data. Itu dia. Itulah seluruh kotak peralatan kami :/

  3. Keamanan. Item ini sebagian berasal dari item sebelumnya.

    Kami belum menghabiskan banyak waktu untuk memikirkan hal ini sebelumnya, tetapi bagaimana jika beberapa informasi di kelas Anda tidak ditujukan untuk mata dan telinga orang lain yang ingin tahu? Contoh sederhananya adalah kata sandi atau data pengguna pribadi lainnya, yang di dunia sekarang ini diatur oleh banyak undang-undang.

    Jika kita menggunakan Serializable, kita tidak bisa berbuat apa-apa. Kami membuat cerita bersambung semuanya apa adanya.

    Namun jika kita melakukannya dengan cara yang benar, kita harus mengenkripsi jenis data ini sebelum menulisnya ke file atau mengirimkannya melalui jaringan. Tapi Serializabletidak membuat ini mungkin.

Memperkenalkan antarmuka Externalizable - 3Baiklah, mari kita lihat bagaimana kelas akan terlihat jika kita menggunakan antarmuka Externalizable.
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class UserInfo implements Externalizable {

   private String firstName;
   private String lastName;
   private String superSecretInformation;

private static final long SERIAL_VERSION_UID = 1L;

   // ...constructor, getters, setters, toString()...

   @Override
   public void writeExternal(ObjectOutput out) throws IOException {

   }

   @Override
   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

   }
}
Seperti yang Anda lihat, kami memiliki perubahan signifikan! Yang utama jelas: saat mengimplementasikan antarmuka Externalizable, Anda harus mengimplementasikan dua metode yang diperlukan: writeExternal()danreadExternal(). Seperti yang kami katakan sebelumnya, tanggung jawab untuk serialisasi dan deserialisasi akan berada di tangan pemrogram. Tapi sekarang Anda bisa memecahkan masalah tanpa kendali atas prosesnya! Seluruh proses diprogram langsung oleh Anda. Secara alami, ini memungkinkan mekanisme yang jauh lebih fleksibel. Selain itu, masalah dengan keamanan terpecahkan. Seperti yang Anda lihat, kelas kami memiliki bidang data pribadi yang tidak dapat disimpan tanpa enkripsi. Sekarang kita dapat dengan mudah menulis kode yang memenuhi batasan ini. Misalnya, kita dapat menambahkan ke kelas kita dua metode privat sederhana untuk mengenkripsi dan mendekripsi data sensitif. Kami akan menulis data ke file dan membacanya dari file dalam bentuk terenkripsi. Data lainnya akan ditulis dan dibaca apa adanya :) Hasilnya, kelas kita terlihat seperti ini:
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Base64;

public class UserInfo implements Externalizable {

   private String firstName;
   private String lastName;
   private String superSecretInformation;

   private static final long serialVersionUID = 1L;

   public UserInfo() {
   }

   public UserInfo(String firstName, String lastName, String superSecretInformation) {
       this.firstName = firstName;
       this.lastName = lastName;
       this.superSecretInformation = superSecretInformation;
   }

   @Override
   public void writeExternal(ObjectOutput out) throws IOException {
       out.writeObject(this.getFirstName());
       out.writeObject(this.getLastName());
       out.writeObject(this.encryptString(this.getSuperSecretInformation()));
   }

   @Override
   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
       firstName = (String) in.readObject();
       lastName = (String) in.readObject();
       superSecretInformation = this.decryptString((String) in.readObject());
   }

   private String encryptString(String data) {
       String encryptedData = Base64.getEncoder().encodeToString(data.getBytes());
       System.out.println(encryptedData);
       return encryptedData;
   }

   private String decryptString(String data) {
       String decrypted = new String(Base64.getDecoder().decode(data));
       System.out.println(decrypted);
       return decrypted;
   }

   public String getFirstName() {
       return firstName;
   }

   public String getLastName() {
       return lastName;
   }

   public String getSuperSecretInformation() {
       return superSecretInformation;
   }
}
Kami menerapkan dua metode yang menggunakan parameter yang sama ObjectOutputdan ObjectInputyang sudah kami temui di pelajaran tentang Serializable. Pada saat yang tepat, kami mengenkripsi atau mendekripsi data yang diperlukan, dan kami menggunakan data terenkripsi untuk membuat serial objek kami. Mari kita lihat bagaimana tampilannya dalam praktik:
import java.io.*;

public class Main {

   public static void main(String[] args) throws IOException, ClassNotFoundException {

       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\save.ser");
       ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);

       UserInfo userInfo = new UserInfo("Paul", "Piper", "Paul Piper's passport data");

       objectOutputStream.writeObject(userInfo);

       objectOutputStream.close();

   }
}
Dalam metode encryptString()and decryptString(), kami secara khusus menambahkan keluaran konsol untuk memverifikasi formulir di mana data rahasia akan ditulis dan dibaca. Kode di atas menampilkan baris berikut: SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRh Enkripsi berhasil! Isi lengkap file terlihat seperti ini: ¬н sr UserInfoГ!}ҐџC‚ћ xpt Ivant Ivanovt $SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRhx Sekarang mari kita coba menggunakan logika deserialisasi kita.
public class Main {

   public static void main(String[] args) throws IOException, ClassNotFoundException {

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\save.ser");
       ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);


       UserInfo userInfo = (UserInfo) objectInputStream.readObject();
       System.out.println(userInfo);

       objectInputStream.close();

   }
}
Yah, sepertinya tidak ada yang rumit di sini. Ini harus bekerja! Kami menjalankannya dan mendapatkan... Pengecualian di thread "main" java.io.InvalidClassException: UserInfo; tidak ada konstruktor yang valid Memperkenalkan antarmuka Externalizable - 4 Ups! :( Rupanya, itu tidak begitu mudah! Mekanisme deserialisasi mengeluarkan pengecualian dan menuntut agar kami membuat konstruktor default. Saya bertanya-tanya mengapa. Dengan Serializable, kami berhasil tanpa satu... :/ Di sini kami menemukan nuansa penting lainnya. The perbedaan antara Serializabledan Externalizabletidak hanya terletak pada akses 'perluasan' pemrogram dan kemampuan untuk mengontrol proses secara lebih fleksibel, tetapi juga pada proses itu sendiri. Di atas segalanya, dalam mekanisme deserialisasi .Serializable, memori hanya dialokasikan untuk objek, lalu nilai dibaca dari aliran dan digunakan untuk menyetel bidang objek. Jika kita menggunakan Serializable, konstruktor objek tidak dipanggil! Semua pekerjaan terjadi melalui refleksi (Refleksi API, yang kami sebutkan secara singkat di pelajaran terakhir). Dengan Externalizable, mekanisme deserialization berbeda. Konstruktor default dipanggil terlebih dahulu. Hanya setelah itu metode UserInfoobjek yang dibuat readExternal()dipanggil. Ini bertanggung jawab untuk mengatur bidang objek. Itu sebabnya setiap kelas yang mengimplementasikan Externalizableantarmuka harus memiliki konstruktor default . Mari tambahkan satu ke UserInfokelas kita dan jalankan kembali kodenya:
import java.io.*;

public class Main {

   public static void main(String[] args) throws IOException, ClassNotFoundException {

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\save.ser");
       ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);


       UserInfo userInfo = (UserInfo) objectInputStream.readObject();
       System.out.println(userInfo);

       objectInputStream.close();
   }
}
Keluaran konsol: data paspor Paul Piper UserInfo \ firstName = 'Paul', lastName = 'Piper', superSecretInformation = 'data paspor Paul Piper' } Nah, itu sesuatu yang sama sekali berbeda! Pertama, string yang didekripsi dengan informasi rahasia ditampilkan di konsol. Kemudian objek yang kami pulihkan dari file ditampilkan sebagai string! Jadi kami berhasil menyelesaikan semua masalah :) Topik serialisasi dan deserialisasi tampaknya sederhana, tetapi, seperti yang Anda lihat, pelajarannya panjang. Dan masih banyak lagi yang belum kami bahas! Masih banyak seluk-beluk yang terlibat saat menggunakan masing-masing antarmuka ini. Tetapi untuk menghindari ledakan otak Anda dari informasi baru yang berlebihan, saya akan membuat daftar singkat beberapa poin penting dan memberi Anda tautan ke bacaan tambahan. Jadi, apa lagi yang perlu Anda ketahui? Pertama , selama serialisasi (terlepas dari apakah Anda menggunakan Serializableatau Externalizable), perhatikan staticvariabel. Saat Anda menggunakan Serializable, bidang ini tidak diserialisasi sama sekali (dan, karenanya, nilainya tidak berubah, karena staticbidang adalah milik kelas, bukan objek). Tetapi ketika Anda menggunakanExternalizable, Anda mengontrol sendiri prosesnya, jadi secara teknis Anda dapat membuat cerita bersambung. Namun, kami tidak merekomendasikannya, karena tindakan tersebut kemungkinan besar akan menimbulkan banyak bug yang tidak kentara. Kedua , Anda juga harus memperhatikan variabel dengan finalpengubah. Saat Anda menggunakan Serializable, mereka diserialkan dan dideserialisasi seperti biasa, tetapi saat Anda menggunakan Externalizable, tidak mungkin untuk melakukan deserialisasi finalvariabel ! Alasannya sederhana: semua finalbidang diinisialisasi saat konstruktor default dipanggil — setelah itu, nilainya tidak dapat diubah. Oleh karena itu, untuk membuat serial objek yang memiliki finalkolom, gunakan serialisasi standar yang disediakan oleh Serializable. Ketiga , ketika Anda menggunakan pewarisan, semua kelas turunan mewarisi beberapaExternalizablekelas juga harus memiliki konstruktor default. Berikut ini tautan ke artikel bagus tentang mekanisme serialisasi: Sampai Lain waktu! :)
Komentar
  • Populer
  • Baru
  • Lama
Anda harus login untuk memberikan komentar
Halaman ini belum memiliki komentar