Programmering

Java-serialiseringsalgoritmen avslørt

Serialisering er prosessen med å lagre et objekts tilstand i en sekvens av byte; deserialisering er prosessen med å gjenoppbygge disse bytene til et levende objekt. Java Serialization API gir en standardmekanisme for utviklere å håndtere objektserialisering. I dette tipset vil du se hvordan du kan serieisere et objekt, og hvorfor det noen ganger er nødvendig med serialisering. Du lærer om serialiseringsalgoritmen som brukes i Java, og ser et eksempel som illustrerer serieobjektet til et objekt. Når du er ferdig, bør du ha solid kunnskap om hvordan serialiseringsalgoritmen fungerer og hvilke enheter som er seriell som en del av objektet på et lavt nivå.

Hvorfor kreves serialisering?

I dagens verden vil en typisk bedriftsapplikasjon ha flere komponenter og vil bli distribuert over forskjellige systemer og nettverk. I Java er alt representert som objekter; hvis to Java-komponenter vil kommunisere med hverandre, må det være en mekanisme for å utveksle data. En måte å oppnå dette på er å definere din egen protokoll og overføre et objekt. Dette betyr at mottakersiden må kjenne protokollen som brukes av avsenderen for å gjenopprette objektet, noe som vil gjøre det veldig vanskelig å snakke med tredjepartskomponenter. Derfor må det være en generell og effektiv protokoll for å overføre objektet mellom komponenter. Serialisering er definert for dette formålet, og Java-komponenter bruker denne protokollen til å overføre objekter.

Figur 1 viser et høynivå av klient / server-kommunikasjon, der et objekt overføres fra klienten til serveren gjennom serialisering.

Figur 1. Et høynivå av serieisering i aksjon (klikk for å forstørre)

Hvordan serieisere et objekt

For å serieisere et objekt, må du sørge for at klassen til objektet implementerer java.io Serialiserbar grensesnitt, som vist i liste 1.

Oppføring 1. Implementering Serializable

 importere java.io.Serializable; klasse TestSerial implementerer Serializable {public byte version = 100; antall byte = 0; } 

I Listing 1 er det eneste du måtte gjøre annerledes enn å lage en normal klasse å implementere java.io Serialiserbar grensesnitt. De Serialiserbar grensesnitt er et markørgrensesnitt; det erklærer ingen metoder i det hele tatt. Den forteller serieiseringsmekanismen at klassen kan serieiseres.

Nå som du har gjort klassen kvalifisert for serialisering, er neste trinn å faktisk serieisere objektet. Det gjøres ved å ringe writeObject () metoden for java.io.ObjectOutputStream klasse, som vist i oppføring 2.

Oppføring 2. Anrop til writeObject ()

 public static void main (String args []) kaster IOException {FileOutputStream fos = ny FileOutputStream ("temp.out"); ObjectOutputStream oos = ny ObjectOutputStream (fos); TestSerial ts = ny TestSerial (); oos.writeObject (ts); oos.flush (); oos.close (); } 

Oppføring 2 lagrer tilstanden til TestSerie objekt i en fil som heter temp. ut. oos.writeObject (ts); sparker faktisk i gang serialiseringsalgoritmen, som igjen skriver objektet til temp. ut.

For å gjenopprette objektet fra den vedvarende filen, bruker du koden i Listing 3.

Oppføring 3. Gjenopprette et serieobjekt

 public static void main (String args []) kaster IOException {FileInputStream fis = new FileInputStream ("temp.out"); ObjectInputStream oin = ny ObjectInputStream (fis); TestSerial ts = (TestSerial) oin.readObject (); System.out.println ("versjon =" + ts.versjon); } 

I oppføring 3 skjer gjenopprettingen av objektet med oin.readObject () metodeanrop. Denne metoden kalles i råbyte som vi tidligere vedvarte, og skaper et levende objekt som er en nøyaktig kopi av den opprinnelige objektgrafen. Fordi readObject () kan lese hvilket som helst serieobjekt, en rollebesetning av riktig type kreves.

Å utføre denne koden vil skrives ut versjon = 100 på standardutgangen.

Serien formatet på et objekt

Hvordan ser den serielle versjonen av objektet ut? Husk at eksempelkoden i forrige avsnitt lagret den serielle versjonen av TestSerie objekt inn i filen temp. ut. Oppføring 4 viser innholdet i temp. ut, vises i heksadesimal. (Du trenger et heksadesimalt redigeringsprogram for å se utdataene i heksadesimalt format.)

Oppføring 4. Heksadesimal form for 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 

Hvis du ser igjen på selve TestSerie objekt, ser du at den bare har to byte-medlemmer, som vist i oppføring 5.

