CodeGym/Blog Java/rawak/Apakah perbezaan antara serialisasi dan deserialisasi di ...
John Squirrels
Tahap
San Francisco

Apakah perbezaan antara serialisasi dan deserialisasi di Jawa?

Diterbitkan dalam kumpulan
Hai! Dalam pelajaran hari ini, kita bercakap tentang pensirilan dan penyahserikan di Jawa. Kita akan mulakan dengan contoh mudah. Katakan anda telah mencipta permainan komputer. Jika anda dibesarkan pada tahun 90-an dan mengingati konsol permainan pada era itu, anda mungkin tahu bahawa mereka tidak mempunyai sesuatu yang kami anggap remeh hari ini — keupayaan untuk menyimpan dan memuatkan permainan :) Jika tidak, bayangkan itu! Apakah perbezaan antara serialisasi dan deserialisasi di Jawa?  - 1 Saya takut hari ini permainan tanpa kebolehan ini akan ditakdirkan! Apakah yang dimaksudkan dengan "simpan" dan "memuatkan" permainan juga? Nah, kami memahami maksud biasa: kami mahu meneruskan permainan dari tempat kami berhenti. Untuk melakukan ini, kami mencipta sejenis "titik semak", yang kemudian kami gunakan untuk memuatkan permainan. Tetapi apakah maksud ini kepada pengaturcara dan bukannya pemain permainan kasual? Jawapannya mudah: kami. Katakan anda bermain sebagai Sepanyol dalam Strategium. Permainan anda mempunyai keadaan: siapa yang memiliki wilayah mana, siapa yang mempunyai berapa banyak sumber, siapa yang bersekutu dengan siapa, siapa yang berperang dengan siapa, dan sebagainya. Kami mesti menyimpan maklumat ini, keadaan program kami, untuk memulihkannya pada masa hadapan dan meneruskan permainan. Kerana ini adalah tepat untuk bersiri dan nyahrealisasi . Serialisasi ialah proses menyimpan keadaan objek dalam urutan bait. Penyahserialisasianialah proses memulihkan objek daripada bait ini. Mana-mana objek Java boleh ditukar kepada jujukan bait. Mengapa kita memerlukannya? Kami telah mengatakan lebih daripada sekali bahawa program tidak wujud dengan sendirinya. Selalunya, mereka berinteraksi dengan program lain, bertukar-tukar data, dsb. Dan urutan bait ialah format yang mudah dan cekap. Sebagai contoh, kita boleh menukar SavedGameobjek kita kepada urutan bait, menghantar bait ini melalui rangkaian ke komputer lain, dan kemudian pada komputer kedua menukar bait ini kembali menjadi objek Java! Kedengaran sukar, bukan? Dan melaksanakan proses ini kelihatan seperti sakit :/ Untungnya, ini tidak begitu! :) Di Jawa, theSerializableantara muka bertanggungjawab untuk proses bersiri. Antara muka ini sangat mudah: anda tidak perlu melaksanakan satu kaedah untuk menggunakannya! Beginilah rupa kelas penjimatan permainan kami yang mudah:
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) +
               '}';
   }
}
Tiga tatasusunan bertanggungjawab untuk maklumat tentang wilayah, sumber dan diplomasi. Antara muka Serializable memberitahu mesin maya Java: " Semuanya OK — jika perlu, objek kelas ini boleh bersiri ". Antara muka tanpa satu antara muka kelihatan pelik :/ Mengapa perlu? Jawapan kepada soalan ini boleh dilihat di atas: ia hanya berfungsi untuk memberikan maklumat yang diperlukan kepada mesin maya Java. Dalam salah satu pelajaran terdahulu kami, kami menyebut secara ringkas antara muka penanda . Ini adalah antara muka maklumat khas yang hanya menandakan kelas kami dengan maklumat tambahan yang akan berguna kepada mesin Java pada masa hadapan. Mereka tidak mempunyai sebarang kaedah yang perlu anda laksanakan.Serializableadalah salah satu antara muka tersebut. Satu lagi perkara penting: Mengapa kita memerlukan private static final long serialVersionUIDpembolehubah yang kita takrifkan dalam kelas? Mengapa ia diperlukan? Medan ini mengandungi pengecam unik untuk versi kelas bersiri . Mana-mana kelas yang melaksanakan Serializableantara muka mempunyai versionpengecam. Ia dikira berdasarkan kandungan kelas: medannya, susunan di mana ia diisytiharkan, kaedah, dsb. Jika kita menukar jenis medan dan/atau bilangan medan dalam kelas kita, maka pengecam versi serta-merta berubah . serialVersionUIDjuga ditulis apabila kelas bersiri. Apabila kita cuba untuk menyahsiri, iaitu, memulihkan objek daripada set bait, yang berkaitan serialVersionUIDdibandingkan dengan nilaiserialVersionUIDuntuk kelas dalam program kami. Jika nilai tidak sepadan, maka java.io. InvalidClassException akan dibuang. Kita akan melihat contoh ini di bawah. Untuk mengelakkan ini, kami hanya menetapkan pengecam versi secara manual dalam kelas kami. Dalam kes kami, ia hanya akan sama dengan 1 (tetapi anda boleh menggantikan mana-mana nombor lain yang anda suka). Nah, sudah tiba masanya untuk cuba menyusun SavedGameobjek kita dan lihat apa yang berlaku!
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 neutral position"};

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

       // Create 2 streams 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 the game to a file
       objectOutputStream.writeObject(savedGame);

       // Close the stream and free resources
       objectOutputStream.close();
   }
}
Seperti yang anda lihat, kami mencipta 2 aliran: FileOutputStreamdan ObjectOutputStream. Yang pertama boleh menulis data ke fail, dan yang kedua menukar objek kepada bait. Anda telah pun melihat binaan "bersarang" yang serupa, contohnya, new BufferedReader(new InputStreamReader(...)), dalam pelajaran sebelumnya, jadi perkara itu tidak sepatutnya menakutkan anda :) Dengan mencipta "rantai" dua aliran sedemikian, kami melaksanakan kedua-dua tugas: kami menukar objek SavedGamemenjadi satu set daripada bait dan simpan ke fail menggunakan writeObject()kaedah. Dan, dengan cara itu, kami tidak melihat apa yang kami dapat! Sudah tiba masanya untuk melihat fail! *Nota: anda tidak perlu mencipta fail terlebih dahulu. Jika fail dengan nama itu tidak wujud, ia akan dibuat secara automatik* Dan berikut ialah kandungannya!
¬н sr SavedGame [ diplomacyInfot [Ljava/lang/String;[ resourcesInfoq ~ [ territoriesInfoq ~ xpur [Ljava.lang.String;­ТVзй{G xp t pФранция воюет СЃ Россией, Испания заняла позицию нейтралитетаuq ~ t "РЈ Испании 100 золотаt РЈ Р РѕСЃСЃРёРё 80 золотаt !РЈ Франции 90 золотаuq ~ t &РЈ Испании 6 провинцийt %РЈ Р РѕСЃСЃРёРё 10 провинцийt &РЈ Франции 8 провинций
Uh-oh :( Nampaknya program kami tidak berfungsi :( Malah, ia berjaya. Anda ingat bahawa kami menghantar satu set bait, bukan sekadar objek atau teks, ke fail? Nah, inilah yang set bait kelihatan seperti :) Ini adalah permainan kami yang disimpan! Jika kami ingin memulihkan objek asal kami, iaitu mulakan dan teruskan permainan di tempat kami berhenti, maka kami memerlukan proses terbalik: penyahserikatan . Beginilah rupanya dalam kami kes:
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);
   }
}
Dan inilah hasilnya!
SavedGame{territoriesInfo=["Spain has 6 provinces, Russia has 10 provinces, France has 8 provinces], resourcesInfo=[Spain has 100 gold, Russia has 80 gold, France has 90 gold], diplomacyInfo=[France is at war with Russia, Spain has taken a neutral position]}
Cemerlang! Kami berjaya menyimpan dahulu keadaan permainan kami ke fail, dan kemudian memulihkannya daripada fail. Sekarang mari kita cuba melakukan perkara yang sama, tetapi tanpa pengecam versi untuk SavedGamekelas kita. Kami tidak akan menulis semula kedua-dua kelas kami. Kod mereka akan kekal sama, tetapi kami akan mengalih keluar private static final long serialVersionUIDdaripada SavedGamekelas. Inilah objek kami selepas bersiri:
¬н sr SavedGameі€MіuОm‰ [ diplomacyInfot [Ljava/lang/String;[ resourcesInfoq ~ [ territoriesInfoq ~ xpur [Ljava.lang.String;­ТVзй{G xp t pФранция воюет СЃ Россией, Испания заняла позицию нейтралитетаuq ~ t "РЈ Испании 100 золотаt РЈ Р РѕСЃСЃРёРё 80 золотаt !РЈ Франции 90 золотаuq ~ t &РЈ Испании 6 провинцийt %РЈ Р РѕСЃСЃРёРё 10 провинцийt &РЈ Франции 8 провинций
Tetapi lihat apa yang berlaku apabila kita cuba menyahsirinya:
InvalidClassException: local class incompatible: stream classdesc serialVersionUID = -196410440475012755, local class serialVersionUID = -6675950253085108747
Ini adalah pengecualian yang kami nyatakan di atas. By the way, kami terlepas sesuatu yang penting. Adalah masuk akal bahawa Strings dan primitives boleh disirikan dengan mudah: Java mungkin mempunyai beberapa jenis mekanisme terbina dalam untuk melakukan ini. Tetapi bagaimana jika serializablekelas kami mempunyai medan yang bukan primitif, sebaliknya merujuk kepada objek lain? Sebagai contoh, mari buat kelas berasingan TerritoriesInfodan untuk berfungsi dengan kelas kami . 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 + '\'' +
               '}';
   }
}
Dan kini timbul persoalan: adakah semua kelas ini perlu Serializablejika kita mahu membuat siri SavedGamekelas kita yang diubah?
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 +
               '}';
   }
}
Baiklah, mari kita uji! Mari kita biarkan segala-galanya seperti sedia ada dan cuba bersiri SavedGameobjek:
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
       TerritoryInfo territoryInfo = new TerritoryInfo("Spain has 6 provinces, Russia has 10 provinces, France has 8 provinces");
       ResourceInfo resourceInfo = new ResourceInfo("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 neutral position");


       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();
   }
}
Keputusan:
Exception in thread "main" java.io.NotSerializableException: DiplomacyInfo
Ia tidak berjaya! Pada asasnya, itulah jawapan kepada soalan kami. Apabila objek bersiri, semua objek yang dirujuk oleh pembolehubah contohnya disiri. Dan jika objek tersebut juga merujuk kepada objek lain, maka ia juga bersiri. Dan seterusnya ad infinitum. Semua kelas dalam rantaian ini mestilahSerializable , jika tidak, mustahil untuk mensirikannya dan pengecualian akan dibuang. Dengan cara ini, ini boleh menimbulkan masalah di jalan raya. Apakah yang perlu kita lakukan jika, sebagai contoh, kita tidak memerlukan sebahagian daripada kelas apabila kita bersiri? Atau, sebagai contoh, bagaimana jika TerritoryInfokelas itu datang kepada kami sebagai sebahagian daripada perpustakaan pihak ketiga. Dan anggap lagi bahawa ia tidak Serializabledan, oleh itu, kita tidak boleh mengubahnya. Ternyata kita tidak boleh menambah TerritoryInfomedan pada kitaSavedGamekelas, kerana berbuat demikian akan menjadikan seluruh SavedGamekelas tidak boleh bersiri! Itu masalah :/ Apakah perbezaan antara serialisasi dan deserialisasi di Jawa?  - 2Di Jawa, masalah seperti ini diselesaikan menggunakan transientkata kunci. Jika anda menambahkan kata kunci ini pada medan kelas anda, maka medan itu tidak akan bersiri. Mari cuba jadikan salah satu SavedGamemedan contoh kelas itu sementara. Kemudian kami akan bersiri dan memulihkan satu objek.
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
       TerritoryInfo territoryInfo = new TerritoryInfo("Spain has 6 provinces, Russia has 10 provinces, France has 8 provinces");
       ResourceInfo resourceInfo = new ResourceInfo("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 neutral position");


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


   }
}
Dan inilah hasilnya:
SavedGame{territoriesInfo=null, resourcesInfo=ResourcesInfo{info='Spain has 100 gold, Russia has 80 gold, France has 90 gold'}, diplomacyInfo=DiplomacyInfo{info='France is at war with Russia, Spain has taken a neutral position'}}
Selain itu, kami mendapat jawapan kepada soalan kami tentang nilai yang diberikan kepada transientmedan. Ia akan diberikan nilai lalai. Untuk objek, ini adalah null. Anda boleh membaca artikel hebat ini mengenai penyirian apabila anda mempunyai beberapa minit lagi. Ia juga menyebut Externalizableantara muka, yang akan kita bincangkan dalam pelajaran seterusnya. Selain itu, buku "Head-First Java" mempunyai bab mengenai topik ini. Beri perhatian :)
Komen
  • Popular
  • Baru
  • Tua
Anda mesti log masuk untuk meninggalkan ulasan
Halaman ini tidak mempunyai sebarang ulasan lagi