Programmēšana

Atklāts Java serializācijas algoritms

Serializācija ir objekta stāvokļa saglabāšanas process baitu secībā; deserializācija ir šo baitu atjaunošanas process par dzīvo objektu. Java serializācijas API nodrošina standarta mehānismu izstrādātājiem, lai apstrādātu objektu sērijveidošanu. Šajā padomā jūs redzēsiet, kā sērijveidot objektu un kāpēc dažreiz ir nepieciešama serializācija. Uzzināsiet par Java izmantoto sērijas algoritmu un skatiet piemēru, kas ilustrē objekta sērijveida formātu. Līdz brīdim, kad esat pabeidzis, jums vajadzētu būt pārliecinātām par to, kā darbojas serializācijas algoritms un kādas entītijas tiek serializētas kā objekta daļa zemā līmenī.

Kāpēc nepieciešama serializācija?

Mūsdienu pasaulē tipiskai uzņēmuma lietojumprogrammai būs vairāki komponenti, un tā tiks izplatīta dažādās sistēmās un tīklos. Java valodā viss tiek attēlots kā objekti; ja divi Java komponenti vēlas sazināties savā starpā, ir nepieciešams datu apmaiņas mehānisms. Viens veids, kā to panākt, ir noteikt savu protokolu un pārsūtīt objektu. Tas nozīmē, ka saņēmējam ir jāzina protokols, kuru sūtītājs izmanto objekta atkārtotai izveidei, kas ļoti apgrūtinātu sarunu ar trešo pušu komponentiem. Tāpēc objekta pārsūtīšanai starp komponentiem ir nepieciešams vispārējs un efektīvs protokols. Šim nolūkam ir definēta serializācija, un Java komponenti izmanto šo protokolu objektu pārsūtīšanai.

1. attēlā parādīts klienta / servera komunikācijas augsta līmeņa skats, kur objekts tiek pārsūtīts no klienta uz serveri, izmantojot sērijveidu.

1. attēls. Augsta līmeņa serializācijas skats darbībā (noklikšķiniet, lai palielinātu)

Kā sērijveidot objektu

Lai serializētu objektu, jums jāpārliecinās, ka objekta klase ievieš java.io.Serializējams saskarni, kā parādīts 1. sarakstā.

Uzskaitīšana 1. Serializable ieviešana

 importēt java.io.Serializable; klase TestSerial ievieš Serializējamo {publisko baitu versija = 100; publisko baitu skaits = 0; } 

1. sarakstā vienīgais, kas jums bija jādara savādāk, nekā izveidojot normālu klasi, ir java.io.Serializējams interfeiss. The Serializējams interfeiss ir marķiera interfeiss; tā vispār nedeklarē metodes. Tas norāda serializācijas mehānismu, ka klasi var seriālizēt.

Tagad, kad esat padarījis klasi piemērotu serializācijai, nākamais solis ir objekta faktiskā sērijveidošana. Tas tiek darīts, zvanot uz writeObject () metode java.io.ObjectOutputStream klase, kā parādīts 2. sarakstā.

Saraksts 2. Zvanīšana writeObject ()

 public static void main (String args []) izmet IOException {FileOutputStream fos = new FileOutputStream ("temp.out"); ObjectOutputStream oos = jauns ObjectOutputStream (fos); TestSerial ts = jauns TestSerial (); oos.writeObject (ts); oos.skalot (); oos.slēgt (); } 

2. sarakstā tiek saglabāts TestSerial objekts failā ar nosaukumu temp.out. oos.writeObject (ts); faktiski sāk serializācijas algoritmu, kas savukārt raksta objektu temp.out.

Lai atkārtoti izveidotu objektu no pastāvīgā faila, jūs izmantosiet kodu 3. sarakstā.

Saraksts 3. Serializēta objekta atjaunošana

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

3. sarakstā objekta atjaunošana notiek ar oin.readObject () metodes izsaukums. Šīs metodes izsaukums izskata neapstrādātos baitus, kurus mēs iepriekš saglabājām, un izveido aktīvu objektu, kas ir precīza sākotnējā objekta diagrammas kopija. Tā kā readObject () var lasīt jebkuru seriālizējamu objektu, ir nepieciešams nodot pareizajam tipam.

Izpildot šo kodu, tiks izdrukāts versija = 100 par standarta izvadi.

Objekta sērijveida formāts

Kā izskatās objekta sērijveida versija? Atcerieties, ka iepriekšējās sadaļas koda paraugs saglabāja sērijveida versiju TestSerial objektu failā temp.out. 4. sarakstā parādīts temp.out, tiek rādīts heksadecimāli. (Lai redzētu izvadi heksadecimālā formātā, jums ir nepieciešams heksadecimālais redaktors.)

Saraksts 4. TestSerial sešpadsmitā 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. 

