Serializare în Java
Serializarea este procesul de salvare de stat unui obiect la o secvență de octeți; deserializarea este procesul de restabilire a obiectului acestor octeți. Java serializare API oferă un mecanism standard pentru crearea obiectelor serializate. În acest articol, veți vedea cum să serializa un obiect, și de ce serializare este uneori necesar. Vei invata despre algoritmul serializare utilizat în Java și a vedea un exemplu care ilustrează formatul obiect serializat. La final ar trebui să aveți o idee clară a modului în care funcționează algoritmul serializare, precum și modul în care o parte a obiectului reprezentat într-o formă serializate.
De ce serializarea nevoie?
În lumea de astăzi, o aplicație tipică industrială va avea mai multe componente și vor fi distribuite printr-o varietate de sisteme și rețele. În Java, toate reprezentate ca obiecte; În cazul în care cele două componente Java trebuie să comunice unul cu celălalt, au nevoie de un mecanism de comunicare. Există mai multe modalități de a pune în aplicare acest mecanism. Prima cale este de a dezvolta un protocol de proprietate și să treacă un obiect. Acest lucru înseamnă că destinatarul trebuie să cunoască protocolul utilizat de către expeditor pentru a re-crea obiectul, ceea ce complică dezvoltarea componentelor terțe părți. Prin urmare, acesta trebuie să fie de protocol versatil și eficient de a transfera obiecte între componente. Serializare este creat în acest scop, precum și componente Java utilizează acest protocol pentru a transfera obiecte.
Cum serializa un obiect?
Pentru a începe, asigurați-vă că clasa obiect serializat implementează interfața java.io.Serializable așa cum se arată în Listarea 1.
clasa TestSerial implementeaza Serializable versiune octet publice = 100;
număr de octeți publice = 0;
>
* Acest cod sursă a fost evidențiată cu codul sursă Marcatorul.
În Listarea 1, singurul lucru diferit de la crearea unei clase normale este implementeze interfata java.io.Serializable. interfață serializabilă este o interfață de marcare; în ea nu este declarată o singură metodă. Acesta spune mecanismul de serializare care clasa poate fi serializat.
Acum avem tot ce ai nevoie pentru a serializa un obiect, pasul următor este serializarea obiect real. Aceasta se face prin apelarea writeObject (clasa java.io.ObjectOutputStream). așa cum se arată în Listarea 2.
statice void main (String args []) publice aruncă IOException FileOutputStream FOS = new FileOutputStream ( "temp.out");
ObjectOutputStream OOS = new ObjectOutputStream (FOS);
TestSerial ts = new TestSerial ();
oos.writeObject (ts);
oos.flush ();
oos.close ();
>
* Acest cod sursă a fost evidențiată cu codul sursă Marcatorul.
Listarea 2 prezintă un exemplu de conservare de stat TestSerial un fișier numit temp.out
Pentru a re-crea obiect dintr-un fișier, trebuie să utilizați codul din listingul 3.
statice void main (String args []) publice aruncă IOException FileInputStream fls = new FileInputStream ( "temp.out");
ObjectInputStream oin = new ObjectInputStream (fls);
TestSerial ts = (TestSerial) oin.readObject ();
Sistem. out .println ( "versiune =" + ts.version);
>
* Acest cod sursă a fost evidențiată cu codul sursă Marcatorul.
Restaurarea obiectului are loc prin intermediul oin.readObject metoda de apel (). Apelul metodei citește octeți din fișier și creează o copie exactă a graficului obiectului original. oin.readObject () se poate citi orice obiect serializate, prin urmare, este necesar obținut obiectul ar conduce la un anumit tip.
Finalizarea cod va versiune = 100 la ieșirea standard.
Formatul unui obiect serializat
Cum ar trebui să arate ca un obiect serializat? Gândiți-vă la un simplu cod din secțiunea anterioară, care TestSerial opoziție și scrie temp.out. Listarea 4 arată conținutul temp.out. în hexazecimal.
AC ED 00 05 73 72 00 0A 65 72 69 53 61 54 65 6C
73 74 A0 0C 34 00 FE B1 DD F9 00 02 42 02 00 05
63 6F 74 42 6E 75 00 07 76 65 72 73 69 78 6F 6E
70 00 64
Dacă te uiți înapoi la TestSerial. veți vedea că el are doar 2 membru octet. Așa cum se arată în exemplul 5.
Versiunea octet publică = 100;
număr de octeți publice = 0;
* Acest cod sursă a fost evidențiată cu codul sursă Marcatorul.
Byte variabilă dimensiune un octet, și deci completați dimensiunea obiectului (fără antet) - doi octeți. Dar dimensiunea obiectului serializat 51 bytes. Surprins? De unde acești octeți în plus și ceea ce reprezintă? Ei au adăugat algoritmul serializare, și necesitatea de a re-crea obiectul. În paragraful următor, acest algoritm va fi descris în detaliu.
Algoritmul serializare Java
În acest moment, ar trebui să aveți suficiente cunoștințe pentru a serializa un obiect. Dar cum funcționează acest mecanism? Algoritmul serializarea face următoarele lucruri:
- Înregistrarea metadate despre clasa asociată cu obiectul
- intrare recursive descrie superclasele până când se ajunge java.lang.Object
- după sfârșitul înregistrării de metadate începe să înregistreze datele reale asociate cu instanta, numai de data înregistrarea pornește de la partea de sus a superclasei
- înregistrare de date recursiv asociate cu o copie de la cea mai mică dintre superclasa
Listarea 6 prezintă un exemplu de care să acopere toate cazurile posibile de serializare
clasă părinte implementează Serializable int parentVersion = 10;
>
class conțin implementează Serializable int containVersion = 11;
>
public class SerialTest extinde părinte implementează versiunea int Serializable = 66;
conțin con = nou conțin ();
getVersion public int () versiune retur;
>
statice void main (String args []) publice aruncă IOException FileOutputStream FOS = new FileOutputStream ( "temp.out");
ObjectOutputStream OOS = new ObjectOutputStream (FOS);
SerialTest st = new SerialTest ();
oos.writeObject (st);
oos.flush ();
oos.close ();
>
>
* Acest cod sursă a fost evidențiată cu codul sursă Marcatorul.
Exemplul SerialTest serializate clasă de obiecte. care este moștenită de la mamă și cuprinde o clasă de obiecte container conțin. Listarea 7 arată obiectul serializat.
AC ED 00 05 73 72 00 0A 65 72 69 53 61 54 65 6C
73 74 05 52 81 66 02 5A AC F6 02 00 02 49 00 07
76 65 72 73 69 6E 6E 4C 00 03 63 6E 6E 74 00 09
63 4C 6F 74 61 69 6E 6E 3B 72 00 06 78 70 61 72
65 6E 74 0E DB D2 BD EE 85 63 7A 00 01 49 02 00
0D 61 72 65 70 6E 74 56 65 72 73 69 78 70 6E 6E
00 00 00 00 00 0A 42 00 73 72 00 07 63 6F 6E 74
61 69 6E FC BB E6 0E FB 60 CB C7 02 00 01 49 00
63 0E 74 61 6E 69 56 65 6E 6E 72 73 69 6F 6E 78
70 00 00 00 0B
Să ne uităm la ceea ce reprezintă fiecare octet în obiectul serializat. La început există o informație de protocol serializare:
- AC ED: STREAM_MAGIC. Spune că protocolul folosit seriazizatsii.
- 00 05: STREAM_VERSION. Versiunea serializarea.
- 0x73: TC_OBJECT. Desemnarea noului obiect.
În primul algoritm pas serializare înregistrează descrierea clasei asociate cu obiectul. Exemplul a fost serializat clasă de obiecte SerialTest. Prin urmare, algoritmul a început înregistrarea descriere clasa SerailTest.
- 0x72: TC_CLASSDESC. Marcarea o nouă clasă.
- 00 0A. Lungimea numelui clasei.
- 53 65 72 69 61 6c 54 65 73 74: SerialTest. numele clasei.
- 05 52 81 66 02 5A AC F6: SerialVersionUID. identificator de clasă.
- 0x02. Diverse steaguri. Acest steag special indică faptul că obiectul sprijină serializare.
- 00 02. Numărul de câmpuri din clasa.
Acum înregistrări algoritm câmp versiunea int = 66; .
- 0x49. Câmpul de cod de tip. 49 este «eu», care reprezintă Int.
- 00 07. Lungimea numelui câmpului.
- 76 65 72 73 69 6F 6E: versiune. nume de câmp.
Algoritmul apoi scrie următorul câmp, conțin con = nou conțin ();. Prin urmare, este un obiect de desemnare JVM canonică a acestui câmp va fi înregistrată.
- 0x74: TC_STRING. Aceasta indică o nouă linie.
- 00 09. Lungimea șir.
- 4C 6F 63 74 61 6E 69 6E 3B: Lcontain;. JVM semnătură Canonical.
- 0x78: TC_ENDBLOCKDATA. bloc final opțional de date pentru obiect.
Următorul pas al algoritmului este părinte înregistrare clasa definiție. care este o SerialTest superclasa directă.
- 0x72: TC_CLASSDESC. Marcarea o nouă clasă.
- 00 06. Lungimea numele clasei.
- 61 72 65 70 6E 74: părinte. numele clasei
- 0E DB D2 BD 85 63 EE 7A: SerialVersionUID. identificator de clasă.
- 0x02. Diverse steaguri. Acest pavilion indică faptul că clasa acceptă serializare.
- 00 01. Numărul de câmpuri din clasa.
Acum, algoritmul scrie parentali câmpurile clasa descriere. clasă are un singur domeniu, int parentVersion = 100; .
- 0x49. Câmpul de cod de tip. 49 semnifică «I», care este ancorat în Int.
- 00 0D. Lungimea numelui câmpului.
- 61 72 65 70 6E 74 56 65 72 73 69 6F 6E. parentVersion, numele câmpului.
- 0x78: TC_ENDBLOCKDATA. bloc final opțional de date pentru obiect.
- 0x70: TC_NULL. Aceasta se referă la faptul că nu există mai multe superclase pentru că am ajuns în vârful ierarhiei de clasă.
Înainte de aceasta, algoritmul serializare a înregistrat o descriere a claselor asociate cu obiectul și toate superclasele sale. Acum, datele reale asociate cu obiectul care urmează să fie înregistrate. a înregistrat primii membri ai societății-mamă de clasă:
- 00 00 00 0A: 10. Valoarea parentVersion.
Apoi ne-am mutat în SerialTest
- 00 00 00 42: 66. Valoarea versiunii.
Următorii câțiva octeți sunt foarte interesante. Algoritmul trebuie să scrie informații pentru a conține un obiect de clasă.
conțin con = nou conțin ();
* Acest cod sursă a fost evidențiată cu codul sursă Marcatorul.
Algoritmul serializarea nu a înregistrat o descriere a clasei conțin. În momentul în care a ajuns să facă acest lucru.
- 0x73: TC_OBJECT. denotă un nou obiect.
- 0x72: TC_CLASSDESC. reprezintă o nouă clasă.
- 00 07. Lungimea numele clasei.
- 63 6F 74 61 69 6E 6E: conțin. numele clasei.
- FC BB E6 0E FB 60 CB C7: SerialVersionUID. ID-ul pentru această clasă.
- 0x02. Diverse steaguri. Acest pavilion indică faptul că clasa acceptă serializare.
- 00 01. Numărul de câmpuri din clasa.
Algoritmul ar trebui să fie scris numai clasa descriere câmp conatin, int containVersion = 11; .
- 0x49. Câmpul de cod de tip. 49 semnifică «I», care este ancorat în Int.
- 00 0E. Lungimea numelui câmpului.
- 63 6F 74 61 69 6E 6E 56 65 72 73 69 6F 6E: containVersion. nume de câmp.
- 0x78: TC_ENDBLOCKDATA. bloc final opțional de date pentru obiect.
În continuare, algoritmul verifică pentru a vedea dacă conține clasa părinte are. În acest caz, algoritmul începe să înregistreze în această clasă; dar, în acest caz, pentru superclasa conțin nu, TC_NULL înregistrări algoritm.
În cele din urmă, algoritmul înregistrează datele reale asociate cu conatin clasă de obiecte.
- 00 00 00 0B: 11. importanță containVersion.