JavaRush /Java blogi /Random-UZ /Java-da seriyalilashtirish va seriyadan chiqarish

Java-da seriyalilashtirish va seriyadan chiqarish

Guruhda nashr etilgan
Salom! Bugungi ma'ruzamizda Java'da serializatsiya va deserializatsiya haqida gapiramiz. Oddiy misol bilan boshlaylik. Aytaylik, siz kompyuter o'yinining yaratuvchisisiz. Agar siz 90-yillarda o'sgan bo'lsangiz va o'sha davrlardagi o'yin pristavkalarini eslayotgan bo'lsangiz, ehtimol siz ularga bugungi kunda aniq bir narsa etishmayotganini bilasiz - o'yinlarni saqlash va yuklash :) Agar bo'lmasa ... tasavvur qiling! Bugun bunday imkoniyatsiz o'yin muvaffaqiyatsizlikka mahkum bo'lishidan qo'rqaman! Va, aslida, o'yinni "saqlash" va "yuklash" nima? Xo'sh, odatiy ma'noda, biz nima ekanligini tushunamiz: biz o'yinni o'tgan safar to'xtatgan joydan davom ettirmoqchimiz. Buning uchun biz "nazorat nuqtasi" ni yaratamiz, undan keyin o'yinni yuklash uchun foydalanamiz. Lekin bu kundalik ma'noda emas, balki "dasturchi" ma'nosida nimani anglatadi? Javob oddiy: biz dasturimizning holatini saqlaymiz. Aytaylik, siz Ispaniya uchun strategiya o'yinini o'ynayapsiz. Sizning o'yiningiz davlatga ega: kim qanday hududlarga ega, kim qancha resurslarga ega, kim kim bilan ittifoqda va kim, aksincha, urushda va hokazo. Ushbu ma'lumot, dasturimizning holati, keyinchalik ma'lumotlarni qayta tiklash va o'yinni davom ettirish uchun qandaydir tarzda saqlanishi kerak. Aynan shu maqsadda ketma-ketlashtirish va seriyadan chiqarish mexanizmlaridan foydalaniladi . Seriyalashtirish - ob'ekt holatini baytlar ketma-ketligiga saqlash jarayoni. Deserializatsiya - bu baytlardan ob'ektni qayta tiklash jarayoni. Har qanday Java obyekti baytlar ketma-ketligiga aylantiriladi. Bu nima uchun? Dasturlar o'z-o'zidan mavjud emasligini bir necha bor aytdik. Ko'pincha ular bir-biri bilan o'zaro aloqada bo'lishadi, ma'lumotlar almashadilar va hokazo. Buning uchun esa bayt formati qulay va samarali. Biz, masalan, sinf ob'ektimizni SavedGame(saqlangan o'yinni) baytlar ketma-ketligiga aylantirishimiz, bu baytlarni tarmoq orqali boshqa kompyuterga o'tkazishimiz va ikkinchi kompyuterda bu baytlarni Java ob'ektiga aylantirishimiz mumkin! Eshitish qiyin, to'g'rimi? Ko'rinishidan, bu jarayonni tashkil qilish oson bo'lmaydi :/ Yaxshiyamki, yo'q! :) Java'da Serializable interfeysi serializatsiya jarayonlari uchun javobgardir . Ushbu interfeys juda oddiy: uni ishlatish uchun bitta usulni qo'llash shart emas! Saqlash o'yin sinfimiz shunday ko'rinadi:
import java.io.Serializable;
import java.util.Arrays;

public class SavedGame implements Serializable {

   private static final long serialVersionUID = 1L;

   private String[] territoriesInfo;
   private String[] resourcesInfo;
   private String[] diplomacyInfo;

   public SavedGame(String[] territoriesInfo, String[] resourcesInfo, String[] diplomacyInfo){
       this.territoriesInfo = territoriesInfo;
       this.resourcesInfo = resourcesInfo;
       this.diplomacyInfo = diplomacyInfo;
   }

   public String[] getTerritoriesInfo() {
       return territoriesInfo;
   }

   public void setTerritoriesInfo(String[] territoriesInfo) {
       this.territoriesInfo = territoriesInfo;
   }

   public String[] getResourcesInfo() {
       return resourcesInfo;
   }

   public void setResourcesInfo(String[] resourcesInfo) {
       this.resourcesInfo = resourcesInfo;
   }

   public String[] getDiplomacyInfo() {
       return diplomacyInfo;
   }

   public void setDiplomacyInfo(String[] diplomacyInfo) {
       this.diplomacyInfo = diplomacyInfo;
   }

