JavaRush /Java блогу /Random-KY /Java тилинде сериялаштыруу жана сериядан чыгаруу

Java тилинде сериялаштыруу жана сериядан чыгаруу

Группада жарыяланган
Салам! Бүгүнкү лекцияда биз Java тorнде сериалдаштыруу жана сериялаштыруу жөнүндө сүйлөшөбүз. Жөнөкөй бир мисал менен баштайлы. Сиз компьютердик оюндун жаратуучусусуз дейли. Эгер сиз 90-жылдары чоңойгон болсоңуз жана ошол кездеги оюн консолдорун эстесеңиз, анда аларда бүгүнкү күндө айкын бир нерсе жетишпей жатканын билесизби - оюндарды сактоо жана жүктөө :) Эгерде жок болсо... элестетиңиз! Бүгүн андай мүмкүнчүлүгү жок оюн ийгorксиз болуп калабы деп корком! Жана, чынында, оюнду "сактоо" жана "жүктөө" деген эмне? Кадимки мааниде биз мунун эмне экенин түшүнөбүз: биз оюнду акыркы жолу токтогон жерден улантууну каалайбыз. Бул үчүн, биз оюнду жүктөө үчүн колдоно турган "текшерүү пунктун" түзөбүз. Бирок бул күнүмдүк мааниде эмес, “программист” деген мааниде эмнени билдирет? Жооп жөнөкөй: биз программабыздын абалын сактайбыз. Сиз Испания үчүн стратегиялык оюн ойноп жатасыз дейли. Сиздин оюнуңузда мамлекет бар: ким кандай аймактарга ээ, кимдин канча ресурсу бар, ким ким менен союзда, ким, тескерисинче, согушта ж.б.у.с. Бул маалымат, биздин программанын абалы, кийинчерээк маалыматтарды калыбына келтирүү жана оюнду улантуу үчүн кандайдыр бир жол менен сакталышы керек. Сериялаштыруу жана сериялаштыруу механизмдери дал ушул үчүн колдонулат . Сериялаштыруу - an objectтин абалын byte ырааттуулугуна сактоо процесси. Десерализация бул byteтардан an objectти реконструкциялоо процесси. Каалаган Java an objectиси byte ырааттуулугуна айландырылат. Бул эмне үчүн? Программалар өз алдынча жок экенин биз бир нече жолу айтканбыз. Көбүнчө алар бири-бири менен иштешет, маалымат алмашуу ж. Ал эми byte форматы бул үчүн ыңгайлуу жана эффективдүү. Биз, мисалы, класс an objectибизди SavedGame(сакталган оюнду) byteтардын ырааттуулугуна айланта алабыз, ал byteтарды тармак аркылуу башка компьютерге өткөрүп, ал эми экинчи компьютерде ал byteтарды кайра Java an objectисине айланта алабыз! Бул угуу кыйын, туурабы? Кыязы, бул процессти уюштуруу оңой болбойт окшойт :/ Бактыга жараша, жок! :) Java'да Сериялаштырылуучу интерфейс сериялаштыруу процесстерине жооп берет . Бул интерфейс өтө жөнөкөй: аны колдонуу үчүн бир гана ыкманы колдонуунун кереги жок! Сактоо оюну классыбыз ушундай болот:
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) +
               '}';
   }
}
Үч маалымат топтому аймактар, экономика жана дипломатия жөнүндө маалымат үчүн жооп берет жана Сериялаштырылуучу интерфейс Java машинасына: " баары жакшы, эгер бир нерсе болсо, бул класстын an objectилерин сериялаштырса болот " дейт. Эч кандай ыкмалары жок интерфейс кызыктай көрүнөт :/ Бул эмне үчүн керек? Бул суроонун жообу жогоруда: Java машинасына керектүү маалыматты берүү үчүн гана. Мурунку лекциялардын биринде биз маркер интерфейстерин кыскача айтып өткөнбүз. Булар биздин класстарды келечекте Java машинасы үчүн пайдалуу боло турган кошумча маалымат менен белгилеген атайын маалыматтык интерфейстер. Алар ишке ашыруу үчүн зарыл болгон эч кандай ыкмалары жок. Ошентип, Serializable ушундай интерфейстердин бири. private static final long serialVersionUIDДагы бир маанилүү жагдай: биз класста аныкталган өзгөрмө . Бул эмне үчүн керек? Бул талаа сериялаштырылган класстын уникалдуу version идентификаторун камтыйт . Serializable интерфейсин ишке ашырган бардык класстар version идентификаторуна ээ. Ал класстын мазмуну боюнча эсептелет - талаалар, декларация тартиби, ыкмалары. Ал эми классыбыздагы талаанын түрүн жана/же талаалардын санын өзгөртсөк, version идентификатору заматта өзгөрөт. serialVersionUID класс серияланганда да жазылат. Сериядан чыгарууга, башкача айтканда, byte топтомунан an objectти калыбына келтирүүгө аракет кылганда, маани биздин программадагы класстын serialVersionUIDмааниси менен салыштырылат . serialVersionUIDЭгерде маанилер дал келбесе, java.io.InvalidClassException ыргытылат. Төмөндө мунун мисалын көрөбүз. Мындай жагдайларды болтурбоо үчүн, биз классыбыз үчүн бул version идентификаторун жөн гана кол менен орноттук. Биздин учурда, ал жөн гана 1ге барабар болот (сиз каалаган башка санды алмаштырсаңыз болот). SavedGameБиздин an objectибизди сериялаштырууга аракет кылып , эмне болорун көрүүгө убакыт келди !
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();
   }
}
Көрүнүп тургандай, биз 2 жипти түздүк - FileOutputStreamжана ObjectOutputStream. Алардын биринчиси файлга маалыматтарды жаза алат, ал эми экинчиси an objectтерди byteтарга айландыра алат. Сиз буга чейин окшош "уяланган" конструкцияларды көргөнсүз, мисалы, new BufferedReader(new InputStreamReader(...))мурунку лекцияларда, ошондуктан алар сизди коркутпашы керек :) Эки жиптен турган ушундай "чынжырды" түзүү менен биз эки тапшырманы тең аткарабыз: an objectти SavedGamebyteтардын жыйындысына айлантабыз. ыкмасын колдонуп файлга сактаңыз writeObject(). Айтмакчы, биз алган нерсени текшерген жокпуз! Файлды карап чыгууга убакыт келди! *Эскертүү: файлды алдын ала түзүүнүн кереги жок. Бул аттагы файл жок болсо, ал автоматтык түрдө түзүлөт* Жана анын мазмуну мына! ¬н sr SavedGame [ diplomatacyInfot [Ljava/lang/String;[ resourcesInfoq ~ [ territoriesInfoq ~ xpur [Ljava.lang.String;ТVзй{G xp t pФранцвоюРμС РЃСЃРµРЃСЃР˃СРЃС ° РЅРёСЏ Р·Р°Ряла позицию нейтралитетаuq ~ t "РЈ Р˜СЃРїР°РЅРёРёР‚Р†РёРё 10» РѕСЃСЃРёРё 80 золотаt !РЈ Франции 90 золотаuq ~ t &РЈ Р˜СЃРїР°РЅР˜СЃРїР°РЅР˜СЃРїР°РЅРˠРёРёР %ЂииР6РЈ Франции Ј Р РѕСЃСЃРёРё 10 РїСЂРѕРІРёРЅС †РёР№t &РЈ ФранцРеРё 8 проввинций Ой :( Биздин программа иштебей калды окшойт :( Чынында, ал иштеди. Биз файлга так жана byte топтомун өткөрүп бергенибиз эсиңизде. жөн гана an object же текст эмес? Ооба, бул топтом ушундай көрүнөт :) Бул биздин сакталган оюнубуз! Эгерде биз баштапкы an objectибизди калыбына келтиргибиз келсе, башкача айтканда, жүктөп алып, оюнду токтогон жерден улантууну кааласак, бизге тескери процесс , сериядан чыгаруу ... Биздин учурда бул ушундай болот:
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);
   }
}
Жана жыйынтык мына! SavedGame{territoriesInfo=[Испанияда 6 провинция, Россияда 10 провинция, Францияда 8 провинция бар], resourcesInfo=[Испанияда 100 алтын, Россияда 80 алтын, Францияда 90 алтын], diplomatacyInfo=[Франция Орусия менен согушууда, Испания бейтараптык позициясын ээлеп алды]} Улуу! Биз алгач оюнубуздун абалын файлга сактап, андан кийин аны файлдан калыбына келтирүүгө жетиштик. Эми ошону кылганга аракет кылалы, бирок SavedGameversion идентификаторун классыбыздан алып салыңыз. Биз эки классыбызды тең кайра жазбайбыз, алардагы code бирдей болот, жөн гана SavedGameалып салабыз private static final long serialVersionUID. Сериалдаштыруудан кийинки an objectибиз: ¬н sr SavedGameі€MіuОm‰ [ diplomatacyInfot [Ljava/lang/String;[ resourcesInfoq ~ [ territoriesInfoq ~ xpur [Ljava.lang.String;ТВзй{G xp t pФраняСанСЀС† ‚ СЃ РРоссией, Р˜СЃРїР°РЅРЏР·Р°РЅСЏР»Р° RїРѕР·РёС†РёСЋ РЅРμйтралитралитралатР˅"аѣР~Р°Р˜С ёРё 100 Р · олотаt РЈ Р РѕСЃСЃРёРё 80 золотаt !РЈ Франции 90 золотаuq ~ t &РЃё Р˅ t &СЃёР˅ їСЂРѕРІРёРЅС† РёР№t %РЈ Р РѕСЃСЃРёРё 10 провнинцийt &РЈ Франции качан де†РРРЅС†РЈРёРЅС аны сериалдаштырсаңыз, мындай болду: InvalidClassException: жергorктүү класс шайкеш келбейт: stream classdesc serialVersionUID = - 196410440475012755, локалдык класс serialVersionUID = -6675950253085108747 Бул жогоруда айтылган өзгөчөлүк. Бул тууралуу кененирээк биздин студенттердин биринин макаласынан окуй аласыз . Баса, биз бир маанилүү нерсени өткөрүп жибердик. Саптар жана примитивдер экени анык. оңой сериализацияланат: Java, албетте, кээ бирлери бар, анда бул үчүн орнотулган механизмдер бар. Бирок биздин serializable-класста примитивдер эмес, башка an objectтерге шилтемелер катары берилген талаалар болсочы? Мисалы , биздин класс менен иштөө TerritoriesInfoүчүн өзүнчө класстарды түзөлү . 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 + '\'' +
               '}';
   }
}
Бирок азыр бизде бир суроо бар: эгерде биз өзгөртүлгөн классты сериялаштырууну кааласак, бул класстардын бардыгы Сериялаштырылышы керекпи 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 +
               '}';
   }
}
Келгиле, муну иш жүзүндө текшерип көрөлү! Келгиле, бардыгын азыркыдай калтырып, an objectти сериялаштырууга аракет кылалы 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();
   }
}
Натыйжа: "main" жипиндеги өзгөчө жагдай java.io.NotSerializableException: DiplomacyInfo ишке ашкан жок! Чынында, бул жерде биздин суроого жооп. Объектти сериялаштырганда, анын инстанция өзгөрмөлөрүндө шилтеме кылган бардык an objectтер серияланат. Жана бул an objectтер үчүнчү an objectтерге да шилтеме кылса, алар да сериялаштырылат. Жана башкалар ad infinitum. Бул чынжырдагы бардык класстар Сериялаштырыла турган болушу керек, антпесе алар сериялаштырылbyte жана өзгөчө жагдай пайда болот. Бул, демек, келечекте көйгөйлөрдү жаратышы мүмкүн. Мисалы, сериялаштыруу учурунда класстын бир бөлүгүнө муктаж болбосок, эмне кылышыбыз керек? Же, мисалы, TerritoryInfoбиз кандайдыр бир китепкананын бөлүгү катары программабыздагы классты мурастап алдык. Бирок, ал Сериялаштырылbyte, демек, биз аны өзгөртө албайбыз. Көрсө, биз TerritoryInfoклассыбызга талаа кошо албайбыз, анткени анда бүт класс серияланбай калат! Көйгөй:/ Мындай көйгөйлөр Java тorнде ачкыч сөз менен чечилет . Эгер сиз бул ачкыч сөздү класс талаасына кошсоңуз, бул талаанын мааниси серияланbyte. Биздин класстын талааларынын бирин жасаганга аракет кылалы , андан кийин бир an objectти сериялаштырабыз жана калыбына келтиребиз. SavedGameSavedGameJavaда сериялаштыруу жана сериядан чыгаруу - 2transientSavedGame transient
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();


   }
}
Мына натыйжа: SavedGame{territoriesInfo=null, resourcesInfo=ResourcesInfo{info='Испанияда 100 алтын, Россияда 80 алтын, Францияда 90 алтын'}, diplomatacyInfo=DiplomacyInfo{info='Франция Россия менен согушууда, Испания бейтараптык позициясын ээледи'}}transient Ошол эле учурда биз -талаага кандай баа берилет деген суроого жооп алдык . Ал демейки мааниге ээ. Объекттерге карата бул null. Бош убактыңызда сериялаштыруу жөнүндө бул эң сонун макаланы окуй аласыз . Ошондой эле интерфейс жөнүндө сөз болот Externalizable, ал жөнүндө биз кийинки лекцияда сүйлөшөбүз. Кошумчалай кетсек, бул тема боюнча "Башы-Биринчи Java" китебинде бөлүм бар, ага көңүл буруңуз :)
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION