Programiranje

Razkrit je algoritem za serializacijo Java

Serializacija je postopek shranjevanja stanja predmeta v zaporedje bajtov; deserializacija je postopek obnove teh bajtov v živi objekt. API za serializacijo Java zagotavlja standardni mehanizem za razvijalce za obdelavo serializacije objektov. V tem nasvetu boste videli, kako serializirati predmet in zakaj je včasih potrebna serializacija. Spoznali boste algoritem za serializacijo, ki se uporablja v Javi, in si ogledali primer, ki prikazuje serializirano obliko predmeta. Ko končate, bi morali že dobro poznati, kako deluje algoritem serializacije in katere entitete so serializirane kot del predmeta na nizki ravni.

Zakaj je potrebna serializacija?

V današnjem svetu bo tipična poslovna aplikacija imela več komponent in bo porazdeljena po različnih sistemih in omrežjih. V Javi je vse predstavljeno kot predmeti; če hočeta dve komponenti Java komunicirati med seboj, obstaja mehanizem za izmenjavo podatkov. Eden od načinov, kako to doseči, je določitev lastnega protokola in prenos predmeta. To pomeni, da mora prejemni konec poznati protokol, ki ga je pošiljatelj uporabil za ponovno ustvarjanje predmeta, kar bi zelo otežilo pogovor s komponentami drugih proizvajalcev. Zato mora obstajati generičen in učinkovit protokol za prenos predmeta med komponentami. V ta namen je definirana serializacija, komponente Java pa uporabljajo ta protokol za prenos predmetov.

Slika 1 prikazuje pogled komunikacije odjemalec / strežnik na visoki ravni, kjer se objekt s serializacijo prenese iz odjemalca na strežnik.

Slika 1. Pogled na serializacijo na visoki ravni (kliknite za povečavo)

Kako serializirati predmet

Če želite objekt serializirati, morate zagotoviti, da razred predmeta izvaja java.io.Serializable vmesnik, kot je prikazano v seznamu 1.

Seznam 1. Implementacija serializiranega

 import java.io.Serializable; razred TestSerial izvaja Serializable {različica javnega bajta = 100; število javnih bajtov = 0; } 

V seznamu 1 je edina stvar, ki ste jo morali storiti drugače kot pri ustvarjanju običajnega razreda, izvedba java.io.Serializable vmesnik. The Serializabilno vmesnik je označevalni vmesnik; izjavlja, da sploh ni nobenih metod. Sporoča mehanizmu serializacije, da je razred mogoče serializirati.

Zdaj, ko ste razred naredili primernim za serializacijo, je naslednji korak dejansko serializiranje predmeta. To se naredi s klicem writeObject () metoda java.io.ObjectOutputStream razreda, kot je prikazano na seznamu 2.

Seznam 2. Klicanje writeObject ()

 public static void main (String args []) vrže IOException {FileOutputStream fos = new FileOutputStream ("temp.out"); ObjectOutputStream oos = nov ObjectOutputStream (fos); TestSerial ts = novo TestSerial (); oos.writeObject (ts); oos.flush (); oos.close (); } 

Seznam 2 shranjuje stanje TestSerial predmet v datoteki z imenom temp.out. oos.writeObject (ts); dejansko sproži algoritem serializacije, ki nato zapiše predmet temp.out.

Če želite znova ustvariti predmet iz trajne datoteke, uporabite kodo iz seznama 3.

Seznam 3. Ponovno ustvarjanje serializiranega predmeta

 public static void main (String args []) vrže IOException {FileInputStream fis = new FileInputStream ("temp.out"); ObjectInputStream oin = nov ObjectInputStream (fis); TestSerial ts = (TestSerial) oin.readObject (); System.out.println ("version =" + ts.version); } 

Na seznamu 3 se obnova predmeta izvede z oin.readObject () klic metode. Ta klic metode prebere v surovih bajtih, ki smo jih že vztrajali, in ustvari objekt v živo, ki je natančna kopija izvirnega grafa predmeta. Ker readObject () lahko prebere kateri koli predmet, ki ga je mogoče serirati, je potreben odlit v pravi tip.

Izvedba te kode se natisne različica = 100 na standardni izhod.

Serializirana oblika predmeta

Kako izgleda serializirana različica predmeta? Ne pozabite, da je vzorčna koda v prejšnjem razdelku shranila serializirano različico TestSerial predmet v datoteko temp.out. Seznam 4 prikazuje vsebino temp.out, prikazano v šestnajstiški. (Če želite videti izhod v šestnajstiški obliki, potrebujete šestnajstiški urejevalnik.)

