Szerializalas jegyzet
A lap korábbi változatát látod, amilyen Nagy Marcell (vitalap | szerkesztései) 2017. július 12., 13:59-kor történt szerkesztése után volt. (autoedit v2: fájlhivatkozások egységesítése, az új közvetlenül az adott fájlra mutat)
Jelen jegyzet, leírás, segédlet nevezzük bárhogy megpróbálja az Objektumorientált Szoftvertervezés és Szoftvertechnológia tárgyakban előszeretettel kérdezett Java szerializálás témaköréből egy áttekinthető, konyhanyelven készült leírást szolgáltatni, sok-sok példával.
Tartalomjegyzék
Alapok, amiket jó ha tudunk
- Alapvetően minden nem statikus és nem tranzies attribútuma egy osztálynak szerializálódik, amely megvalósítja a Serializable interfészt.
- A láthatóság nem befolyásolja a szerializálhatóságot, mind a public, protected és private adattagok szerializálódnak.
- Kiíráskor minden objektum egyszer íródok ki "rendesen", azt követően az adott objektum újboli kiírásakor - feltételezve, hogy a streamet nem zárták be - csupán egy referencia kerül kiírásra, amely referál az először kiírt "rendes" objektumra.
- A szerializálhatóság mint tulajdonság, fennmarad az örökléskor is, tehát ha egy osztály sorosítható akkor annak leszármazottai is kimenthetőek lesznek.
- A szerializálás tiltására van lehetőségünk, a wirteObject metódust kell felüldefiniálnunk abban az osztályban, amelyiket nem szeretnénk szerializálni:
private void writeObject(ObjectOutputStream o) throws NotSerializableException{ throw new NotSerializableException("No-no! No Mr. Serializaton!"); }
- Két nagyon fontos metódus játszik fő szerepet a szerializálásban:
- private void writeObject (ObjectOutputStream out) throws IOException
- A metódus gyakorlatilag teljes kontrollt biztosít a szerializálandó objektum sorosítása felett. A legtöbb esetben egy out.defaultWriteObject() metódushívással kezdődik ezen metódusok implementálása, majd ezt követően lehetőségünk van egyéb adatok sorosítására az erre alkalmas metódusok meghívásával mint pl. az out.writeDouble.
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
- A writeObject metódus ellentéte, a korábban szerializált obejktumokat ezzel a metódussal tudjuk beolvasni. Felüldefiniálásakor az implementáció itt is - a writeObject-hez hasonlóan - az automatikusan szerializált adatok automatikus visszaolvasásával kezdődik, ami a in.defaultReadObject() meghívásával történik. Ezek után beolvassuk azon extra adatokat amelyeket korábban a writeObject() metódussal szerializáltunk. Fontos, hogy a típusegyezésre nekünk kell figyelnünk, így beolvasáskor helyesen kell kasztolnunk, illetve a primitív típusok esetén a megfelelő beolvasó metódust kell meghívnunk.
- private void writeObject (ObjectOutputStream out) throws IOException
- Egy, két nyalánkság:
- private Object writeReplace() throws ObjectStreamException
- A metódus segítségével létrehozható egy "helyettesítő" objektum. A szerializálás során ez az újonnan létrehozott objektum fog szerializálódni az eredeti helyett.
- Az ObjectOuputStream ellenőrzi, hogy a sorosítani kívánt osztály definiál-e writeReplace() metódust, és ha igen meghívja azt először majd az így visszaadott objektumot fogja végül sorosítani.
- private Object readResolve() throws ObjectStreamException
- A writeReplace() ellentéte. Ha a metódus definiált az osztályban, akkor az objektum beolvasása előtt, ennek a metódusnak az eredményét "olvassa be" az ObjectInputStream, a korábban szerializált helyett.
- private static final ObjectStreamField[] serialPersistentFields
- Fontos, hogy ez a korábbiakkal ellentétben nem metódus, hanem egy statikus, nem módosítható tömb az osztályban.
- A tömb használatával lehetőségünk van explicit megadni, hogy az osztály mely attribútumai szerializálódjanak. Fontos, hogy csak a tömbben megjelölt tagváltozók mentődnek ki, tehát hiába van az osztálynak több nem statikus és nem tranziens tagváltozója, csak és kizárólag azon attribútumok fognak szerializálódni amelyek ebben a tömbben szerepelnek!
- A lenti példában beállítottuk, hogy a Dog osztály szerializálásakor csak az age és a name attribútumok mentődjenek le, a többi adat ne. Fontos, hogy a tranziensnek jelölt attribútumok is szerializálhatók így!
- private Object writeReplace() throws ObjectStreamException
public class Dog implements Serializable { public String name; public int age; private int ID; private String owner; private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("age",Integer.TYPE), new ObjectStreamField("name", String.TYPE) }; ... }
Korábbi vizsgapéldák
OOT - 2015. június 2.
public class A implements Serializable { private int x = 1; public transient int y = 2; private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("y", Integer.TYPE) }; public A() { x = 3; y = 4; } public Object writeReplace() throws ObjectStreamException { A a = new A(); a.x = 5; a.y = 6; return a; } }
- Eredmény: x = 0, y = 6
OOT - 2015. június 9.
public class A implements Serializable { private transient int x = 8; public int y = 4; public A () { x = 0; y = 4; } private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("x", Integer.TYPE) }; private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{ in.defaultReadObject(); x = y + 4; } }
- Eredmény: x=4, y=0
- Java fájl letöltése