Ja paskatās vēlreiz uz faktisko TestSerial objektu, jūs redzēsiet, ka tajā ir tikai divi baitu dalībnieki, kā parādīts 5. sarakstā.

Saraksts 5. TestSerial baitu dalībnieki

 publiskā baita versija = 100; publisko baitu skaits = 0; 

Baitā mainīgā lielums ir viens baits, un tāpēc objekta kopējais lielums (bez galvenes) ir divi baiti. Bet, apskatot sērijveida objekta lielumu 4. sarakstā, jūs redzēsit 51 baitu. Pārsteigums! Kur radās papildu baiti, un kāda ir to nozīme? Tos ievieš serializācijas algoritms, un tie ir nepieciešami, lai objektu no jauna izveidotu. Nākamajā sadaļā jūs detalizēti izpētīsit šo algoritmu.

Java serializācijas algoritms

Tagad jums vajadzētu būt diezgan labām zināšanām par to, kā sertificēt objektu. Bet kā process notiek zem pārsega? Parasti serializācijas algoritms rīkojas šādi:

  • Tajā tiek izrakstīti ar instanci saistītās klases metadati.
  • Tā rekursīvi izraksta augstākās klases aprakstu, līdz atrod java.lang.object.
  • Kad metadatu informācija ir pabeigta, tā sākas ar faktiskajiem datiem, kas saistīti ar instanci. Bet šoreiz tas sākas no augstākās superklases.
  • Tas rekursīvi raksta datus, kas saistīti ar gadījumu, sākot no mazākās superklases līdz visvairāk atvasinātajai klasei.

Es šai sadaļai esmu uzrakstījis citu objekta piemēru, kas aptvers visus iespējamos gadījumus. Jaunais seriālizējamais objekta paraugs ir parādīts 6. sarakstā.

Saraksts 6. Serializētā objekta paraugs

 klases vecāks ievieš Serializējamo {int parentVersion = 10; } klase satur rīkus Serializējams {int saturVersion = 11; } publiskā klase SerialTest paplašina vecāku rīkus Serializable {int version = 66; satur con = jauns saturēt (); public int getVersion () {atgriešanās versija; } public static void main (String args []) izmet IOException {FileOutputStream fos = new FileOutputStream ("temp.out"); ObjectOutputStream oos = jauns ObjectOutputStream (fos); SerialTest st = jauns SerialTest (); oos.writeObject (st); oos.skalot (); oos.slēgt (); }} 

Šis piemērs ir vienkāršs. Tas serializē tipa objektu SerialTest, kas atvasināts no vecāks un tam ir konteinera objekts, satur. Šī objekta sērijveida formāts ir parādīts 7. sarakstā.

Saraksts 7. Objekta parauga sērijas forma

 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. attēlā ir piedāvāts augsta līmeņa skatījums uz šī scenārija serializācijas algoritmu.

2. attēls. Serializācijas algoritma izklāsts

Apskatīsim detalizēti objekta sērijveida formātu un redzēsim, ko katrs baits pārstāv. Sāciet ar informāciju par serializācijas protokolu:

  • AC ED: STREAM_MAGIC. Norāda, ka tas ir serializācijas protokols.
  • 00 05: STREAM_VERSION. Serializācijas versija.
  • 0x73: TC_OBJECT. Norāda, ka tas ir jauns Objekts.

Serializācijas algoritma pirmais solis ir rakstīt klases aprakstu, kas saistīts ar instanci. Piemērs sērijveidā tipa objektu SerialTest, tāpēc algoritms sākas, uzrakstot SerialTest klasē.

  • 0x72: TC_CLASSDESC. Norāda, ka šī ir jauna klase.
  • 00 0A: Klases nosaukuma garums.
  • 53 65 72 69 61 6c 54 65 73 74: SerialTest, klases nosaukums.
  • 05 52 81 5A AC 66 02 F6: SerialVersionUID, šīs klases sērijas versijas identifikators.
  • 0x02: Dažādi karogi. Šis konkrētais karodziņš saka, ka objekts atbalsta serializāciju.
  • 00 02: Lauku skaits šajā klasē.

Pēc tam algoritms raksta lauku int versija = 66;.

  • 0x49: Lauka tipa kods. 49 apzīmē "I", kas apzīmē Int.
  • 00 07: Lauka nosaukuma garums.
  • 76 65 72 73 69 6F 6E: versija, lauka nosaukums.

Un tad algoritms raksta nākamo lauku, satur con = jauns saturēt ();. Šis ir objekts, tāpēc tas uzrakstīs šī lauka kanonisko JVM parakstu.

  • 0x74: TC_STRING. Pārstāv jaunu virkni.
  • 00 09: Virknes garums.
  • 4C 63 6F 6E 74 61 69 6E 3B: Lkonteins;, kanoniskais JVM paraksts.
  • 0x78: TC_ENDBLOCKDATA, objekta izvēles bloķēšanas datu beigas.