Seznam 4. Šestnajstiška oblika TestSerial

 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 

Če še enkrat pogledate dejansko TestSerial objekt, boste videli, da ima le dva bajtna člana, kot je prikazano na seznamu 5.

Seznam 5. Člani bajta TestSerial

 različica javnega bajta = 100; število javnih bajtov = 0; 

Velikost bajtne spremenljivke je en bajt, zato je skupna velikost predmeta (brez glave) dva bajta. Če pa pogledate velikost zaporednega predmeta v seznamu 4, boste videli 51 bajtov. Presenečenje! Od kod odvečni bajti in kakšen je njihov pomen? Uvede jih algoritem za serializacijo in so potrebni za ponovno ustvarjanje predmeta. V naslednjem razdelku boste podrobno raziskali ta algoritem.

Java-ov algoritem za serializacijo

Do zdaj bi morali že precej dobro vedeti, kako predmet serializirati. Kako pa poteka postopek pod pokrovom motorja? Na splošno algoritem serializacije naredi naslednje:

  • Zapiše metapodatke razreda, povezanega z primerkom.
  • Rekurzivno zapisuje opis superklase, dokler ne najde java.lang.object.
  • Ko konča s pisanjem informacij o metapodatkih, se začne z dejanskimi podatki, povezanimi z primerkom. A tokrat se začne od najvišjega superrazreda.
  • Rekurzivno zapisuje podatke, povezane z primerkom, začenši od najmanj superklase do najbolj izpeljanega razreda.

Za ta odsek sem napisal drug primer predmeta, ki bo zajemal vse možne primere. Novi vzorčni objekt, ki ga je treba serializirati, je prikazan na seznamu 6.

Seznam 6. Vzorec serializiranega predmeta

 razred nadrejeni izvaja Serializable {int parentVersion = 10; } razred vsebuje izvedbe Serializable {int containVersion = 11; } javni razred SerialTest razširja nadrejene izvedbe Serializable {int version = 66; vsebuje con = novo vsebuje (); public int getVersion () {vrnjena različica; } public static void main (String args []) vrže IOException {FileOutputStream fos = new FileOutputStream ("temp.out"); ObjectOutputStream oos = nov ObjectOutputStream (fos); SerialTest st = nov SerialTest (); oos.writeObject (st); oos.flush (); oos.close (); }} 

Ta primer je preprost. Serializira objekt tipa SerialTest, ki izhaja iz starš in ima objekt vsebnika, vsebujejo. Serijska oblika tega predmeta je prikazana na seznamu 7.

Seznam 7. Serializirana oblika vzorčnega predmeta

 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 

Slika 2 ponuja pogled na algoritem serializacije za ta scenarij na visoki ravni.

Slika 2. Oris algoritma serializacije

Podrobno si oglejmo serializirano obliko predmeta in si oglejmo, kaj predstavlja vsak bajt. Začnite z informacijami o protokolu za serializacijo:

  • AC ED: STREAM_MAGIC. Določa, da je to protokol za serializacijo.
  • 00 05: STREAM_VERSION. Različica za serializacijo.
  • 0x73: TC_OBJECT. Določa, da je to novo Predmet.

Prvi korak algoritma za serializacijo je napisati opis razreda, povezanega z primerkom. Primer serializira objekt tipa SerialTest, zato se algoritem začne s pisanjem opisa datoteke SerialTest razred.

  • 0x72: TC_CLASSDESC. Določa, da gre za nov razred.
  • 00 0A: Dolžina imena razreda.
  • 53 65 72 69 61 6c 54 65 73 74: SerialTest, ime predavanja.
  • 05 52 81 5A AC 66 02 F6: SerialVersionUID, identifikator serijske različice tega razreda.
  • 0x02: Različne zastave. Ta posebna zastava pravi, da objekt podpira serializacijo.
  • 00 02: Število polj v tem razredu.

Nato algoritem zapiše polje int različica = 66;.

  • 0x49: Koda vrste polja. 49 predstavlja "Jaz", kar pomeni Int.
  • 00 07: Dolžina imena polja.
  • 76 65 72 73 69 6F 6E: različico, ime polja.

In potem algoritem zapiše naslednje polje, vsebuje con = novo vsebuje ();. To je objekt, zato bo zapisal kanonični podpis JVM tega polja.

  • 0x74: TC_STRING. Predstavlja nov niz.
  • 00 09: Dolžina vrvice.
  • 4C 63 6F 6E 74 61 69 6E 3B: Lcontain;, kanonični podpis JVM.
  • 0x78: TC_ENDBLOCKDATA, konec neobveznih podatkov bloka za objekt.

