JavaRush /Java blogi /Random-UZ /Java-da tashqi interfeys

Java-da tashqi interfeys

Guruhda nashr etilgan
Salom! Bugun biz Java ob'ektlarini ketma-ketlashtirish va seriyadan chiqarishga kirishimizni davom ettiramiz. Oxirgi ma'ruzada biz Serializable marker interfeysi bilan tanishdik, undan foydalanish misollarini ko'rib chiqdik, shuningdek, transient kalit so'zi yordamida serializatsiya jarayonini boshqarishni o'rgandik . Xo'sh, "jarayonni boshqarish", albatta, kuchli so'z. Bizda bitta kalit so'z, bitta versiya identifikatori bor va bu asosan. Jarayonning qolgan qismi Java ichida "qattiq simli" bo'lib, unga kirish imkoni yo'q. Qulaylik nuqtai nazaridan, bu, albatta, yaxshi. Ammo dasturchi o'z ishida nafaqat o'zining qulayligiga e'tibor qaratishi kerak, to'g'rimi? :) Boshqa omillarni hisobga olish kerak. Shuning uchun, Serializable Java-da serializatsiya-deserializatsiya uchun yagona vosita emas. Bugun biz Externalizable interfeysi bilan tanishamiz . Ammo biz uni o'rganishga o'tishimizdan oldin ham sizda mantiqiy savol tug'ilishi mumkin: nega bizga boshqa vosita kerak? SerializableMen o'z ishim bilan shug'ullandim va butun jarayonning avtomatik amalga oshirilishi quvonishdan boshqa narsa emas. Biz ko'rib chiqqan misollar ham murakkab emas edi. Xo‘sh, nima gap? Nega aynan bir xil vazifa uchun boshqa interfeys kerak? Gap shundaki, Serializableuning bir qator kamchiliklari bor. Keling, ulardan ba'zilarini sanab o'tamiz:
  1. Ishlash. Interfeys Serializablejuda ko'p afzalliklarga ega, ammo yuqori ishlash aniq ulardan biri emas.

Tashqi interfeys bilan tanishtirish - 2

Birinchidan , ichki mexanizm Serializableish paytida katta hajmdagi xizmat ma'lumotlarini va har xil turdagi vaqtinchalik ma'lumotlarni yaratadi.
Ikkinchidan (agar siz qiziqsangiz, hozir bunga kirishingiz va bo'sh vaqtingizda o'qishingiz shart emas), ish SerializableReflection API-dan foydalanishga asoslangan. Ushbu qarama-qarshilik Java-da imkonsiz bo'lib tuyuladigan narsalarni qilish imkonini beradi: masalan, shaxsiy maydonlarning qiymatlarini o'zgartirish. JavaRush-da Reflection API haqida ajoyib maqola bor , bu haqda bu yerda o'qishingiz mumkin.

  1. Moslashuvchanlik. dan foydalanganda biz ketma-ketlashtirish-deserializatsiya jarayonini umuman nazorat qilmaymiz Serializable.

    Bir tomondan, bu juda qulay, chunki agar biz ishlashga ahamiyat bermasak, kodni yozmaslik qobiliyati qulay ko'rinadi. Ammo, agar biz serializatsiya mantig'iga haqiqatan ham o'zimizning ba'zi xususiyatlarimizni (ulardan birining misoli quyida keltirilgan) qo'shishimiz kerak bo'lsa-chi?

    Aslini olganda, jarayonni nazorat qilishimiz kerak bo'lgan narsa - bu transientba'zi ma'lumotlarni chiqarib tashlash uchun kalit so'z, va bu ham. "Asboblar to'plami" kabi: /

  2. Xavfsizlik. Bu nuqta qisman avvalgisidan kelib chiqadi.

    Biz ilgari bu haqda ko'p o'ylamaganmiz, lekin sizning sinfingizdagi ba'zi ma'lumotlar "boshqa odamlarning quloqlari" (aniqrog'i, ko'zlar) uchun mo'ljallanmagan bo'lsa-chi? Oddiy misol - parol yoki foydalanuvchining boshqa shaxsiy ma'lumotlari, zamonaviy dunyoda bir qator qonunlar bilan tartibga solinadi.

    dan foydalanib Serializable, biz bu haqda hech narsa qila olmaymiz. Biz hamma narsani avvalgidek seriyalashtiramiz.

    Ammo, yaxshi ma'noda, biz faylga yozish yoki tarmoq orqali uzatishdan oldin bunday turdagi ma'lumotlarni shifrlashimiz kerak. Ammo Serializablebu imkoniyatni bermaydi.

