CodeGym/Java Blog/Random/Externalizable na interface sa Java
John Squirrels
Antas
San Francisco

Externalizable na interface sa Java

Nai-publish sa grupo
Hi! Ngayon, patuloy nating malalaman ang serialization at deserialization ng mga object ng Java. Sa huling aralin, nalaman namin ang interface ng Serializable marker, sinuri ang mga halimbawa ng paggamit nito, at natutunan din kung paano mo magagamit ang lumilipas na keyword upang kontrolin ang proseso ng serialization. Buweno, ang pagsasabi na 'kontrolin natin ang proseso' ay maaaring labis itong nasasabik. Mayroon kaming isang keyword, isang identifier ng bersyon, at tungkol doon. Ang natitirang bahagi ng proseso ay nakatago sa loob ng Java, at hindi namin ito ma-access. Siyempre, sa mga tuntunin ng kaginhawaan, ito ay mabuti. Ngunit ang isang programmer ay hindi lamang dapat magabayan ng kanyang sariling kaginhawahan, tama ba? :) Mayroong iba pang mga kadahilanan na kailangan mong isaalang-alang. Kaya naman Serializableay hindi lamang ang mekanismo para sa serialization-deserialization sa Java. Ngayon ay makikilala natin ang Externalizable na interface. Ngunit bago natin simulan ang pag-aaral nito, maaari kang magkaroon ng isang makatwirang tanong: bakit kailangan natin ng isa pang mekanismo? Serializableginawa ang trabaho nito, at ano ang hindi dapat mahalin tungkol sa awtomatikong pagpapatupad ng buong proseso? At ang mga halimbawa na aming tiningnan ay hindi rin kumplikado. So anong problema? Bakit kailangan natin ng isa pang interface para sa parehong mga gawain? Ang katotohanan ay Serializablemayroon itong ilang mga pagkukulang. Inilista namin ang ilan sa kanila:
  1. Pagganap. Ang Serializableinterface ay may maraming mga pakinabang, ngunit ang mataas na pagganap ay malinaw na hindi isa sa kanila.

    Ipinapakilala ang Externalizable na interface - 2

    Una, Serializable ang panloob na pagpapatupad ay bumubuo ng isang malaking halaga ng impormasyon ng serbisyo at lahat ng uri ng pansamantalang data.

    Pangalawa, Serializable umaasa sa Reflection API (hindi mo na kailangang sumisid ng malalim sa ngayon; maaari kang magbasa nang higit pa sa iyong paglilibang, kung interesado ka). Hinahayaan ka ng bagay na ito na gawin ang mga tila imposibleng bagay sa Java: halimbawa, baguhin ang mga halaga ng mga pribadong field. Ang CodeGym ay may mahusay na artikulo tungkol sa Reflection API . Maaari mong basahin ang tungkol dito.

  2. Kakayahang umangkop. Hindi namin kinokontrol ang proseso ng serialization-deserialization kapag ginamit namin ang Serializableinterface.

    Sa isang banda, ito ay napaka-maginhawa, dahil kung hindi tayo partikular na nag-aalala tungkol sa pagganap, kung gayon mukhang maganda na hindi kailangang magsulat ng code. Ngunit paano kung kailangan talaga naming magdagdag ng ilan sa aming sariling mga tampok (magbibigay kami ng isang halimbawa sa ibaba) sa serialization logic?

    Karaniwan, ang kailangan lang nating kontrolin ang proseso ay ang transientkeyword upang ibukod ang ilang data. Ayan yun. Iyan ang aming buong toolbox :/

  3. Seguridad. Ang item na ito ay nakukuha sa bahagi mula sa nakaraang item.

    Wala pa kaming gaanong oras sa pag-iisip tungkol dito, ngunit paano kung ang ilang impormasyon sa iyong klase ay hindi para sa mga mata at tainga ng iba? Ang isang simpleng halimbawa ay isang password o iba pang personal na data ng user, na sa mundo ngayon ay pinamamahalaan ng isang grupo ng mga batas.

    Kung gagamitin natin Serializable, wala talaga tayong magagawa tungkol dito. I-serialize namin ang lahat nang ganito.

    Ngunit kung gagawin natin ito sa tamang paraan, dapat nating i-encrypt ang ganitong uri ng data bago ito isulat sa isang file o ipadala ito sa isang network. Ngunit Serializablehindi ito ginagawang posible.