Naslednji korak algoritma je pisanje opisa starš razred, ki je neposredni superrazred SerialTest.

  • 0x72: TC_CLASSDESC. Določa, da gre za nov razred.
  • 00 06: Dolžina imena razreda.
  • 70 61 72 65 6E 74: SerialTest, ime predavanja
  • 0E DB D2 BD 85 EE 63 7A: SerialVersionUID, identifikator serijske različice tega razreda.
  • 0x02: Različne zastave. Ta zastavica opozarja, da objekt podpira serializacijo.
  • 00 01: Število polj v tem razredu.

Zdaj bo algoritem napisal opis polja za starš razred. starš ima eno polje, int parentVersion = 100;.

  • 0x49: Koda vrste polja. 49 predstavlja "Jaz", kar pomeni Int.
  • 00 0D: Dolžina imena polja.
  • 70 61 72 65 6E 74 56 65 72 73 69 6F 6E: parentVersion, ime polja.
  • 0x78: TC_ENDBLOCKDATA, konec podatkov bloka za ta objekt.
  • 0x70: TC_NULL, kar predstavlja dejstvo, da superrazredov ni več, ker smo dosegli vrh hierarhije razredov.

Doslej je algoritem za serializacijo napisal opis razreda, povezanega z primerkom, in vseh njegovih super razredov. Nato bo zapisal dejanske podatke, povezane z primerkom. Najprej zapiše člane nadrejenega razreda:

  • 00 00 00 0A: 10, vrednost parentVersion.

Potem se premakne na SerialTest.

  • 00 00 00 42: 66, vrednost različico.

Naslednjih nekaj bajtov je zanimivih. Algoritem mora zapisati podatke o vsebujejo objekt, prikazan na seznamu 8.

Seznam 8. Objekt vsebuje

 vsebuje con = novo vsebuje (); 

Ne pozabite, da algoritem za serializacijo ni napisal opisa razreda za vsebujejo razred še. To je priložnost, da napišem ta opis.

  • 0x73: TC_OBJECT, ki označuje nov objekt.
  • 0x72: TC_CLASSDESC.
  • 00 07: Dolžina imena razreda.
  • 63 6F 6E 74 61 69 6E: vsebujejo, ime predavanja.
  • FC BB E6 0E FB CB 60 C7: SerialVersionUID, identifikator serijske različice tega razreda.
  • 0x02: Različne zastave. Ta zastavica pomeni, da ta razred podpira serializacijo.
  • 00 01: Število polj v tem razredu.

Nato mora algoritem napisati opis za vsebujejoedino polje, int containVersion = 11;.

  • 0x49: Koda vrste polja. 49 predstavlja "Jaz", kar pomeni Int.
  • 00 0E: Dolžina imena polja.
  • 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E: vsebujejoVersion, ime polja.
  • 0x78: TC_ENDBLOCKDATA.

Nato algoritem za serializacijo preveri, ali vsebujejo ima kateri koli nadrejeni razred. Če bi se, bi algoritem začel pisati ta razred; vendar v tem primeru ni superklase za vsebujejo, torej algoritem piše TC_NULL.

  • 0x70: TC_NULL.

Končno algoritem zapiše dejanske podatke, povezane z vsebujejo.

  • 00 00 00 0B: 11, vrednost vsebujejoVersion.

Zaključek

V tem nasvetu ste videli, kako serializirati predmet, in se naučili, kako algoritem serializacije podrobno deluje. Upam, da boste v tem članku našli več podrobnosti o tem, kaj se zgodi, ko predmet dejansko serializirate.

O avtorju

Sathiskumar Palaniappan ima več kot štiri leta izkušenj v IT industriji in že več kot tri leta sodeluje s tehnologijami, povezanimi z Javo. Trenutno dela kot inženir sistemske programske opreme v tehnološkem centru Java, IBM Labs. Izkušnje ima tudi v telekomunikacijski industriji.

Viri

  • Preberite specifikacijo serializacije objekta Java. (Spec je PDF.)
  • "Poravnajte svoje predmete: odkrijte skrivnosti API-ja za serializacijo Java" (Todd M. Greanier, JavaWorld, julij 2000) ponuja pogled na matice in postopke procesa serializacije.
  • 10. poglavje Java RMI (William Grosso, O'Reilly, oktober 2001) je tudi koristna referenca.

To zgodbo "Razkrit algoritem serializacije Java" je prvotno objavil JavaWorld.

$config[zx-auto] not found$config[zx-overlay] not found