Prg2-11-Serialization

Werbung
Programmieren 2
11 – Objekt-Serialisierung
Bachelor Medieninformatik
Sommersemester 2015
Dipl.-Inform. Ilse Schmiedecke
[email protected]
1
Noch eine Persistenzalternative
 Eine Adresse als Ganzes in den Strom schicken?
 Ein ganzes Adressbuch in den Strom schicken?
 oder einen Stammbaum?
 Oder eine Prozessakte?
 Oder eine Spielfigur?
22
Die Idee: Objekt raus, Objekt rein
 Java.io unterstützt dieses Konzept mit Binärströmen:
ObjectOutputStream, ObjectInputStream
 Verkettung wie gehabt:
out = new ObjectOutputStream(new File OutputStream("myfile.obj");
in = new ObjectInputStream(new FileInputStream("myfile.obj");
 Schreiben und Lesen ganzer Objekte:
out.writeObject(myAddressBook);
myAddressBook = (AddressBook)in.readObject();
 Könnte es einfacher sein?
 keine Schleifen durch alle Einträge
 keine Protokolle
33
Vielleicht mal etwas anderes?
 Avatar hat einen Namen und eine Liste von Assets
 unter anderem auch Bilder (Image-s)
44
Fragen? Bedenken?
 Keine Sorge bei einfachen Objekten
 Attribute sind primitive Datentypen oder Strings
 Objektströme automatisieren das Protokoll, d.h. die Reihenfolge der
Binärinformation
 Kompliziertere Attribute?
 Avatar enthält ein Bild
 Avatar hat Liste von Assets (wie lang?)
 Avatar könnte weitere Avatare als Gefährten "kennen"
(Liste Baumstruktur, Zyklen?)
 Vererbungshierarchien?
Assets sind Waffen, Fähigkeiten, Kenntnisse... (Unterklassen)
Liste von Assets enthält unterschiedliche Elemente!!
55
Die Antwort heißt Objekt-Serialisierung
 Java-Objektserialisierung automatisiert:
 die Binärcodierung von Daten (primitive Typen und String)
 das Protokoll für die Binärcodierung von Objekte
Avatar1
Avatar2
Avatar3
 eine Typkennung für binär codierte Objekte (Polymorphie!)
 eine Referenzverfolgung zur Vermeidung von Duplikaten (Zyklen!)
1
2
3
1
2
3
4
6
5
5
4
6
66
Serialisierbarkeit
 Eine Klasse, deren Objekte serialisierbar sein sollen, muss das
Interface Serializable implementieren.
public class Avatar implements Serializable {...}
public class Asset implements Serializable {...}
 Die Attribute einer serialisierbaren Klassen müssen serialisierbar sein
 Serializable ist ein Marker-Interface, es enthält keine Methoden
public interface Serializable { }
 Alle primitiven Typen sind Serializable
 Fast alle Klassen in den Java-Standardbibliotheken sind Serializable
(wichtige Ausnahme: Object)
 Alle Unterklassen einer serialisierbaren Klasse sind (natürlich!)
Serializable
77
Spielprototyp mit Avatar

Player
+name


Avatar
Asset
+name
+coins
+image
0..*
Weapon
Wisdom
+image
+description
Dagger

+name
+value
+strength
+realm
Ein Avatar hat Name, Münzen,
Bild und eine Liste von
"Assets" (Aktivposten)
Eine Asset ist eine Waffe oder
Weisheit
Eine Waffe ist ein Dolch oder
ein Schwert
Weisheit gehört zu einem der
Bereiche Landwirtschaft,
Schmieden, Frieden, Alchimie
oder Kriegskunst
<<enumeration>>
Realm
+Farming
+Forging
+Peace
+Alchimy
+War
Sword
88
Enumeration
 Eine Enumeration ist ein Typ
 public Realm myRealm;
 endliche Anzahl benannter Elemente
 benutzbar als Realm.Forging, Realm.War
 Reihenfolge liegt fest, d.h. sie sind vergleichbar
 Gleichheit und Größer/ Kleiner sind definert
 Arithmetische Operationen mit den Werten sind nicht möglich
 zugehöriger Integerwert kann gelesen werden:
 myRealm.ordinal();
 per Definition Serializable, d.h. implements ... ist unnötig
99
Avatar
 Avatar verwaltet Liste von
Assets
1010
Diskussion Assets
 Liste von Assets hat Elemente verschiedener Struktur und
Länge, je nach Unterklasse
  typsichere Serialisierung ist wichtig!
 Es ist sinnvoll, Asset und Weapon als abstrakte Klassen zu
definieren, damit keine Instanzen gebildet werden
1111
Konstanten
 Konstante definiert man als static final
 static
 final
der Wert soll in allen Instanzen gleich sein
nach der Initialisierung unveränderlich
1212
Spielprotoyp: Player
 ein Player spielt (kontrolliert) eine Avatar
 Insbesondere liest er ihn zu Beginn ein und definiert auch das
Herausschreiben
1313
Spielprototyp Payer-Persistenz
1414
Spielprototyp: Hilfsmethoden für die Simulation
1515
Spielprototyp: Main-Methode
 Name wird als Aufruf-Argument übergeben
1616
Serialisierbarkeit - Ausnahmen
 Klassenattribute werden nicht serialisiert
(gehören nicht zum Objektzustand, sondern zum Systemzustand)
 Es kann Attribute geben, die nicht serialisiert werden sollen / müssen
 abgeleitete Attribute – z.B. Alter errechenbar aus dem Geburtsdatum
 ausführungsspezifische Attribute, z.B. IP-Adresse, Portnummer,
Verbindungsdauer...
 Diese Attribute können als "transient" markiert werden
transient private int Dauer = 0;
 Eine Belegung mit sinnvollen Werten muss in der Klasse programmiert
werden.
public int get Dauer() {
if (dauer != 0) return dauer;
return currentYear-yearOfBirth;
}
1717
Serialisierbarkeit - Grenzen
 Eine Klasse kann grundsätzlich nur serialisierbar sein,
wenn es ihre Oberklasse auch ist.
 Ausnahme nur für Spezialfälle: selbst implementierte Serialisierung.
 die Serialisierungs-Methoden implementieren
writeObject
readObject
readObjectNoData
(Signaturen s.u.)
 und dabei die Oberklassenattribute mit berücksichtigen
private void writeObject(java.io.ObjectOutputStream out) throws IOException
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException; private void readObjectNoData() throws
ObjectStreamException;
1818
Serialisierbarkeit: Versionsnummer
 Ein Avatar wurde herausgeschrieben
 Danach wurde die Avatar-Klasse geändert (Image-Attribut hinzugefügt)
 Was passiert beim Einlesen?
rjava.io.InvalidClassException: rpg.Avatar; local class incompatible:
stream classdesc serialVersionUID = -3920281712614004619,
local class serialVersionUID = -4623769236742658137
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at rpg.Player.getAvatar(Player.java:39)
at rpg.Player.<init>(Player.java:19)
at rpg.Main_1.main(Main_1.java:6)
1919
Serialisierbarkeit: Versionsnummer
 Jedes Klasse erhält automatisch eine Versionsnummer, die bei
Änderung neu erzeugt wird
 Diese Versionsnummer serialVersionUID wird mit serialisiert
 Passt bei der Deserialisierung die Versionsnummer im Programm
nicht zur Versionsnummer im "stream" , wird eine Exception
geworfen.
rjava.io.InvalidClassException: rpg.Avatar; local class incompatible:
stream classdesc serialVersionUID = -3920281712614004619,
local class serialVersionUID = -4623769236742658137
 SUPER! So werden versehentliche Fehldeutungen von Daten
vermieden!
2020
Serialisierung: Versionsnummer
 Die Versionsnummer ändert sich auch bei Änderungen, die die
Serialisierung nicht betreffen:




Änderungen an Methoden
Änderungen an Attributnamen oder -sichtbarkeiten
Änderungen an statischen Attributen
Änderungen an Kommentaren
Eigene Versionsnummer vergeben und nur bei relevanten
Änderungen neu generieren
2121
Setzen der Versionsnummer
 Default:
 Aus der Klassenstruktur generiert:
 kann selbst mit dem Werkzeug serialver erzeugt werden:
2222
Zusammenfassung
 Durch Serialisierung ist es möglich, ganze Objekte auf
einmal zu lesen und zu schreiben
 einfach und effizient
 typ- und versionssicher
 alte Daten nur mit alten Programmen wieder herstellbar!
 ohne Probleme bei zyklischen Datenstrukturen
Das Mittel der Wahl für effiziente Persistenz
 in der Testphase sind Textdateien vorzuziehen!
2323
Nächstes Mal geht's ins Netzwerk
24
24
Herunterladen