JavaRush /Java блогу /Random-KY /Javaдагы тышкы интерфейс

Javaдагы тышкы интерфейс

Группада жарыяланган
Салам! Бүгүн биз Java an objectтерин сериялаштыруу жана сериядан чыгаруу боюнча киришүүнү улантабыз. Акыркы лекцияда биз Serializable маркер интерфейси менен тааныштык, аны колдонуунун мисалдарын карап чыктык, ошондой эле transient ачкыч сөзү менен сериялаштыруу процессин башкарууну үйрөндүк . Ооба, "процессти башкаруу", албетте, күчтүү сөз. Бизде бир ачкыч сөз, бир version ID бар жана бул негизинен. Калган процесс Java ичинде "катуу жабдылган" жана ага кирүү мүмкүнчүлүгү жок. Ыңгайлуу көз караштан алганда, бул, албетте, жакшы. Бирок программист өз ишинде өзүнүн ыңгайлуулугуна гана көңүл буруш керек, туурабы? :) Башка факторлорду эске алуу керек. Ошондуктан, Serializable Java'да сериялаштыруу-десериялаштыруу үчүн жалгыз курал эмес. Бүгүн биз Externalizable интерфейси менен таанышабыз . Бирок, биз аны изилдөөгө өткөнгө чейин, сизде жөндүү суроо пайда болушу мүмкүн: эмне үчүн бизге башка курал керек? SerializableМен өзүмдүн жумушумду аткардым жана бүт процесстин автоматтык түрдө ишке ашырылышы кубанбай койбойт. Биз карап чыккан мисалдар да татаал эмес болчу. Анда эмне болгон? Эмне үчүн бир эле тапшырма үчүн башка интерфейс керек? SerializableАнын бир катар кемчorктери бар экендиги чындык . Алардын айрымдарын санап көрөлү:
  1. Performance. Интерфейстин Serializableкөптөгөн артыкчылыктары бар, бирок жогорку аткаруу алардын бири эмес.

Тышкы интерфейсти киргизүү - 2

Биринчиден , ички механизм Serializableиш учурунда кызматтык маалыматтын жана ар кандай түрдөгү убактылуу маалыматтардын чоң көлөмүн түзөт.
Экинчиден (эгер сизди кызыктырса, азыр ага кирип, бош убактыңызда окуунун кереги жок), иш SerializableReflection API колдонууга негизделген. Бул карама-каршылык Javaда мүмкүн эместей көрүнгөн нерселерди кылууга мүмкүндүк берет: мисалы, жеке талаалардын баалуулуктарын өзгөртүү. JavaRush Reflection API жөнүндө эң сонун макалага ээ , сиз бул тууралуу окуй аласыз.

  1. ийкемдүүлүк. Колдонууда сериялаштыруу-десериялаштыруу процессин такыр көзөмөлдөбөйбүз Serializable.

    Бир жагынан алганда, бул абдан ыңгайлуу, анткени биз аткарууга чындап маани бербесек, codeду жазбай коюу ыңгайлуу көрүнөт. Бирок сериялаштыруу логикасына чындап эле өзүбүздүн айрым өзгөчөлүктөрүбүздү (алардын биринин мисалы төмөндө болот) кошуу керек болсочу?

    Негизинен, процессти көзөмөлдөөбүз керек болгон нерсе - бул transientкээ бир маалыматтарды алып салуу үчүн ачкыч сөз, жана бүттү. "Инструменттер топтому" сыяктуу: /

  2. Коопсуздук. Бул пункт жарым-жартылай мурункусунан келип чыгат.

    Биз буга чейин бул тууралуу көп ойлонгон эмеспиз, бирок сиздин классыңыздагы кээ бир маалымат "башкалардын кулактарына" (тагыраак айтканда, көзгө) арналбасачы? Жөнөкөй мисал - заманбап дүйнөдө бир топ мыйзамдар менен жөнгө салынган сырсөз же башка жеке колдонуучу маалыматтар.

    Колдонуу Serializable, биз бул жөнүндө эч нерсе кыла албайбыз. Биз бардыгын кандай болсо, ошондой сериялайбыз.

    Бирок, жакшы жагынан алганда, биз бул маалыматтарды файлга жазуудан же тармак аркылуу өткөрүүдөн мурун шифрлешибиз керек. Бирок Serializableбул мүмкүнчүлүк бербейт.

Тышкы интерфейсти киргизүү - 3Келгиле, акыры класстын 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 {

   }
}
Көрүнүп тургандай, биз олуттуу өзгөртүүлөрдү киргиздик! Эң негизгиси көрүнүп турат: интерфейсти ишке ашырууда Externalizableэки милдеттүү ыкманы ишке ашыруу керек - writeExternal()жана readExternal(). Мурда айткандай, сериалдаштыруу жана сериялаштыруу үчүн бардык жоопкерчorк программистке жүктөлөт. Бирок, азыр бул процесске контролдуктун жоктугун чечсе болот! Бүт процесс түздөн-түз сиз тарабынан программаланган, бул, албетте, бир топ ийкемдүү механизмди түзөт. Мындан тышкары, коопсуздук маселеси да чечилди. Көрүнүп тургандай, биздин класста бир талаа бар: шифрлөөсүз сакталган жеке маалыматтар. Эми биз бул чектөөгө жооп берген codeду оңой жаза алабыз. Мисалы, жашыруун маалыматтарды шифрлөө жана чечмелөө үчүн биздин класска эки жөнөкөй жеке ыкманы кошуңуз. Биз аларды файлга жазып, шифрленген түрдө файлдан окуйбуз. Ал эми калган маалыматтарды ошол бойдон жазабыз жана окуйбуз :) Натыйжада, биздин класс төмөнкүдөй болот:
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 outжана параметрлерди колдонгон эки ыкманы ишке ашырдык . Керектүү учурда биз керектүү маалыматтарды шифрлейбиз же чечмелейбиз жана бул формада биз аны an objectибизди сериялаштыруу үчүн колдонобуз. Келгиле, бул иш жүзүндө кандай болорун карап көрөлү: ObjectInputSerializable
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()жана методдорунда decryptString()биз жашыруун маалыматтар кандай формада жазылып жана окула турганын текшерүү үчүн консолго атайын чыгардык. Жогорудагы code консолго төмөнкү сапты чыгарат: SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRh Шифрлөө ийгorктүү болду! Файлдын толук мазмуну төмөнкүдөй көрүнөт: ¬н sr UserInfoГ!}ҐџC‚ћ xpt Ivant Ivanovt $SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRhx Эми биз жазган сериядан чыгаруу логикасын колдонууга аракет кылалы.
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();

   }
}
Ооба, бул жерде татаал эч нерсе жок окшойт, иштеши керек! Иштейли... "main" жипиндеги өзгөчө жагдай java.io.InvalidClassException: UserInfo; жарактуу конструктор жок Тышкы интерфейсти киргизүү - 4 Ой :( Бул анчалык деле жөнөкөй эмес болуп чыкты! Сериялаштыруу механизми өзгөчө кырдаалды жаратып, бизден демейки конструкторду түзүүнү талап кылды. Кызык, эмнеге? SerializableБиз ансыз да жетиштик... :/ Бул жерде биз дагы бир маанилүү нюанска келдик. SerializableАлардын ортосундагы айырмачылык Externalizableпрограммалоочу үчүн “кеңейтилген” жеткorктүүлүктө жана процессти ийкемдүү башкаруу мүмкүнчүлүгүнөн гана эмес, процесстин өзүндө да.Биринчиден, сериядан чыгаруу механизминде ... Колдонулганда, Serializableэс жөн эле an object үчүн бөлүнгөн, андан кийин анын бардык талааларын толтурган агымдан баалуулуктар окулат. Эгерде биз колдонсок Serializable, an objectтин конструктору чакырылbyte! Бардык иштер чагылдыруу аркылуу аткарылат (Reflection API, биз акыркы бөлүмдө кыскача айтып өткөнбүз. лекция).Жагдайда Externalizableсериядан чыгаруу механизми башкача болот. Башында демейки конструктор чакырылат. Ошондон кийин гана an objectтин талааларын толтуруу үчүн жооп берген UserInfoтүзүлгөн an object ыкмасына чакырылат . Башкача айтканда. readExternal()эмне үчүн интерфейсти ишке ашырган класстын Externalizableдемейки конструктору болушу керек . Аны классыбызга кошуп UserInfo, codeду кайра иштетели:
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();
   }
}
Консолдун чыгышы: Ivan Ivanовдун паспорттук маалыматтары UserInfo{firstName='Ivan', lastName='Ivanov', superSecretInformation='Ivan Ivanовдун паспорттук маалыматтары'} Такыр башка маселе! Биринчиден, жашыруун маалыматтар менен шифрленген сап консолго чыгарылды, андан кийин биздин an object файлдан сап форматында калыбына келтирилди! Мына ушинтип биз бардык көйгөйлөрдү ийгorктүү чечтик :) Сериялаштыруу жана сериялаштыруу темасы жөнөкөй көрүнөт, бирок өзүңүздөр көрүп тургандай, биздин лекциялар узак болуп чыкты. Жана бул баары эмес! Бул интерфейстердин ар бирин колдонууда дагы көптөгөн кылдаттыктар бар, бирок азыр сиздин мээңиз жаңы маалыматтын көлөмүнөн жарылбашы үчүн, мен дагы бир нече маанилүү ойлорду кыскача тизмелеп, кошумча окууга шилтеме берем. Демек, дагы эмнени бorшиңиз керек? БиринчиденSerializable , сериялаштырууда ( колдонгонуңуз маанилүү эмес Externalizable), өзгөрмөлөргө көңүл буруңуз static. Колдонулганда Serializableбул талаалар такыр серияланbyte (жана, ошого жараша алардын мааниси өзгөрбөйт, анткени staticталаалар an objectке эмес, класска таандык). Бирок аны колдонууда Externalizableпроцессти өзүңүз башкарасыз, андыктан техникалык жактан муну жасоого болот. Бирок бул сунушталbyte, анткени бул тымызын каталар менен коштолот. Экинчиден , модификатору бар өзгөрмөлөргө да көңүл буруу керек final. Колдонулганда, Serializableалар адаттагыдай сериялаштырылат жана сериядан ажыратылат, бирок колдонулганда, өзгөрмөнүн Externalizableсериясын жок кылууfinal мүмкүн эмес ! Себеби жөнөкөй: finalдемейки конструктор чакырылганда бардык талаалар инициализацияланат жана андан кийин алардын маанисин өзгөртүүгө болбойт. Ошондуктан, final-талааларды камтыган an objectтерди сериялаштыруу үчүн, аркылуу стандарттуу сериялаштыруу колдонуңуз Serializable. Үчүнчүдөн , мурасты колдонууда, кандайдыр бир Externalizableкласстан келип чыккан бардык тукум кууруучу класстарда демейки конструкторлор да болушу керек. Бул жерде сериалдаштыруу механизмдери жөнүндө жакшы макалаларга шилтемелер бар: Көрүшкөнчө! :)
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION