„Szerializalas jegyzet” változatai közötti eltérés

A VIK Wikiből
Nagy Marcell (vitalap | szerkesztései)
a autoedit v2: fájlhivatkozások egységesítése, az új közvetlenül az adott fájlra mutat
 
(27 közbenső módosítás, amit 2 másik szerkesztő végzett, nincs mutatva)
2. sor: 2. sor:
== Alapok, amiket jó ha tudunk ==
== 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.
* 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!");
  }
<br/>
* Két nagyon fontos metódus játszik fő szerepet a szerializálásban:
* Két nagyon fontos metódus játszik fő szerepet a szerializálásban:
**private void '''writeObject''' (ObjectOutputStream out) throws IOException
**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.
***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
**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.
<br />
<br />
*'''Egy, két nyalánkság:'''
*'''Egy, két nyalánkság:'''
**private Object '''writeReplace'''() throws ObjectStreamException
**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.
***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.
***Amikor 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 és az így visszaadott objektumot fogja végül sorosítani.
***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!'''
  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 ==
== Korábbi vizsgapéldák ==
27. sor: 54. sor:
   }
   }


==== Megoldás, magyarázat ====
* Eredmény: x = 0, y = 6
A Java, csodálatos módon megengedi azt, hogy egy transient-nek - tehát alapvetően nem szerializálódó - jelölt attribútumot mégis tudjunk sorosítani. Ezt a csodálatos lehetőséget úgy valósítja meg, hogy


=== OOT - 2015. június 9. ===
=== OOT - 2015. június 9. ===
45. sor: 71. sor:
       }
       }
   }
   }
* Eredmény: x=4, y=0
* [[Media:oot_20150602VizsgaFeladat_20150612.java | Java fájl letöltése]]

A lap jelenlegi, 2017. július 12., 14:59-kori változata

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.

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.


  • 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!
  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;
     }
  }