Nākamais algoritma solis ir rakstīt aprakstu vecāks klase, kas ir tiešā klases augstākā klase SerialTest.

  • 0x72: TC_CLASSDESC. Norāda, ka šī ir jauna klase.
  • 00 06: Klases nosaukuma garums.
  • 70 61 72 65 6E 74: SerialTest, klases nosaukums
  • 0E DB D2 BD 85 EE 63 7A: SerialVersionUID, šīs klases sērijas versijas identifikators.
  • 0x02: Dažādi karogi. Šis karodziņš atzīmē, ka objekts atbalsta serializāciju.
  • 00 01: Lauku skaits šajā klasē.

Tagad algoritms uzrakstīs lauka aprakstu vecāks klasē. vecāks ir viens lauks, int parentVersion = 100;.

  • 0x49: Lauka tipa kods. 49 apzīmē "I", kas apzīmē Int.
  • 00 0D: Lauka nosaukuma garums.
  • 70 61 72 65 6E 74 56 65 72 73 69 6F 6E: parentVersion, lauka nosaukums.
  • 0x78: TC_ENDBLOCKDATA, šī objekta bloku datu beigas.
  • 0x70: TC_NULL, kas apzīmē faktu, ka vairs nav nevienas superklases, jo esam sasnieguši klases hierarhijas augšdaļu.

Līdz šim serializācijas algoritms ir uzrakstījis klases aprakstu, kas saistīts ar instanci un visām tās superklasēm. Pēc tam tā uzrakstīs faktiskos datus, kas saistīti ar gadījumu. Vispirms tā raksta vecāku klases locekļus:

  • 00 00 00 0A: 10, vērtība parentVersion.

Tad tas pāriet uz SerialTest.

  • 00 00 00 42: 66, vērtība versija.

Daži nākamie baiti ir interesanti. Algoritmam ir jāuzraksta informācija par satur objekts, parādīts 8. sarakstā.

Saraksts 8. Objekts satur

 satur con = jauns saturēt (); 

Atcerieties, ka serializācijas algoritms nav uzrakstījis klases aprakstu satur klase vēl. Šī ir iespēja uzrakstīt šo aprakstu.

  • 0x73: TC_OBJECT, apzīmējot jaunu objektu.
  • 0x72: TC_CLASSDESC.
  • 00 07: Klases nosaukuma garums.
  • 63 6F 6E 74 61 69 6E: satur, klases nosaukums.
  • FC BB E6 0E FB CB 60 C7: SerialVersionUID, šīs klases sērijas versijas identifikators.
  • 0x02: Dažādi karogi. Šis karodziņš norāda, ka šī klase atbalsta serializāciju.
  • 00 01: Lauku skaits šajā klasē.

Pēc tam algoritmam ir jāuzraksta apraksts saturvienīgais lauks, int saturVersija = 11;.

  • 0x49: Lauka tipa kods. 49 apzīmē "I", kas apzīmē Int.
  • 00 0E: Lauka nosaukuma garums.
  • 63 6F 6E 74 61 69 6E 56 65 72 73 69 6F 6E: includeVersion, lauka nosaukums.
  • 0x78: TC_ENDBLOCKDATA.

Tālāk serializācijas algoritms pārbauda, ​​vai satur ir kādas vecāku klases. Ja tā būtu, algoritms sāktu rakstīt šo klasi; bet šajā gadījumā nav superklases satur, tāpēc raksta algoritms TC_NULL.

  • 0x70: TC_NULL.

Visbeidzot, algoritms raksta faktiskos datus, kas saistīti ar satur.

  • 00 00 00 0B: 11, vērtība includeVersion.

Secinājums

Šajā padomā jūs esat redzējis, kā sertificēt objektu, un uzzinājāt, kā detalizēti darbojas serializācijas algoritms. Es ceru, ka šis raksts sniedz jums sīkāku informāciju par to, kas notiek, kad objektu faktiski sērijveida.

Par autoru

Sathiskumar Palaniappan ir vairāk nekā četru gadu pieredze IT nozarē, un viņš vairāk nekā trīs gadus strādā ar Java saistītām tehnoloģijām. Pašlaik viņš strādā kā sistēmas programmatūras inženieris Java tehnoloģiju centrā, IBM Labs. Viņam ir arī pieredze telekomunikāciju nozarē.

Resursi

  • Izlasiet Java objektu sērijas specifikāciju. (Spec ir PDF.)
  • "Saplaciniet savus objektus: atklājiet Java serializācijas API noslēpumus" (Todd M. Greanier, JavaWorld, 2000. gada jūlijs) piedāvā ieskatu sērijas procesa uzgriežņos un skrūvēs.
  • 10. Nodaļa Java RMI (William Grosso, O'Reilly, 2001. gada oktobris) ir arī noderīga atsauce.

Šo stāstu "Atklāts Java sērijas algoritms" sākotnēji publicēja JavaWorld.

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