Tashqi interfeys bilan tanishtirish - 3Keling, nihoyat 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;

   //...конструктор, геттеры, сеттеры, toString()...

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

   }

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

   }
}
Ko'rib turganingizdek, biz jiddiy o'zgarishlar qildik! Asosiysi aniq: interfeysni amalga oshirishda Externalizablesiz ikkita majburiy usulni qo'llashingiz kerak - writeExternal()va readExternal(). Yuqorida aytib o'tganimizdek, ketma-ketlashtirish va seriyadan chiqarish uchun barcha javobgarlik dasturchiga yuklanadi. Biroq, endi siz ushbu jarayonni nazorat qilmaslik muammosini hal qilishingiz mumkin! Butun jarayon to'g'ridan-to'g'ri siz tomonidan dasturlashtirilgan, bu, albatta, ancha moslashuvchan mexanizmni yaratadi. Bundan tashqari, xavfsizlik muammosi ham hal qilinadi. Ko'rib turganingizdek, bizning sinfimizda bir soha mavjud: shaxsiy ma'lumotlar shifrlanmagan holda saqlanishi mumkin emas. Endi biz ushbu cheklovga javob beradigan kodni osongina yozishimiz mumkin. Misol uchun, maxfiy ma'lumotlarni shifrlash va parolini ochish uchun sinfimizga ikkita oddiy shaxsiy usulni qo'shing. Biz ularni faylga yozamiz va shifrlangan shaklda fayldan o'qiymiz. Qolgan ma'lumotlarni esa shunday yozamiz va o'qiymiz :) Natijada bizning sinfimiz shunday ko'rinishga ega bo'ladi:
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;
   }
}
ObjectOutput outBiz bir xil va parametrlardan foydalanadigan ikkita usulni amalga oshirdik, ObjectInputular haqida ma'ruzada allaqachon duch kelganmiz Serializable. Kerakli vaqtda biz kerakli ma'lumotlarni shifrlaymiz yoki shifrini hal qilamiz va bu shaklda biz ob'ektimizni ketma-ketlashtirish uchun foydalanamiz. Keling, bu amalda qanday ko'rinishini ko'rib chiqaylik:
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("Ivan", "Ivanov", "Ivan Ivanov's passport data");

       objectOutputStream.writeObject(userInfo);

       objectOutputStream.close();

   }
}
encryptString()va usullarida decryptString()biz maxfiy ma'lumotlar qanday shaklda yozilishi va o'qilishini tekshirish uchun konsolga chiqishni qo'shdik. Yuqoridagi kod konsolga quyidagi qatorni chiqaradi: SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRh shifrlash muvaffaqiyatli bo'ldi! Faylning to'liq mazmuni quyidagicha ko'rinadi: ¬n sr UserInfoG!}HĐџC‚ћ xpt Ivant Ivanovt $SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRhx Endi biz yozgan seriyani bekor qilish mantiqidan foydalanishga harakat qilaylik.
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();

   }
}
Xo'sh, bu erda hech qanday murakkab narsa yo'qdek tuyuladi, u ishlashi kerak! Ishlaylik... "asosiy" mavzudagi istisno java.io.InvalidClassException: UserInfo; yaroqli konstruktor yo'q Tashqi interfeys bilan tanishtirish - 4 Oops :( Bu unchalik oddiy emas ekan! Seriyadan chiqarish mexanizmi istisno qildi va bizdan standart konstruktor yaratishni talab qildi. Qiziq, nega? SerializableBiz usiz ham uddaladik... :/ Mana yana bir muhim nuancega keldik. SerializableO'rtasidagi farq Externalizablenafaqat dasturchi uchun "kengaytirilgan" kirish va jarayonni yanada moslashuvchan boshqarish qobiliyatida, balki jarayonning o'zida hamdir.Birinchi navbatda, seriyani yo'qotish mexanizmida ... Foydalanilganda, Serializablexotira oddiygina. ob'ekt uchun ajratilgan, shundan so'ng uning barcha maydonlarini to'ldiradigan oqimdan qiymatlar o'qiladi. Agar biz dan foydalansak Serializable, ob'ekt konstruktori chaqirilmaydi! Barcha ishlar aks ettirish orqali amalga oshiriladi (Reflection API, biz oxirgi qismida qisqacha aytib o'tgandik. ma'ruza).. bo'lsa, Externalizabledeserializatsiya mexanizmi boshqacha bo'ladi. Boshida standart konstruktor chaqiriladi. Va shundan keyingina ob'ekt maydonlarini to'ldirish uchun mas'ul bo'lgan UserInfoyaratilgan ob'ekt usuli chaqiriladi . Ya'ni. readExternal()nima uchun interfeysni amalga oshiradigan har qanday sinf Externalizablestandart konstruktorga ega bo'lishi kerak . Keling, uni sinfimizga qo'shamiz UserInfova kodni qayta ishga tushiramiz:
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();
   }
}
Konsol chiqishi: Ivan Ivanovning pasport ma'lumotlari UserInfo{firstName='Ivan', lastName='Ivanov', superSecretInformation='Ivan Ivanovning pasport ma'lumotlari'} Butunlay boshqa masala! Birinchidan, maxfiy ma'lumotlarga ega shifrlangan satr konsolga chiqarildi va keyin bizning ob'ektimiz fayldan string formatida tiklandi! Shunday qilib, biz barcha muammolarni muvaffaqiyatli hal qildik :) Seriyalashtirish va seriyadan chiqarish mavzusi oddiy ko'rinadi, lekin ko'rib turganingizdek, bizning ma'ruzalarimiz uzoq bo'lib chiqdi. Va bu hammasi emas! Ushbu interfeyslarning har birini ishlatishda yana ko'p nozikliklar mavjud, ammo endi sizning miyangiz yangi ma'lumotlar hajmidan portlamasligi uchun men yana bir nechta muhim fikrlarni qisqacha sanab o'taman va qo'shimcha o'qish uchun havolalar beraman. Xo'sh, yana nimani bilishingiz kerak? Birinchidan , ketma-ketlashtirishda (foydalanasizmi Serializableyoki farqi yo'q Externalizable), o'zgaruvchilarga e'tibor bering static. Foydalanilganda, Serializablebu maydonlar umuman seriyalashtirilmaydi (va shunga mos ravishda ularning qiymati o'zgarmaydi, chunki staticmaydonlar ob'ektga emas, balki sinfga tegishli). Ammo uni ishlatganda, Externalizablejarayonni o'zingiz nazorat qilasiz, shuning uchun texnik jihatdan buni amalga oshirish mumkin. Ammo bu tavsiya etilmaydi, chunki bu nozik xatolar bilan to'la. Ikkinchidan , modifikatorli o'zgaruvchilarga ham e'tibor qaratish lozim final. Foydalanilganda Serializableular odatdagidek ketma-ketlashtiriladi va seriyadan chiqariladi, lekin foydalanilganda o'zgaruvchini Externalizableseriyadan chiqarishfinal mumkin emas ! Sababi oddiy: finalstandart konstruktor chaqirilganda barcha maydonlar ishga tushiriladi va shundan keyin ularning qiymatini o'zgartirib bo'lmaydi. Shuning uchun, -maydonlarni o'z ichiga olgan ob'ektlarni ketma-ketlashtirish uchun finalorqali standart ketma-ketlashtirishdan foydalaning Serializable. Uchinchidan , merosdan foydalanganda, ba'zi bir Externalizablesinfdan kelib chiqadigan barcha irsiy sinflar standart konstruktorlarga ega bo'lishi kerak. Serializatsiya mexanizmlari haqida yaxshi maqolalarga havolalar: Ko'rishguncha! :)
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION