JavaRush /Java блогы /Random-KK /Java тіліндегі сыртқы интерфейс

Java тіліндегі сыртқы интерфейс

Топта жарияланған
Сәлеметсіз бе! Бүгін біз Java нысандарын сериялауға және сериядан шығаруға кіріспемізді жалғастырамыз. Соңғы дәрісте біз Серияланатын маркер интерфейсімен таныстық, оны қолдану мысалдарын қарастырдық, сонымен қатар транзиторлы кілт сөзін пайдаланып сериализация процесін басқаруды үйрендік . Әрине, «процесті басқару» - бұл күшті сөз. Бізде бір кілт сөз, бір нұсқа идентификаторы бар және бұл негізінен. Процесстің қалған бөлігі Java ішінде «қатты сымды» болып табылады және оған кіру мүмкін емес. Ыңғайлылық тұрғысынан бұл, әрине, жақсы. Бірақ бағдарламашы өз жұмысында тек өзінің жайлылығына ғана назар аударуы керек емес пе? :) Басқа факторларды ескеру қажет. Сондықтан, Serializable Java-да сериялау-серияландырудың жалғыз құралы емес. Бүгін біз Externalizable интерфейсімен танысамыз . Бірақ біз оны зерттеуге көшкенге дейін сізде ақылға қонымды сұрақ туындауы мүмкін: бізге басқа құрал не үшін қажет? SerializableМен өз жұмысымды жеңдім, және бүкіл процестің автоматты түрде орындалуы қуанбайды. Біз қарастырған мысалдар да күрделі емес еді. Сонымен, мәміле қандай? Неліктен бірдей тапсырма үшін басқа интерфейс? Өйткені, Serializableоның бірқатар кемшіліктері бар. Олардың кейбірін тізіп көрейік:
  1. Өнімділік. Интерфейстің 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(). Жоғарыда айтқанымыздай, сериялау және сериядан шығару үшін барлық жауапкершілік бағдарламашыға жүктеледі. Дегенмен, енді сіз бұл процесті бақылаудың жоқтығы мәселесін шеше аласыз! Бүкіл процесті тікелей сіз бағдарламалайды, бұл, әрине, әлдеқайда икемді механизмді жасайды. Сонымен қатар, қауіпсіздік мәселесі де шешілді. Көріп отырғаныңыздай, біздің сыныпта өріс бар: шифрсыз сақтауға болмайтын жеке деректер. Енді біз осы шектеуге сәйкес келетін 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және параметрлерді пайдаланатын екі әдісті іске асырдық . Қажетті уақытта біз қажетті деректерді шифрлаймыз немесе шифрын шешеміз және осы пішінде біз оны нысанымызды сериялау үшін пайдаланамыз. Бұл іс жүзінде қалай көрінетінін көрейік: 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 Шифрлау сәтті аяқталды! Файлдың толық мазмұны келесідей: ¬н 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жад жай ғана an object үшін бөлінген, содан кейін оның барлық өрістерін толтыратын ағыннан мәндер оқылады. Егер біз қолдансақ , an object конструкторы шақырылмайды! Барлық жұмыс рефлексия арқылы орындалады (Reflection API, біз оны соңғы бөлімде қысқаша атап өттік. лекция).Жағдайда сериясыздандыру механизмі басқаша болады.Басында әдепкі конструктор шақырылады.Содан кейін ғана an objectінің өрістерін толтыруға жауап беретін құрылған an object әдісіне шақырылады.Яғни . неге интерфейсті жүзеге асыратын кез келген класс әдепкі конструктор болуы керек . Оны сыныпқа қосып , codeты қайта іске қосайық: ExternalizableSerializableSerializableExternalizableUserInforeadExternal()ExternalizableUserInfo
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овтың төлқұжат деректері'} Мүлдем басқа мәселе! Алдымен, құпия деректері бар шифрланған жол консольге шығарылды, содан кейін біздің нысан файлдан жол пішімінде қалпына келтірілді! Осылайша біз барлық мәселелерді сәтті шештік :) Серияландыру және сериядан шығару тақырыбы қарапайым сияқты, бірақ сіз көріп тұрғандай, біздің дәрістеріміз ұзақ болды. Және бұл бәрі емес! Осы интерфейстердің әрқайсысын пайдаланған кезде тағы да көптеген нәзіктіктер бар, бірақ енді сіздің миыңыз жаңа ақпарат көлемінен жарылып кетпеуі үшін мен тағы бірнеше маңызды ойларды қысқаша тізіп, қосымша оқуға сілтемелер беремін. Сонымен, сізге тағы не білу керек? БіріншіденSerializable , сериялау кезінде ( немесе пайдаланғаныңыз маңызды емес Externalizable), айнымалыларға назар аударыңыз static. Пайдаланылған кезде Serializableбұл өрістер мүлдем серияланбайды (және сәйкесінше олардың мәні өзгермейді, өйткені staticөрістер нысанға емес, сыныпқа жатады). Бірақ оны пайдаланған кезде Externalizableсіз процесті өзіңіз басқарасыз, сондықтан техникалық түрде мұны жасауға болады. Бірақ бұл ұсынылмайды, өйткені бұл нәзік қателіктерге толы. Екіншіден , модификаторы бар айнымалыларға да назар аудару керек final. Қолданылған кезде Serializableолар әдеттегідей серияланады және сериядан шығарылады, бірақ пайдаланған кезде айнымалыны Externalizableсериядан шығаруfinal мүмкін емес ! Себебі қарапайым: барлық final-өрістері әдепкі конструктор шақырылғанда инициализацияланады, содан кейін олардың мәнін өзгерту мүмкін емес. Сондықтан, final-өрістері бар нысандарды сериялау үшін арқылы стандартты сериялауды пайдаланыңыз Serializable. Үшіншіден , мұраны пайдаланған кезде, кейбір Externalizableкласстан түсетін барлық мұрагерлік сыныптарда әдепкі конструкторлар болуы керек. Мұнда сериялау механизмдері туралы жақсы мақалаларға сілтемелер берілген: Кездескенше! :)
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION