Programavimas

Atskleistas „Java“ serializavimo algoritmas

Serializavimas yra objekto būsenos išsaugojimo baitų sekoje procesas; deserializacija yra tų baitų atstatymo į gyvą objektą procesas. „Java Serialization“ API suteikia standartinį mechanizmą, skirtą kūrėjams valdyti objektų nuoseklumą. Šiame patarime pamatysite, kaip susisteminti objektą ir kodėl kartais reikia atlikti serializavimą. Sužinosite apie „Java“ naudojamą serializavimo algoritmą ir pamatysite pavyzdį, kuris iliustruoja serijinį objekto formatą. Iki to laiko, kai baigsite, turėtumėte gerai žinoti, kaip veikia serializavimo algoritmas ir kokie objektai yra nuosekliai siejami kaip objekto dalis žemame lygyje.

Kodėl reikalingas serializavimas?

Šiuolaikiniame pasaulyje tipinė įmonės programa turės kelis komponentus ir bus paskirstyta įvairioms sistemoms ir tinklams. „Java“ viskas vaizduojama kaip objektai; jei du „Java“ komponentai nori bendrauti tarpusavyje, reikia duomenų mainų mechanizmo. Vienas iš būdų tai pasiekti yra apibrėžti savo protokolą ir perkelti objektą. Tai reiškia, kad priimančioji šalis turi žinoti siuntėjo naudojamą protokolą objektui sukurti iš naujo, o tai apsunkintų kalbėjimąsi su trečiųjų šalių komponentais. Taigi, norint perkelti objektą tarp komponentų, reikia bendro ir efektyvaus protokolo. Šiam tikslui apibrėžta serializacija, o „Java“ komponentai naudoja šį protokolą objektams perkelti.

1 paveiksle parodytas aukšto lygio kliento / serverio ryšio vaizdas, kai objektas iš kliento į serverį perduodamas atliekant nuoseklųjį suderinimą.

1 pav. Aukšto lygio serializacijos vaizdas (spustelėkite, jei norite padidinti)

Kaip susieti objektą

Norėdami susieti objektą, turite įsitikinti, kad objekto klasė įgyvendina java.io.Serializuojama sąsaja, kaip parodyta 1 sąraše.

Sąrašas 1. „Serializable“ įgyvendinimas

 importuoti java.io.Serializable; klasė „TestSerial“ įgyvendina „Serializable“ {public byte version = 100; viešųjų baitų skaičius = 0; } 

1 sąraše vienintelis dalykas, kurį turėjote padaryti kitaip nei kurdami įprastą klasę, yra įdiegti java.io.Serializuojama sąsaja. Serijinis sąsaja yra žymeklio sąsaja; ji nedeklaruoja jokių metodų. Jis nurodo serializavimo mechanizmą, kad klasė gali būti nuosekli.

Dabar, kai klasę padarėte tinkama serializuoti, kitas žingsnis yra iš tikrųjų serializuoti objektą. Tai daroma paskambinus writeObject () metodas java.io.ObjectOutputStream klasė, kaip parodyta 2 sąraše.

Sąrašas 2. Skambinimas writeObject ()

 public static void main (String args []) išmeta IOException {FileOutputStream fos = new FileOutputStream ("temp.out"); ObjectOutputStream oos = naujas ObjectOutputStream (fos); TestSerial ts = nauja TestSerial (); oos.writeObject (ts); oos.skalauti (); oos.uždaryti (); } 

2 sąraše saugoma „TestSerial“ objektas faile, vadinamame temp.out. oos.writeObject (ts); iš tikrųjų paleidžia serializavimo algoritmą, kuris savo ruožtu rašo objektą temp.out.

Norėdami iš naujo sukurti objektą iš nuolatinio failo, naudosite 3 sąrašo kodą.

Sąrašas 3. Serijinio objekto atkūrimas

 public static void main (String args []) išmeta IOException {FileInputStream fis = new FileInputStream ("temp.out"); ObjectInputStream oin = naujas ObjectInputStream (fis); TestSerial ts = (TestSerial) oin.readObject (); System.out.println ("versija =" + ts.versija); } 

3 sąraše objektas atkuriamas naudojant oin.readObject () metodo skambutis. Šis metodo iškvietimas nurodo neapdorotus baitus, kuriuos mes išlaikėme anksčiau, ir sukuria gyvą objektą, kuris yra tiksli originalaus objekto grafiko kopija. Nes readObject () gali nuskaityti bet kurį serijinį objektą, reikalingas tinkamo tipo perdavimas.

Vykdant šį kodą bus atspausdinta versija = 100 apie standartinę išvestį.

Serijinis objekto formatas

Kaip atrodo serijinė objekto versija? Atminkite, kad ankstesnio skyriaus kodo pavyzdys išsaugojo serijinę „TestSerial“ objektą į failą temp.out. 4 sąraše rodomas temp.out, rodomas šešioliktainiais skaičiais. (Norint pamatyti išvestį šešioliktainio formato, jums reikia šešioliktainio redaktoriaus.)

Sąrašas 4. „TestSerial“ šešioliktainė forma

 AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65 73 74 A0 0C 34 00 FE B1 DD F9 02 00 02 42 00 05 63 6F 75 6E 74 42 00 07 76 65 72 73 69 6F 6E 78 70 00 64 

Jei dar kartą pažvelgsite į tikrąjį „TestSerial“ objektą, pamatysite, kad jame yra tik du baitų nariai, kaip parodyta 5 sąraše.

5. „TestSerial“ baitų narių sąrašas

 viešojo baito versija = 100; viešųjų baitų skaičius = 0; 

Baito kintamojo dydis yra vienas baitas, taigi bendras objekto dydis (be antraštės) yra du baitai. Bet jei pažiūrėsite į serijinio objekto dydį 4 sąraše, pamatysite 51 baitą. Staigmena! Iš kur atsirado papildomi baitai ir kokia jų reikšmė? Jas įvedė serializavimo algoritmas ir jos reikalingos norint iš naujo sukurti objektą. Kitame skyriuje išsamiai išnagrinėsite šį algoritmą.

„Java“ nuoseklumo algoritmas

Iki šiol turėtumėte žinoti apie tai, kaip susieti objektą. Bet kaip procesas vyksta po gaubtu? Paprastai serializavimo algoritmas atlieka šiuos veiksmus:

  • Jis išrašo klasės, susietos su egzemplioriumi, metaduomenis.
  • Rekursyviai rašo superklasės aprašymą, kol randa java.lang.object.
  • Baigęs rašyti metaduomenų informaciją, jis prasideda nuo faktinių duomenų, susijusių su egzemplioriumi. Tačiau šį kartą jis prasideda nuo aukščiausios superklasės.
  • Jis rekursyviai rašo duomenis, susietus su egzemplioriumi, pradedant nuo mažiausiai superklasės iki labiausiai išvestos klasės.

Aš parašiau kitokį šio skyriaus objekto pavyzdį, kuris apims visus galimus atvejus. Naujas serijinio objekto pavyzdys parodytas 6 sąraše.

Sąrašas 6. Serijinio objekto pavyzdys

 klasės tėvai įgyvendina Serializable {int parentVersion = 10; } klasėje yra padargų Serializuojamas {int includeVersion = 11; } public class SerialTest praplečia tėvų įrankius Serializable {int version = 66; yra con = naujas yra (); public int getVersion () {return version; } public static void main (String args []) išmeta IOException {FileOutputStream fos = new FileOutputStream ("temp.out"); ObjectOutputStream oos = naujas ObjectOutputStream (fos); „SerialTest“ st = naujas „SerialTest“ (); oos.writeObject (st); oos.skalauti (); oos.uždaryti (); }} 

Šis pavyzdys yra paprastas. Tai serializuoja tipo objektą „SerialTest“, kuris yra kilęs iš tėvas ir turi konteinerio objektą, turėti. Šio objekto serijinis formatas rodomas 7 sąraše.

Sąrašas 7. Serijos forma pavyzdžio objektas

 AC ED 00 05 73 72 00 0A 53 65 72 69 61 6C 54 65 73 74 05 52 81 5A AC 66 02 F6 02 00 02 49 00 07 76 65 72 73 69 6F 6E 4C 00 03 63 6F 6E 74 00 09 4C 63 6F 6E 74 61 69 6E 3B 78 72 00 06 70 61 72 65 6E 74 0E DB D2 BD 85 EE 63 7A 02 00 01 49 00 0D 70 61 72 65 6E 74 56 65 72 73 69 6F 6E 78 70 00 00 00 0A 00 00 00 42 73 72 00 07 63 6F 6E 74 61 69 6E FC BB E6 0E FB CB 60 C7 02 00 01 49 00 0E 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E 78 70 00 00 00 0B 

2 paveiksle aukšto lygio žvilgsnis į šio scenarijaus serializavimo algoritmą.

2 paveikslas. Serializavimo algoritmo metmenys

Išsamiai peržiūrėkime serijinį objekto formatą ir pažiūrėkime, ką reiškia kiekvienas baitas. Pradėkite nuo serializavimo protokolo informacijos:

  • AC ED: STREAM_MAGIC. Nurodo, kad tai yra serijos protokolas.
  • 00 05: STREAM_VERSION. Serializavimo versija.
  • 0x73: TC_OBJECT. Nurodo, kad tai yra nauja Objektas.

Pirmasis serializavimo algoritmo žingsnis yra parašyti klasės, susijusios su egzemplioriumi, aprašą. Pavyzdys serizuoja tipo objektą „SerialTest“, todėl algoritmas pradedamas rašant aprašą „SerialTest“ klasė.

  • 0x72: TC_CLASSDESC. Nurodo, kad tai nauja klasė.
  • 00 0A: Klasės pavadinimo ilgis.
  • 53 65 72 69 61 6c 54 65 73 74: „SerialTest“, klasės pavadinimas.
  • 05 52 81 5A AC 66 02 F6: „SerialVersionUID“, šios klasės serijos versijos identifikatorius.
  • 0x02: Įvairios vėliavos. Ši konkreti vėliava sako, kad objektas palaiko serializavimą.
  • 00 02: Šios klasės laukų skaičius.

Tada algoritmas rašo lauką int versija = 66;.

  • 0x49: Lauko tipo kodas. 49 reiškia „aš“, kuris reiškia Vid.
  • 00 07: Lauko pavadinimo ilgis.
  • 76 65 72 73 69 6F 6E: versija, lauko pavadinimas.

Tada algoritmas parašo kitą lauką, yra con = naujas yra ();. Tai objektas, todėl jis parašys šio lauko kanoninį JVM parašą.

  • 0x74: TC_STRING. Atstovauja naują eilutę.
  • 00 09: Stygos ilgis.
  • 4C 63 6F 6E 74 61 69 6E 3B: Lcontain;, kanoninis JVM parašas.
  • 0x78: TC_ENDBLOCKDATA, objekto neprivalomų blokavimo duomenų pabaiga.

Kitas algoritmo žingsnis yra parašyti aprašą tėvas klasė, kuri yra betarpiškas superklasė „SerialTest“.

  • 0x72: TC_CLASSDESC. Nurodo, kad tai nauja klasė.
  • 00 06: Klasės pavadinimo ilgis.
  • 70 61 72 65 6E 74: „SerialTest“, klasės pavadinimas
  • 0E DB D2 BD 85 EE 63 7A: „SerialVersionUID“, serijinis šios klasės versijos identifikatorius.
  • 0x02: Įvairios vėliavos. Ši žyma pažymi, kad objektas palaiko serializavimą.
  • 00 01: Šios klasės laukų skaičius.

Dabar algoritmas parašys lauko aprašą tėvas klasė. tėvas turi vieną lauką, int parentVersion = 100;.

  • 0x49: Lauko tipo kodas. 49 reiškia „aš“, kuris reiškia Vid.
  • 00 0D: Lauko pavadinimo ilgis.
  • 70 61 72 65 6E 74 56 65 72 73 69 6F 6E: parentVersion, lauko pavadinimas.
  • 0x78: TC_ENDBLOCKDATA, šio objekto blokavimo duomenų pabaiga.
  • 0x70: TC_NULL, o tai reiškia, kad nebėra superklasių, nes pasiekėme klasės hierarchijos viršūnę.

Iki šiol serializavimo algoritmas parašė klasės, susietos su egzemplioriumi, ir visų jo klasių aprašą. Tada jis parašys faktinius duomenis, susijusius su egzemplioriumi. Pirmiausia tėvų klasės nariams rašoma:

  • 00 00 00 0A: 10, vertė parentVersion.

Tada pereinama prie „SerialTest“.

  • 00 00 00 42: 66, vertė versija.

Kiti keli baitai yra įdomūs. Algoritmas turi parašyti informaciją apie turėti objektas, parodytas 8 sąraše.

Sąrašas 8. Objektas yra

 yra con = naujas yra (); 

Atminkite, kad serializavimo algoritmas neparašė klasės aprašo turėti klasė dar. Tai yra galimybė parašyti šį aprašymą.

  • 0x73: TC_OBJECT, paskiriant naują objektą.
  • 0x72: TC_CLASSDESC.
  • 00 07: Klasės pavadinimo ilgis.
  • 63 6F 6E 74 61 69 6E: turėti, klasės pavadinimas.
  • FC BB E6 0E FB CB 60 C7: „SerialVersionUID“, serijinis šios klasės versijos identifikatorius.
  • 0x02: Įvairios vėliavos. Ši žyma nurodo, kad ši klasė palaiko serijavimą.
  • 00 01: Šios klasės laukų skaičius.

Tada algoritmas turi parašyti aprašą turėtivienintelis laukas, int includeVersija = 11;.

  • 0x49: Lauko tipo kodas. 49 reiškia „aš“, kuris reiškia Vid.
  • 00 0E: Lauko pavadinimo ilgis.
  • 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E: includeVersion, lauko pavadinimas.
  • 0x78: TC_ENDBLOCKDATA.

Tada serializavimo algoritmas patikrina, ar turėti turi bet kurias tėvų klases. Jei taip būtų, algoritmas pradėtų rašyti tą klasę; bet šiuo atveju nėra superklasės turėti, todėl rašo algoritmas TC_NULL.

  • 0x70: TC_NULL.

Galiausiai algoritmas rašo faktinius duomenis, susijusius su turėti.

  • 00 00 00 0B: 11, vertė includeVersion.

Išvada

Šiame patarime jūs pamatėte, kaip nuosekliai atlikti objektą, ir sužinojote, kaip detaliai veikia serializavimo algoritmas. Tikiuosi, kad šiame straipsnyje pateikiama daugiau informacijos apie tai, kas nutinka, kai jūs iš tikrųjų nuosekliai suderinate objektą.

Apie autorių

„Sathiskumar Palaniappan“ turi daugiau nei ketverių metų patirtį IT pramonėje ir daugiau nei trejus metus dirba su „Java“ susijusiomis technologijomis. Šiuo metu jis dirba sistemos programinės įrangos inžinieriumi „Java“ technologijų centre „IBM Labs“. Jis taip pat turi telekomunikacijų pramonės patirties.

Ištekliai

  • Perskaitykite „Java“ objektų serijos specifikaciją. (Spec yra PDF.)
  • „Išlyginkite savo objektus: atraskite„ Java Serialization API “paslaptis“ (Todd M. Greanier, „JavaWorld“, 2000 m. Liepos mėn.) Siūlo pažvelgti į serijinio proceso veržles ir varžtus.
  • 10 skyrius „Java“ RMI (William Grosso, O'Reilly, 2001 m. Spalio mėn.) Taip pat yra naudinga nuoroda.

Šią istoriją „Atskleistas„ Java “serializavimo algoritmas“ iš pradžių paskelbė „JavaWorld“.