Oppføring 5. TestSerials byte-medlemmer

 offentlig byteversjon = 100; antall byte = 0; 

Størrelsen på en bytevariabel er en byte, og dermed er den totale størrelsen på objektet (uten overskriften) to byte. Men hvis du ser på størrelsen på det serialiserte objektet i Listing 4, ser du 51 byte. Overraskelse! Hvor kom de ekstra byte fra, og hva er deres betydning? De introduseres av serialiseringsalgoritmen, og er nødvendige for å gjenopprette objektet. I neste avsnitt vil du utforske denne algoritmen i detalj.

Java's serialiseringsalgoritme

Nå skal du ha ganske god kunnskap om hvordan du serierer et objekt. Men hvordan fungerer prosessen under panseret? Generelt gjør serialiseringsalgoritmen følgende:

  • Det skriver ut metadataene til klassen som er knyttet til en forekomst.
  • Den skriver rekursivt ut beskrivelsen av superklassen til den finner java.lang.object.
  • Når den er ferdig med å skrive metadatainformasjonen, starter den med de faktiske dataene som er knyttet til forekomsten. Men denne gangen starter den fra den øverste superklassen.
  • Den skriver dataene som er knyttet til forekomsten rekursivt, fra den minste superklassen til den mest avledede klassen.

Jeg har skrevet et annet eksempelobjekt for denne delen som vil dekke alle mulige tilfeller. Det nye prøveobjektet som skal serieiseres, vises i Listing 6.

Oppføring 6. Eksempel på serieobjekt

 klasseforeldre implementerer Serialiserbar {int parentVersion = 10; } klasse inneholder redskaper Serialiserbare {int containVersion = 11; } offentlig klasse SerialTest utvider foreldreverktøy Serialiserbar {int versjon = 66; inneholder con = nytt inneholder (); public int getVersion () {returversjon; } offentlig statisk ugyldig hoved (String args []) kaster IOException {FileOutputStream fos = ny FileOutputStream ("temp.out"); ObjectOutputStream oos = ny ObjectOutputStream (fos); SerialTest st = ny SerialTest (); oos.writeObject (st); oos.flush (); oos.close (); }} 

Dette eksemplet er enkelt. Den serielliserer et objekt av typen SerialTest, som er avledet fra foreldre og har en containerobjekt, inneholde. Det serielle formatet til dette objektet er vist i Listing 7.

Oppføring 7. Seriell form for prøveobjekt

 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 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 0B 

Figur 2 gir et høynivå på serialiseringsalgoritmen for dette scenariet.

Figur 2. En oversikt over serialiseringsalgoritmen

La oss gå gjennom det serieformerte objektet i detalj og se hva hver byte representerer. Begynn med informasjon om serialiseringsprotokollen:

  • AC ED: STREAM_MAGIC. Spesifiserer at dette er en serieprotokoll.
  • 00 05: STREAM_VERSION. Serialiseringsversjonen.
  • 0x73: TC_OBJECT. Spesifiserer at dette er en ny Gjenstand.

Det første trinnet i serialiseringsalgoritmen er å skrive beskrivelsen av klassen som er knyttet til en forekomst. Eksemplet serialiserer et objekt av typen SerialTest, så algoritmen starter med å skrive beskrivelsen av SerialTest klasse.

  • 0x72: TC_CLASSDESC. Spesifiserer at dette er en ny klasse.
  • 00 0A: Lengden på kursnavnet.
  • 53 65 72 69 61 6c 54 65 73 74: SerialTest, navnet på klassen.
  • 05 52 81 5A AC 66 02 F6: SerialVersionUID, den serielle versjonsidentifikatoren for denne klassen.
  • 0x02: Ulike flagg. Dette bestemte flagget sier at objektet støtter serialisering.
  • 00 02: Antall felt i denne klassen.

Deretter skriver algoritmen feltet int versjon = 66;.

  • 0x49: Feltypekode. 49 representerer "jeg", som står for Int.
  • 00 07: Lengde på feltnavnet.
  • 76 65 72 73 69 6F 6E: versjon, navnet på feltet.

Og så skriver algoritmen det neste feltet, inneholder con = nytt inneholder ();. Dette er et objekt, så det vil skrive den kanoniske JVM-signaturen til dette feltet.

  • 0x74: TC_STRING. Representerer en ny streng.
  • 00 09: Strengens lengde.
  • 4C 63 6F 6E 74 61 69 6E 3B: Lcontain;, den kanoniske JVM-signaturen.
  • 0x78: TC_ENDBLOCKDATA, slutten på valgfrie blokkeringsdata for et objekt.

Det neste trinnet i algoritmen er å skrive beskrivelsen av foreldre klasse, som er den umiddelbare superklassen til SerialTest.

  • 0x72: TC_CLASSDESC. Spesifiserer at dette er en ny klasse.
  • 00 06: Lengden på kursnavnet.
  • 70 61 72 65 6E 74: SerialTest, navnet på klassen
  • 0E DB D2 BD 85 EE 63 7A: SerialVersionUID, identifikatoren for serieversjonen av denne klassen.
  • 0x02: Ulike flagg. Dette flagget bemerker at objektet støtter serialisering.
  • 00 01: Antall felt i denne klassen.

Nå vil algoritmen skrive feltbeskrivelsen for foreldre klasse. foreldre har ett felt, int parentVersion = 100;.

  • 0x49: Feltypekode. 49 representerer "jeg", som står for Int.
  • 00 0D: Lengde på feltnavnet.
  • 70 61 72 65 6E 74 56 65 72 73 69 6F 6E: foreldreversjon, navnet på feltet.
  • 0x78: TC_ENDBLOCKDATA, slutten på blokkeringsdata for dette objektet.
  • 0x70: TC_NULL, som representerer det faktum at det ikke er flere superklasser fordi vi har nådd toppen av klassehierarkiet.

Så langt har serialiseringsalgoritmen skrevet beskrivelsen av klassen som er knyttet til forekomsten og alle dens superklasser. Deretter vil den skrive de faktiske dataene som er knyttet til forekomsten. Det skriver foreldreklassemedlemmene først:

  • 00 00 00 0A: 10, verdien av foreldreversjon.

Så går det videre til SerialTest.

  • 00 00 00 42: 66, verdien av versjon.

De neste byte er interessante. Algoritmen må skrive informasjonen om inneholde objekt, vist i oppføring 8.

Oppføring 8. Inneholde objektet

 inneholder con = nytt inneholder (); 

Husk at serialiseringsalgoritmen ikke har skrevet klassebeskrivelsen for inneholde klasse ennå. Dette er muligheten til å skrive denne beskrivelsen.

  • 0x73: TC_OBJECT, betegner et nytt objekt.
  • 0x72: TC_CLASSDESC.
  • 00 07: Lengden på kursnavnet.
  • 63 6F 6E 74 61 69 6E: inneholde, navnet på klassen.
  • FC BB E6 0E FB CB 60 C7: SerialVersionUID, den serielle versjonsidentifikatoren for denne klassen.
  • 0x02: Ulike flagg. Dette flagget indikerer at denne klassen støtter serialisering.
  • 00 01: Antall felt i denne klassen.

Deretter må algoritmen skrive beskrivelsen for inneholdeeneste felt, int containVersion = 11;.

  • 0x49: Feltypekode. 49 representerer "jeg", som står for Int.
  • 00 0E: Lengde på feltnavnet.
  • 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E: containVersion, navnet på feltet.
  • 0x78: TC_ENDBLOCKDATA.

Deretter sjekker serialiseringsalgoritmen for å se om inneholde har foreldreklasser. Hvis det gjorde det, ville algoritmen begynne å skrive den klassen; men i dette tilfellet er det ingen superklasse for inneholde, så skriver algoritmen TC_NULL.

  • 0x70: TC_NULL.

Til slutt skriver algoritmen de faktiske dataene som er knyttet til inneholde.

  • 00 00 00 0B: 11, verdien av containVersion.

Konklusjon

I dette tipset har du sett hvordan du kan serieisere et objekt, og lært hvordan serialiseringsalgoritmen fungerer i detalj. Jeg håper denne artikkelen gir deg mer detaljer om hva som skjer når du faktisk serialiserer et objekt.

Om forfatteren

Sathiskumar Palaniappan har mer enn fire års erfaring i IT-bransjen, og har jobbet med Java-relaterte teknologier i mer enn tre år. For tiden jobber han som systemprogramvareingeniør ved Java Technology Center, IBM Labs. Han har også erfaring innen telekombransjen.

Ressurser

  • Les spesifikasjonen for Java-seriens seriellisering. (Spec er en PDF.)
  • "Flate objektene dine: Oppdag hemmelighetene til Java Serialization API" (Todd M. Greanier, JavaWorld, juli 2000) gir et innblikk i mutter og skruer i serieiseringsprosessen.
  • Kapittel 10 av Java RMI (William Grosso, O'Reilly, oktober 2001) er også en nyttig referanse.

Denne historien, "Java-serialiseringsalgoritmen avslørt", ble opprinnelig utgitt av JavaWorld.

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