Ipinapakilala ang Externalizable na interface - 3Well, tingnan natin kung ano ang magiging hitsura ng klase kung gagamitin natin ang Externalizableinterface.
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 {

   }
}
Tulad ng nakikita mo, mayroon kaming mga makabuluhang pagbabago! Ang pangunahing isa ay halata: kapag nagpapatupad ng Externalizableinterface, dapat mong ipatupad ang dalawang kinakailangang pamamaraan: writeExternal()atreadExternal(). Gaya ng sinabi namin kanina, ang responsibilidad para sa serialization at deserialization ay nasa programmer. Ngunit ngayon maaari mong malutas ang problema ng walang kontrol sa proseso! Ang buong proseso ay direktang na-program mo. Naturally, pinapayagan nito ang isang mas nababaluktot na mekanismo. Bukod pa rito, nalutas ang problema sa seguridad. Gaya ng nakikita mo, ang aming klase ay may personal na field ng data na hindi maiimbak nang hindi naka-encrypt. Ngayon ay madali na tayong makakasulat ng code na nakakatugon sa hadlang na ito. Halimbawa, maaari kaming magdagdag sa aming klase ng dalawang simpleng pribadong pamamaraan upang i-encrypt at i-decrypt ang sensitibong data. Isusulat namin ang data sa file at babasahin ito mula sa file sa naka-encrypt na form. Ang natitirang data ay isusulat at babasahin kung ano ito :) Bilang resulta, ganito ang hitsura ng aming klase:
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;
   }
}
Ipinatupad namin ang dalawang pamamaraan na gumagamit ng pareho ObjectOutputat ObjectInputmga parameter na nakilala na namin sa aralin tungkol sa Serializable. Sa tamang sandali, ine-encrypt o i-decrypt namin ang kinakailangang data, at ginagamit namin ang naka-encrypt na data para i-serialize ang aming object. Tingnan natin kung ano ang hitsura nito sa pagsasanay:
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();

   }
}
Sa encryptString()at decryptString()mga pamamaraan, partikular kaming nagdagdag ng console output upang i-verify ang form kung saan isusulat at babasahin ang lihim na data. Ang code sa itaas ay nagpakita ng sumusunod na linya: SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRh Nagtagumpay ang pag-encrypt! Ang buong nilalaman ng file ay ganito ang hitsura: ¬н sr UserInfoГ!}ҐџC‚ћ xpt Ivant Ivanovt $SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRhx Ngayon ay subukan nating gamitin ang aming deserialization logic.
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();

   }
}
Well, mukhang walang kumplikado dito. Dapat itong gumana! Pinapatakbo namin ito at nakakuha ng... Exception sa thread na "main" java.io.InvalidClassException: UserInfo; walang wastong constructor Ipinapakilala ang Externalizable na interface - 4 Oops! :( Tila, hindi ito ganoon kadali! Ang mekanismo ng deserialization ay nagbigay ng eksepsiyon at hiniling na lumikha kami ng isang default na tagabuo. Nagtataka ako kung bakit. Sa pamamagitan ng , Serializablenalampasan namin nang walang isa... :/ Dito ay nakatagpo kami ng isa pang mahalagang nuance. Ang ang pagkakaiba sa pagitan ng Serializableat Externalizablenamamalagi hindi lamang sa 'pinalawak' na pag-access ng programmer at ang kakayahang mas madaling makontrol ang proseso, kundi pati na rin sa proseso mismo. Higit sa lahat, sa mekanismo ng deserialization . Kapag gumagamitSerializable, ang memorya ay inilalaan lamang para sa object, at pagkatapos ay binabasa ang mga value mula sa stream at ginagamit upang itakda ang mga field ng object. Kung gagamitin natin ang Serializable, hindi tinatawag ang constructor ng object! Ang lahat ng gawain ay nangyayari sa pamamagitan ng pagmuni-muni (ang Reflection API, na maikling binanggit namin sa huling aralin). Sa Externalizable, iba ang mekanismo ng deserialization. Ang default na tagabuo ay unang tinawag. Pagkatapos lamang nito ay tinawag ang pamamaraan UserInfong nilikha na bagay readExternal(). Ito ay responsable para sa pagtatakda ng mga patlang ng bagay. Iyon ang dahilan kung bakit ang anumang klase na nagpapatupad ng Externalizableinterface ay dapat na may default na tagabuo . Magdagdag tayo ng isa sa aming UserInfoklase at muling patakbuhin ang 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();
   }
}
Output ng console: Data ng pasaporte ni Paul Piper UserInfo \ firstName = 'Paul', lastName = 'Piper', superSecretInformation = 'data ng pasaporte ni Paul Piper' } Ngayon ay isang bagay na ganap na naiiba! Una, ang na-decrypt na string na may lihim na impormasyon ay ipinakita sa console. Pagkatapos ang bagay na nakuha namin mula sa file ay ipinakita bilang isang string! Kaya't matagumpay naming nalutas ang lahat ng mga problema :) Ang paksa ng serialization at deserialization ay tila simple, ngunit, tulad ng nakikita mo, ang mga aralin ay mahaba. At marami pa tayong hindi natalakay! Mayroon pa ring maraming mga subtleties na kasangkot kapag ginagamit ang bawat isa sa mga interface na ito. Ngunit upang maiwasang sumabog ang iyong utak mula sa labis na bagong impormasyon, maikli kong ilista ang ilang mas mahahalagang punto at bibigyan ka ng mga link sa karagdagang pagbabasa. Kaya, ano pa ang kailangan mong malaman? Una , sa panahon ng serialization (hindi alintana kung gumagamit ka man Serializableo Externalizable), bigyang pansin ang staticmga variable. Kapag ginamit mo ang Serializable, ang mga patlang na ito ay hindi naka-serialize sa lahat (at, nang naaayon, ang kanilang mga halaga ay hindi nagbabago, dahil ang staticmga patlang ay kabilang sa klase, hindi ang bagay). Pero kapag ginamit moExternalizable, ikaw mismo ang kumokontrol sa proseso, kaya sa teknikal na paraan maaari mong i-serialize ang mga ito. Ngunit, hindi namin ito inirerekomenda, dahil ang paggawa ay malamang na lumikha ng maraming banayad na mga bug. Pangalawa , dapat mo ring bigyang pansin ang mga variable na may finalmodifier. Kapag ginamit mo ang Serializable, ang mga ito ay serialized at deserialized gaya ng dati, ngunit kapag ginamit mo ang Externalizable, imposibleng deserialize ang isang finalvariable ! Ang dahilan ay simple: ang lahat finalng mga patlang ay sinisimulan kapag ang default na tagabuo ay tinawag - pagkatapos nito, ang kanilang halaga ay hindi na mababago. Samakatuwid, upang i-serialize ang mga bagay na may finalmga field, gamitin ang karaniwang serialization na ibinigay ng Serializable. Pangatlo , kapag gumamit ka ng inheritance, lahat ng descendant classes na nagmamana ng ilanExternalizableang klase ay dapat ding may mga default na konstruktor. Narito ang link sa magandang artikulo tungkol sa mga mekanismo ng serialization: Hanggang sa muli! :)
Mga komento
  • Sikat
  • Bago
  • Luma
Dapat kang naka-sign in upang mag-iwan ng komento
Wala pang komento ang page na ito