Uvod u Java serializaciju

1. Uvod

Serijalizacija je pretvorba stanja objekta u bajtni tok; deserializacija čini suprotno. Drugačije rečeno, serializacija je pretvorba Java objekta u statički tok (slijed) bajtova koji se zatim mogu spremiti u bazu podataka ili prenijeti preko mreže.

2. Serijalizacija i deserijalizacija

Postupak serializacije neovisan je o instanci, tj. Objekti se mogu serializirati na jednoj platformi, a deserijalizirati na drugoj. Klase koje ispunjavaju uvjete za serializaciju trebaju implementirati posebno sučelje markeraSerijalizirati.

Oba ObjectInputStream i ObjectOutputStream su razine visoke razine koje se protežu java.io.InputStream i java.io.OutputStream odnosno. ObjectOutputStream može pisati primitivne tipove i grafikone objekata u Izlazni tok kao tok bajtova. Ovi se tokovi mogu naknadno čitati pomoću ObjectInputStream.

Najvažnija metoda u ObjectOutputStream je:

javna konačna void writeObject (Object o) baca IOException;

Koji uzima objekt koji se može serirati i pretvara ga u niz (tok) bajtova. Slično tome, najvažnija metoda u ObjectInputStream je:

javni konačni objekt readObject () baca IOException, ClassNotFoundException;

Koji može pročitati tok bajtova i pretvoriti ga natrag u Java objekt. To se zatim može vratiti na izvorni objekt.

Ilustrirajmo serializaciju s a Osoba razred. Imajte na umu da statička polja pripadaju klasi (za razliku od objekta) i nisu serializirana. Također imajte na umu da možemo koristiti ključnu riječ prolazan zanemarivanje polja klase tijekom serializacije:

javna klasa Osoba implementira Serializable {private static final long serialVersionUID = 1L; static string država = "ITALIJA"; privatno int doba; privatni naziv niza; privremena visina int; // geteri i postavljači}

Test u nastavku prikazuje primjer spremanja objekta tipa Osoba u lokalnu datoteku, a zatim pročitajte ovu vrijednost natrag u:

@Test public void whenSerializingAndDeserializing_ThenObjectIsTheSame () () baca IOException, ClassNotFoundException {Person person = new Person (); person.setAge (20); person.setName ("Joe"); FileOutputStream fileOutputStream = novi FileOutputStream ("yourfile.txt"); ObjectOutputStream objectOutputStream = novi ObjectOutputStream (fileOutputStream); objectOutputStream.writeObject (osoba); objectOutputStream.flush (); objectOutputStream.close (); FileInputStream fileInputStream = novi FileInputStream ("yourfile.txt"); ObjectInputStream objectInputStream = novi ObjectInputStream (fileInputStream); Osoba p2 = (Osoba) objectInputStream.readObject (); objectInputStream.close (); assertTrue (p2.getAge () == p.getAge ()); assertTrue (p2.getName (). jednako (p.getName ())); }

Koristili smo ObjectOutputStream za spremanje stanja ovog objekta u datoteku pomoću FileOutputStream. Datoteka "Yourfile.txt" kreira se u direktoriju projekta. Zatim se datoteka učitava pomoću FileInputStream.ObjectInputStream pokupi ovaj tok i pretvori ga u novi objekt koji se zove str2.

Na kraju testiramo stanje učitanog objekta i ono se podudara sa stanjem izvornog objekta.

Primijetite da učitani objekt mora biti izričito prebačen u Osoba tip.

3. Upozorenja o Java serializaciji

Postoje neka upozorenja koja se tiču ​​serializacije u Javi.

3.1. Nasljeđivanje i sastav

Kad razred provodi java.io.Serializable sučelje, sve se njegove podklase također mogu serializirati. Naprotiv, kada objekt ima referencu na drugi objekt, ti objekti moraju implementirati Serijalizirati sučelje odvojeno, ili a NotSerializableException bit će bačen:

javna klasa Person implementira serializable {private int age; privatni naziv niza; privatna adresa Adresa; // mora se i serializirati} 

Ako se jedno od polja u serializabilnom objektu sastoji od niza objekata, tada se svi ti objekti moraju također serializirati, inače NotSerializableException bit će bačen.

3.2. UID serijske verzije

JVM pridružuje verziju (dugo) broj sa svakom serializabilnom klasom. Koristi se za provjeru imaju li spremljeni i učitani objekti iste atribute i stoga su kompatibilni pri serializaciji.

Većina IDE-a ovaj broj može generirati automatski, a temelji se na nazivu klase, njezinim atributima i povezanim modifikatorima pristupa. Sve promjene rezultiraju različitim brojem i mogu izazvati znak InvalidClassException.

Ako klasa koja se serira ne deklarira serialVersionUID, JVM će ga generirati automatski tijekom izvođenja. Međutim, toplo se preporučuje da se svaka klasa izjasni serialVersionUID jer je generirani ovisan o prevoditelju i stoga može rezultirati neočekivanim InvalidClassExceptions.

3.3. Prilagođena serializacija u Javi

Java određuje zadani način na koji se objekti mogu serializirati. Java klase mogu nadjačati ovo zadano ponašanje. Prilagođena serializacija može biti osobito korisna pri pokušaju serializacije objekta koji ima neke neseribilne atribute. To se može postići pružanjem dvije metode unutar klase koje želimo serializirati:

private void writeObject (ObjectOutputStream out) baca IOException;

i

private void readObject (ObjectInputStream in) baca IOException, ClassNotFoundException;

Ovim metodama možemo te serizibilne atribute serializirati u druge oblike koji se mogu serializirati:

javna klasa Zaposlenik implementira Serializable {private static final long serialVersionUID = 1L; privatna privremena adresa; privatna osoba; // postavljači i getteri privatna void writeObject (ObjectOutputStream oos) baca IOException {oos.defaultWriteObject (); oos.writeObject (address.getHouseNumber ()); } private void readObject (ObjectInputStream ois) baca ClassNotFoundException, IOException {ois.defaultReadObject (); Integer houseNumber = (Integer) ois.readObject (); Adresa a = nova adresa (); a.setHouseNumber (houseNumber); this.setAddress (a); }}
adresa javne klase {private int houseNumber; // postavljači i dobivači}

Sljedeći jedinični test testira ovu prilagođenu serializaciju:

@Test public void whenCustomSerializingAndDeserializing_ThenObjectIsTheSame () baca IOException, ClassNotFoundException {Person p = new Person (); p.setAge (20); p.setName ("Joe"); Adresa a = nova adresa (); a.setHouseNumber (1); Zaposlenik e = novi zaposlenik (); e.setPerson (p); e.setAddress (a); FileOutputStream fileOutputStream = novi FileOutputStream ("yourfile2.txt"); ObjectOutputStream objectOutputStream = novi ObjectOutputStream (fileOutputStream); objectOutputStream.writeObject (e); objectOutputStream.flush (); objectOutputStream.close (); FileInputStream fileInputStream = novi FileInputStream ("yourfile2.txt"); ObjectInputStream objectInputStream = novi ObjectInputStream (fileInputStream); Zaposlenik e2 = (Zaposlenik) objectInputStream.readObject (); objectInputStream.close (); assertTrue (e2.getPerson (). getAge () == e.getPerson (). getAge ()); assertTrue (e2.getAddress (). getHouseNumber () == e.getAddress (). getHouseNumber ()); }

U ovom kodu vidimo kako serializacijom spasiti neke atribute koji se ne mogu serizirati Adresa uz prilagođenu serializaciju. Imajte na umu da atribute koji se ne mogu serizirati moramo označiti kao prolazan kako bi se izbjeglo NotSerializableException.

4. Zaključak

U ovom smo brzom vodiču pregledali Java serializaciju, raspravljali o važnim stvarima koje treba imati na umu i pokazali kako se vrši prilagođena serializacija.

Kao i uvijek, izvorni kod korišten u ovom vodiču dostupan je na GitHub-u.