   @Override
   public String toString() {
       return "SavedGame{" +
               "territoriesInfo=" + Arrays.toString(territoriesInfo) +
               ", resourcesInfo=" + Arrays.toString(resourcesInfo) +
               ", diplomacyInfo=" + Arrays.toString(diplomacyInfo) +
               '}';
   }
}
Uchta ma'lumotlar to'plami hududlar, iqtisod va diplomatiya haqidagi ma'lumotlar uchun mas'uldir va Serializable interfeysi Java mashinasiga aytadi: " Hammasi yaxshi, agar biror narsa bo'lsa, ushbu sinf ob'ektlarini ketma-ketlashtirish mumkin ." Hech qanday usulga ega bo'lmagan interfeys g'alati ko'rinadi :/ Bu nima uchun kerak? Bu savolga javob yuqorida: faqat Java mashinasiga kerakli ma'lumotlarni taqdim etish uchun. Oldingi ma'ruzalardan birida biz marker interfeyslarini qisqacha aytib o'tgan edik. Bular maxsus ma'lumot beruvchi interfeyslar bo'lib, ular bizning darslarimizni kelajakda Java mashinasi uchun foydali bo'ladigan qo'shimcha ma'lumotlar bilan belgilaydi. Ularda amalga oshirilishi kerak bo'lgan usullar yo'q. Shunday qilib, Serializable shunday interfeyslardan biridir. private static final long serialVersionUIDYana bir muhim nuqta: biz sinfda aniqlagan o'zgaruvchi . Nima uchun kerak? Bu maydon seriyali sinfning noyob versiya identifikatorini o'z ichiga oladi . Serializable interfeysini amalga oshiradigan har qanday sinf versiya identifikatoriga ega. U sinfning mazmuni - maydonlar, deklaratsiya tartibi, usullari asosida hisoblanadi. Va agar biz sinfimizdagi maydon turini va/yoki maydonlar sonini o'zgartirsak, versiya identifikatori bir zumda o'zgaradi. serialVersionUID sinf seriyalashtirilganda ham yoziladi. Seriyadan chiqarishga, ya'ni baytlar to'plamidan ob'ektni tiklashga harakat qilganimizda, qiymat bizning dasturimizdagi sinf serialVersionUIDqiymati bilan taqqoslanadi . serialVersionUIDAgar qiymatlar mos kelmasa, java.io.InvalidClassException tashlanadi. Buning misolini quyida ko'rib chiqamiz. Bunday holatlarning oldini olish uchun biz sinfimiz uchun ushbu versiya identifikatorini qo'lda o'rnatamiz. Bizning holatda, u oddiygina 1 ga teng bo'ladi (siz o'zingiz yoqtirgan boshqa raqamni almashtirishingiz mumkin). SavedGameXo'sh, ob'ektimizni ketma-ketlashtirishga harakat qilish va nima sodir bo'lishini ko'rish vaqti keldi !
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Main {

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

       // create our object
       String[] territoryInfo = {"Spain has 6 provinces", "Russia has 10 provinces", "France has 8 provinces"};
       String[] resourcesInfo = {"Spain has 100 gold", "Russia has 80 gold", "France has 90 gold"};
       String[] diplomacyInfo = {"France is at war with Russia, Spain has taken a position of neutrality"};

       SavedGame savedGame = new SavedGame(territoryInfo, resourcesInfo, diplomacyInfo);

       //create 2 threads to serialize the object and save it to a file
       FileOutputStream outputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\save.ser");
       ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);

       // save game to file
       objectOutputStream.writeObject(savedGame);

       // close the stream and release resources
       objectOutputStream.close();
   }
}
Ko'rib turganingizdek, biz 2 ta mavzu yaratdik - FileOutputStreamva ObjectOutputStream. Ulardan birinchisi faylga ma'lumotlarni yozishi mumkin, ikkinchisi esa ob'ektlarni baytlarga aylantira oladi. Siz allaqachon shunga o'xshash "joylashtirilgan" konstruktsiyalarni ko'rgansiz, masalan, oldingi ma'ruzalarda, shuning uchun ular sizni qo'rqitmasligi kerak :) Ikki ipdan iborat bunday "zanjir" ni yaratish orqali biz ikkala vazifani ham bajaramiz: ob'ektni baytlar to'plamiga new BufferedReader(new InputStreamReader(...))aylantiramiz. SavedGameva usuli yordamida faylga saqlang writeObject(). Aytgancha, biz olgan narsalarni ham tekshirmadik! Faylni ko'rish vaqti keldi! *Izoh: faylni oldindan yaratish shart emas. Agar shunday nomdagi fayl mavjud bo'lmasa, u avtomatik ravishda yaratiladi* Va mana uning mazmuni! ¬n sr SavedGame [ diplomatacyInfot [Ljava/lang/String;[ resurslarInfoq ~ [ territoriesInfoq ~ xpur [Ljava.lang.String;TVzy{G xp t pR¤SЂR°RąS†RIRẑSăR°RąS†RIRẑSăR˃SăRµRăSăRậSăS˃RậSăS˃R˃S˃Rẗ ° RąRyoSď R·R°RSďR»R° Rí̈RẑR·RyoS†RyoSЋ RąRµR№S‚SЂR°R»RyoS‚RµS‚R°uq ~ t "RЈ R˜SЃRIí̈R°RąRyoRyoRẀRyoRyoRẀ0R" RẑSЃSЃRyoRyo 80 R·RẑR»RẑS‚R°t !RĈ R¤SĐR°RąS†RyoRyo 90 R·RẑR»RẑS‚R°uq ~ t &RĐ R˜SЃRíẖRyoRyoRyoRyoRẑ %RẖRyoRyoRẖRẖRyoRyoRẑ %RẖRyoRyoRẐ Ј RẑSăSăRyoRyo 10 RíSĂRẑRIRyoRąS †RyoR№t &RЈ R¤SЂR°RąS†ReRyo 8 RíSЂRẑRIRIRyoRąS†RyoR№ Oops :( Bizning dasturimiz ishlamaganga o'xshaydi :( Aslida, u ishlagan. Esingizda bo'lsa, biz faylga aniq bir qator baytlar va baytlarni o'tkazganmiz. shunchaki ob'ekt yoki matn emasmi? Xo'sh, bu to'plam shunday ko'rinadi :) Bu bizning saqlangan o'yinimiz! Agar biz asl ob'ektimizni tiklamoqchi bo'lsak, ya'ni o'yinni to'xtagan joydan yuklamoqchi va davom ettirmoqchi bo'lsak, bizga teskari jarayon , deserializatsiya ... Bizning holatda u shunday ko'rinadi:
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);

       SavedGame savedGame = (SavedGame) objectInputStream.readObject();

       System.out.println(savedGame);
   }
}
Va bu erda natija! SavedGame{territoriesInfo=[Ispaniyada 6 ta viloyat, Rossiyada 10 ta viloyat, Fransiyada 8 ta viloyat bor], resourcesInfo=[Ispaniyada 100 ta oltin, Rossiyada 80 ta oltin, Frantsiyada 90 ta oltin], diplomatacyInfo=[Frantsiya Rossiya bilan urushda, Ispaniya betaraflik pozitsiyasini egalladi]} Ajoyib! Biz avval o'yinimizning holatini faylga saqlashga muvaffaq bo'ldik va keyin uni fayldan tikladik. Keling, xuddi shunday qilishga harakat qilaylik, lekin SavedGameversiya identifikatorini sinfimizdan olib tashlang. Biz ikkala sinfimizni ham qayta yozmaymiz, ulardagi kod bir xil bo'ladi, shunchaki olib SavedGametashlaymiz private static final long serialVersionUID. Seriyalashdan keyin bizning ob'ektimiz: ¬n sr SavedGameí€MíuOm‰ [ diplomatacyInfot [Ljava/lang/String;[ resourcesInfoq ~ [ territoriesInfoq ~ xpur [Ljava.lang.String;TVzy{G xp t pR¤SеR°RẑSR°RąS‖ ‚ SЃ R RẑSЃSЃRyoRµR№, R˜SЃRí̈R°RąRďR·R°RąSďR»R° RíRẑR·RyoS†RyoSċ RąRµR№S‚SЂR°R»RyoS‚SЂR°R»RyoS‚SЂR°R»RyoS‚SЂR°R»R°S‚R˅t‚Rˈt‚Rˈt‚R˅R˜SЃRí̈R°RďR·R°RąSďR»R° yoRyo 100 R · RẑR»RẑS‚R°t RĈ R RẑSăSăRyoRyo 80 R·RẑR»RẑS‚R°t !RĈ R¤SЂR°RąS†RyoRyo 90 R·RẑR»RẑS‚R°uq ~ t &RăS‚RyoRyo t &RăSąRyo í̈SЂRẑRIRyoRąS† RyoR№t %RĈ R RẑSăSăRyoRyo 10 RíSЂRẑRIRąRyoRąS†RyoR№t &Rđ R¤SЂR°RąS†RyoRyo 8 RẖRyoRąS†RyoRyo 8 RẖRyoRąS†RyoRĐRyo uni seriyalash, shunday bo'ldi: InvalidClassException: mahalliy sinf mos kelmaydi: oqim classdesc serialVersionUID = - 196410440475012755, mahalliy sinf serialVersionUID = -6675950253085108747 Bu yuqorida aytib o'tilgan istisno. Bu haqda o'quvchilarimizdan birining maqolasida batafsil o'qishingiz mumkin.Aytgancha, biz bir muhim nuqtani o'tkazib yubordik.Ko'rinib turibdiki, satrlar va primitivlar Osonlik bilan ketma-ketlashtiriladi: Java, albatta, ba'zilariga ega, buning uchun o'rnatilgan mexanizmlar mavjud. serializableAmmo bizning -sinfimizda ibtidoiy emas, balki boshqa ob'ektlarga havola sifatida ifodalangan maydonlar bo'lsa- chi ? Keling, masalan , sinfimiz bilan ishlash TerritoriesInfouchun alohida sinflar yarataylik . ResourcesInfoDiplomacyInfoSavedGame
public class TerritoriesInfo {

   private String info;

   public TerritoriesInfo(String info) {
       this.info = info;
   }

   public String getInfo() {
       return info;
   }

   public void setInfo(String info) {
       this.info = info;
   }

   @Override
   public String toString() {
       return "TerritoriesInfo{" +
               "info='" + info + '\'' +
               '}';
   }
}

public class ResourcesInfo {

   private String info;

   public ResourcesInfo(String info) {
       this.info = info;
   }

   public String getInfo() {
       return info;
   }

   public void setInfo(String info) {
       this.info = info;
   }

   @Override
   public String toString() {
       return "ResourcesInfo{" +
               "info='" + info + '\'' +
               '}';
   }
}

public class DiplomacyInfo {

   private String info;

   public DiplomacyInfo(String info) {
       this.info = info;
   }

   public String getInfo() {
       return info;
   }

   public void setInfo(String info) {
       this.info = info;
   }

   @Override
   public String toString() {
       return "DiplomacyInfo{" +
               "info='" + info + '\'' +
               '}';
   }
}
Ammo endi bizda savol bor: agar biz o'zgartirilgan sinfni seriyalashtirmoqchi bo'lsak, bu sinflarning barchasi Serializatsiya qilinishi mumkinmi SavedGame?
import java.io.Serializable;
import java.util.Arrays;

public class SavedGame implements Serializable {

   private TerritoriesInfo territoriesInfo;
   private ResourcesInfo resourcesInfo;
   private DiplomacyInfo diplomacyInfo;

   public SavedGame(TerritoriesInfo territoriesInfo, ResourcesInfo resourcesInfo, DiplomacyInfo diplomacyInfo) {
       this.territoriesInfo = territoriesInfo;
       this.resourcesInfo = resourcesInfo;
       this.diplomacyInfo = diplomacyInfo;
   }

   public TerritoriesInfo getTerritoriesInfo() {
       return territoriesInfo;
   }

   public void setTerritoriesInfo(TerritoriesInfo territoriesInfo) {
       this.territoriesInfo = territoriesInfo;
   }

   public ResourcesInfo getResourcesInfo() {
       return resourcesInfo;
   }

   public void setResourcesInfo(ResourcesInfo resourcesInfo) {
       this.resourcesInfo = resourcesInfo;
   }

   public DiplomacyInfo getDiplomacyInfo() {
       return diplomacyInfo;
   }

   public void setDiplomacyInfo(DiplomacyInfo diplomacyInfo) {
       this.diplomacyInfo = diplomacyInfo;
   }

   @Override
   public String toString() {
       return "SavedGame{" +
               "territoriesInfo=" + territoriesInfo +
               ", resourcesInfo=" + resourcesInfo +
               ", diplomacyInfo=" + diplomacyInfo +
               '}';
   }
}
Keling, buni amalda tekshirib ko'ramiz! Keling, hamma narsani hozircha qoldirib, ob'ektni ketma-ketlashtirishga harakat qilaylik SavedGame:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Main {

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

       // create our object
       TerritoriesInfo territoriesInfo = new TerritoriesInfo("Spain has 6 provinces, Russia has 10 provinces, France has 8 provinces");
       ResourcesInfo resourcesInfo = new ResourcesInfo("Spain has 100 gold, Russia has 80 gold, France has 90 gold");
       DiplomacyInfo diplomacyInfo =  new DiplomacyInfo("France is at war with Russia, Spain has taken a position of neutrality");


       SavedGame savedGame = new SavedGame(territoriesInfo, resourcesInfo, diplomacyInfo);

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

       objectOutputStream.writeObject(savedGame);

       objectOutputStream.close();
   }
}
Natija: "main" java.io.NotSerializableExceptiondagi istisno: DiplomacyInfo bajarilmadi! Aslida, bu bizning savolimizga javob. Ob'ektni ketma-ketlashtirganda, uning misol o'zgaruvchilarida havola qilingan barcha ob'ektlar ketma-ketlashtiriladi. Va agar bu ob'ektlar uchinchi ob'ektlarga ham murojaat qilsa, ular ham ketma-ketlashtiriladi. Va hokazolar infinitum. Ushbu zanjirdagi barcha sinflar Serializatsiya qilinadigan bo'lishi kerak, aks holda ular ketma-ketlashtirilmaydi va istisno qilinadi. Aytgancha, bu kelajakda muammolarni keltirib chiqarishi mumkin. Biz, masalan, seriyalilashtirish paytida sinfning bir qismiga muhtoj bo'lmasak, nima qilishimiz kerak? Yoki, masalan, TerritoryInfodasturimizdagi sinf ba'zi kutubxonaning bir qismi sifatida "meroslangan". Biroq, u Serializatsiya qilinmaydi va shunga mos ravishda biz uni o'zgartira olmaymiz. Ma'lum bo'lishicha, biz TerritoryInfosinfimizga maydon qo'sha SavedGameolmaymiz , chunki bu holda butun sinf SavedGameketma-ketlashtirilmaydi! Muammo:/ Java-da seriyalilashtirish va seriyadan chiqarish - 2Ushbu turdagi muammolar Java-da kalit so'z yordamida hal qilinadi transient. Agar siz ushbu kalit so'zni sinf maydoniga qo'shsangiz, bu maydonning qiymati ketma-ketlashtirilmaydi. Keling, sinfimiz maydonlaridan birini yaratishga harakat qilaylik SavedGame transient, shundan so'ng biz bitta ob'ektni ketma-ketlashtiramiz va tiklaymiz.
import java.io.Serializable;

public class SavedGame implements Serializable {

   private transient TerritoriesInfo territoriesInfo;
   private ResourcesInfo resourcesInfo;
   private DiplomacyInfo diplomacyInfo;

   public SavedGame(TerritoriesInfo territoriesInfo, ResourcesInfo resourcesInfo, DiplomacyInfo diplomacyInfo) {
       this.territoriesInfo = territoriesInfo;
       this.resourcesInfo = resourcesInfo;
       this.diplomacyInfo = diplomacyInfo;
   }

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



import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class Main {

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

       // create our object
       TerritoriesInfo territoriesInfo = new TerritoriesInfo("Spain has 6 provinces, Russia has 10 provinces, France has 8 provinces");
       ResourcesInfo resourcesInfo = new ResourcesInfo("Spain has 100 gold, Russia has 80 gold, France has 90 gold");
       DiplomacyInfo diplomacyInfo =  new DiplomacyInfo("France is at war with Russia, Spain has taken a position of neutrality");


       SavedGame savedGame = new SavedGame(territoriesInfo, resourcesInfo, diplomacyInfo);

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

       objectOutputStream.writeObject(savedGame);

       objectOutputStream.close();
   }
}


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);

       SavedGame savedGame = (SavedGame) objectInputStream.readObject();

       System.out.println(savedGame);

       objectInputStream.close();


   }
}
Va natija: SavedGame{territoriesInfo=null, resourcesInfo=ResourcesInfo{info='Ispaniyada 100 oltin, Rossiyada 80 oltin, Fransiyada 90 oltin'}, diplomatacyInfo=DiplomacyInfo{info='Fransiya Rossiya bilan urushda, Ispaniya betaraflik pozitsiyasini egalladi'}}transient Shu bilan birga, -maydonga qanday qiymat beriladi, degan savolga javob oldik . Unga standart qiymat beriladi. Ob'ektlar holatida bu null. Bo'sh vaqtingizda seriallashtirish haqidagi ushbu ajoyib maqolani o'qishingiz mumkin . Bundan tashqari, interfeys haqida gapiradi Externalizable, bu haqda keyingi ma'ruzada gaplashamiz. Bundan tashqari, "Head-First Java" kitobida ushbu mavzu bo'yicha bo'lim mavjud, unga e'tibor bering :)
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION