Streams Programmiermethodik SS 08 Stefan Podlipnig Universität Innsbruck Übersicht • • • • File-Klasse Datenströme Spezielle Themen Serialisierung Stefan Podlipnig Programmiermethodik (SS 08) 2 FILE-KLASSE Stefan Podlipnig Programmiermethodik (SS 08) 3 Dateien • In Java gibt es eine File-Klasse – Liefert Informationen über Dateien und Verzeichnisse – Diese Klasse wurde eingeführt, um Dateioperationen plattformunabhängig durchzuführen • Ein konkretes File-Objekt repräsentiert eine Datei oder ein Verzeichnis im Dateisystem • Der Verweis wird durch einen Pfadnamen spezifiziert – Absoluter Pfadname (von der Wurzel ausgehend) – Relativer Pfadname (abhängig vom aktuellen Verzeichnis) – Pfadangaben sind plattformabhängig (siehe API) Stefan Podlipnig Programmiermethodik (SS 08) 4 File-Klasse • Konstruktor stellt die Beziehung zu einer Datei im Verzeichnis her • Beispiele für Konstruktoren File(String parent, String child) File(String pathname) • Beispiele String parent = "C:" + File.separator + "Test"; File f1 = new File("test1.txt"); File f2 = new File(parent,"test2.txt"); Stefan Podlipnig Programmiermethodik (SS 08) 5 File-Klasse (einige Methoden) • Allgemeine Methoden (Informationen über Dateien) public public public public public public public boolean canRead() boolean canWrite() boolean exists() long lastModified() String getAbsolutePath() String getParent() String [] list() //Änderungszeit //Absoluter Pfad //Parent (Datei etc.) //Verzeichnisinhalt • Methoden für die Manipulation public public public public public boolean boolean boolean boolean boolean renameTo(File dest) setLastModified(long time); delete() createNewFile() throws IOException mkdir() • Siehe externes Beispiel StreamTest1.java Stefan Podlipnig Programmiermethodik (SS 08) 6 DATENSTRÖME Stefan Podlipnig Programmiermethodik (SS 08) 7 Motivation • Die Java Bibliothek enthält eine ganze Reihe von Klassen, um anspruchsvolle Ein- bzw. Ausgabeoperationen zu bewältigen und von verschiedenen Datenquellen zu lesen und zu schreiben • Das Ein- /Ausgabemodell in Java basiert auf sequentiellen Datenströmen – Beim Schreiben erzeugt man einen Ausgabestrom (in eine Datei oder einen Speicher) – Beim Lesen kommen die Daten von einem Eingabestrom (von einer Datei oder einem Speicher) Stefan Podlipnig Programmiermethodik (SS 08) 8 IO-Begriffe • Stream – Die interne Repräsentation einer (externen) Datei oder einer Input/OutputEinheit in einem System • Input – Lesen der Daten von einer Datei oder einer Eingabeeinheit in einen Stream – Stream wird als Input Stream bezeichnet • Output – Schreiben der Daten von einem Stream in eine Datei oder eine Ausgabeeinheit – Stream wird als Output Stream bezeichnet • Source/Destination – Jeder Stream hat eine Quelle (Source) und eine Senke (Destination) Stefan Podlipnig Programmiermethodik (SS 08) 9 Allgemeine Beispiele (1) InputStream JMenuBar mbar = new JMenuBar(); JMenu menu = new JMenu( "Datei" ); JMenuItem item = new JMenuItem( "Öffnen" ); item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK) ); item.addActionListener( this ); menu.add( item ); mbar.add( menu ); setJMenuBar( mbar ); InputStream add( viewComponent ); setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); setSize( 600, 400 ); } public void actionPerformed( ActionEvent e ) { JFileChooser d = new JFileChooser(); d.setFileFilter( new FileFilter() } public boolean accept(File f) Tastatur Programm OutputStream JMenuBar mbar = new JMenuBar(); JMenu menu = new JMenu( "Datei" ); JMenuItem item = new JMenuItem( "Öffnen" ); item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK) ); item.addActionListener( this ); menu.add( item ); mbar.add( menu ); setJMenuBar( mbar ); add( viewComponent ); setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); setSize( 600, 400 ); } OutputStream public void actionPerformed( ActionEvent e ) { JFileChooser d = new JFileChooser(); d.setFileFilter( new FileFilter() } public boolean accept(File f) Bildschirm Programm Stefan Podlipnig Programmiermethodik (SS 08) 10 Allgemeine Beispiele (2) • Lesen/Schreiben einer Datei ------------------------------------ ------------------------------------ InputStream JMenuBar mbar = new JMenuBar(); JMenu menu = new JMenu( "Datei" ); JMenuItem item = new JMenuItem( "Öffnen" ); item.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK) ); item.addActionListener( this ); menu.add( item ); mbar.add( menu ); setJMenuBar( mbar ); add( viewComponent ); ------------------------------------ setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); setSize( 600, 400 ); } OutputStream public void actionPerformed( ActionEvent e ) { JFileChooser d = new JFileChooser(); d.setFileFilter( new FileFilter() } Programm Stefan Podlipnig Programmiermethodik (SS 08) 11 Strom (Modell) • Ein Datenstrom wird durch eine Klasse repräsentiert – Hat private Attribute (Name, Position etc.) – Hat bestimmte Methoden – Beispiele • read() – Liest ein Element aus dem Strom • write() – Schreibt ein Element in den Strom • Vorteil – Systemabhängigkeit wird in wenigen Klassen isoliert – Rest des Programms systemneutral Stefan Podlipnig Programmiermethodik (SS 08) 12 Standard I/O • Einfachster I/O - Mechanismus – Texteingabe von der Tastatur – Textausgabe auf den Bildschirm ("Konsole") • Auf praktisch jedem System verfügbar • Minimale Systemanforderungen • Standard - I/O über vordefinierte Objekte – System.in – System.out – System.err Standard-Eingabe (← Tastatur) Standard-Ausgabe (→ Bildschirm) Fehlerausgabe (→ Bildschirm) • in, out, error – Statische, öffentliche Datenelemente der Klasse System Stefan Podlipnig Programmiermethodik (SS 08) 13 Klassenhierachien • Es gibt 2 Hierarchien – Byteströme – Zeichenströme • In jeder Hierarchie 2 Arten – Datenströme • Sind mit bestimmten Datenquellen oder Datensenken verbunden • Lesen von Datenquellen bzw. schreiben in Datensenken – Filterströme • • • • Stefan Podlipnig Sind nicht direkt mit einer Quelle oder Senke verknüpft Sind mit einem Datenstrom verbunden Agieren wie ein Filter vor diesem Datenstrom Vorverarbeiten/Nachbearbeiten von Daten Programmiermethodik (SS 08) 14 Byteströme • Bytestrom ist eine Folge von Bytes • Operationen – Einzelne Bytes lesen/schreiben – Ganze Bytefolgen lesen/schreiben • Alle Byteströme werden abgeleitet von – InputStream oder OutputStream – Sind abstrakte Klassen – Geben API vor und liefern eine partielle Implementierung Stefan Podlipnig Programmiermethodik (SS 08) 15 InputStream (Version 1.5) • Zum Lesen von Bytes • Datenströme (dunkel), Filterströme (hell) Stefan Podlipnig Programmiermethodik (SS 08) 16 OutputStream (Version 1.5) • Zum Schreiben von Bytes • Datenströme (dunkel), Filterströme (hell) Stefan Podlipnig Programmiermethodik (SS 08) 17 Zeichenströme • Zeichenströme enthalten Texte in ASCII - oder Unicode • Operationen – Einzelne Zeichen lesen/schreiben – Strings lesen/schreiben – char-Arrays lesen/schreiben • Zeichenströme werden abgeleitet von – Reader oder Writer – Sind abstrakte Klassen Stefan Podlipnig Programmiermethodik (SS 08) 18 Reader (Version 1.5) • Zum Lesen von 16 bit Zeichen • Datenströme (dunkel), Filterströme (hell) Stefan Podlipnig Programmiermethodik (SS 08) 19 Writer (Version 1.5) • Zum Schreiben von 16 bit Zeichen • Datenströme (dunkel), Filterströme (hell) Stefan Podlipnig Programmiermethodik (SS 08) 20 I/O – Superklassen (1) • Reader und InputStream definieren ähnliche APIs für unterschiedliche Datentypen, z.B. – Reader int read() int read(char cbuf[]) int read(char cbuf[], int off, int len) – InputStream int read() int read(byte cbuf[]) int read(byte cbuf[], int off, int len) • Ähnliches gilt für Writer und OutputStream Stefan Podlipnig Programmiermethodik (SS 08) 21 I/O-Superklassen (2) • Weitere Methoden für Eingabeströme – Aktuelle Position im Strom markieren – Zurücksetzen der aktuellen Position auf vorherige Markierung – Input überspringen • Weitere Methoden für Ausgabeströme – Datenstrom leeren und damit noch gepufferte Daten verarbeiten (flush) • Für alle Klassen gilt – Automatisches Öffnen bei der Erzeugung – Schließen durch den Aufruf der close-Methode • Sobald ein Strom nicht mehr benötigt wird • Gibt Ressourcen frei Stefan Podlipnig Programmiermethodik (SS 08) 22 Anwendung von Strömen I/O - Typ Speicher (Memory) Datenstrom CharArrayReader, CharArrayWriter, ByteArrayInputStream, ByteArrayOutputStream, StringReader, StringWriter, StringBufferInputStream Pipe PipedReader, PipedWriter, PipedInputStream, PipedOutputStream File FileReader, FileWriter, FileInputStream, FileOutputStream Konkatenation (mehrerer InputStreams) Objekt - Serialisierung Datenkonvertierung (Standardtypen in rechnerunabhängiges Binärformat) N/A, SequenceInputStream N/A, ObjectInputStream, ObjectOutputStream N/A , DataInputStream, DataOutputStream Zählstreams (für Zeilennummern) LineNumberReader, LineNumberInputStream Vorausschauend (peeking ahead) PushbackReader, PushbackInputStream Ausgabe (Printing) Pufferung Filterströme (Filtering) Konvertierung zwischen Byte- und Datenströmen Stefan Podlipnig PrintWriter, PrintStream BufferedReader, BufferedWriter, BufferedInputStream, BufferedOutputStream FilterReader, FilterWriter, FilterInputStream, FilterOutputStream InputStreamReader (byte in char), OutputStreamWriter (char in byte) Programmiermethodik (SS 08) 23 Beispiel (FileStreams) • Sehr einfach zu verwenden • 4 Klassen – – – – FileReader FileWriter FileInputStream FileOutputStream • Lesen aus / Schreiben in eine Datei im Dateisystem • Konstruktor – Mit String – Mit File oder FileDescriptor • Siehe externes Beispiel StreamTest2.java Stefan Podlipnig Programmiermethodik (SS 08) 24 Ströme (2 wichtige Konzepte) • Zur I/O-Leistungssteigerung gibt es zwei wichtige Konzepte – Datenpufferung – Konkatenation • Datenpufferung – Zur Zwischenspeicherung – Wenn I/O langsamer als die CPU ist • Konkatenation – Ströme können miteinander verbunden werden – Der Output eines Stroms ist der Input eines anderen Stroms • Ein Strom wird im Konstruktor eines anderen Stroms als Argument übergeben • Verbinden von Filterströmen und Datenströmen Stefan Podlipnig Programmiermethodik (SS 08) 25 Datenpufferung • Inputpuffer – Speichert schon gelesene aber nicht verarbeitete Daten • Nicht Zeichen für Zeichen lesen und an das Programm übergeben • Folgen von Zeichen in Puffer kopieren und bei einer Leseoperation an das Programm übergeben • Outputpuffer – Speichert temporäre Daten, die geschrieben werden – Schreiben, wenn der Puffer voll wird (oder flush() aufgerufen wird) • Viele I/O - Geräte unterstützen Operationen auf Blöcke • Der Datentransfer zwischen Puffer und Objekten ist normalerweise schnell (siehe Entwicklung von Anwendungssystemen) • Die Pufferung verbessert die Laufzeit von Programmen Stefan Podlipnig Programmiermethodik (SS 08) 26 Konkatenation (1) • Beispieldeklaration BufferedReader inStream = new BufferedReader(new FileReader("in.txt")); – Verbindet einen BufferedReader mit einem FileReader – Das Programm kann dann inStream.readLine() aufrufen, um die Eingabedatei Zeile für Zeile zu lesen • Datenfluss – Textdatei → FileReader → BufferedReader → Speicher Stefan Podlipnig Programmiermethodik (SS 08) 27 Konkatenation (2) • Für die Konkatenation muss ein Strom als Argument beim Konstruktor eines anderen Stroms übergeben werden • Beispiel (Java API) public class BufferedReader extends Reader { … public BufferedReader(Reader in, int sz) { super(in); …. } … public BufferedReader(Reader in) { this(in, defaultCharBufferSize); } … } • Benutzung BufferedReader inStream = new BufferedReader(new FileReader("in.txt")); Stefan Podlipnig Programmiermethodik (SS 08) 28 Filterströme • Es könne eigene Filterströme von den entsprechenden abstrakten Klassen abgeleitet werden • Ein Filterstrom verwendet weiteren Strom – Zu lesende Daten werden aus dem darunter liegenden Strom gelesen, gefiltert und an den Aufrufer weitergegeben – Zu schreibende Daten werden gefiltert und in den darunter liegenden Strom geschrieben – Filtern kann viele Bedeutungen haben (Zeichen verändern, löschen oder zählen, Zeilen zählen etc.) • Eigenen Strom implementieren – Abstrakte Klasse verwenden • – – – Input- und OutputStreams kommen oft gemeinsam vor, d.h. man wird meist zwei Klassen implementieren müssen Überschreiben der read- und write-Methoden (wenn benötigt) Neue Methoden anbieten Testen, ob die Implementierungen (Input, Output) korrekt zusammenarbeiten Stefan Podlipnig Programmiermethodik (SS 08) 29 Beispiel • BufferedReader BufferedReader ist ein Filterstrom (puffert) … BufferedReader d = new BufferedReader(new InputStreamReader(System.in)); String input; while (!(input = d.readLine()).equals("quit")) { System.out.println(input); } … • Beispiel für eigenen Filterstrom – Siehe Implementierung von CheckedInputStream/CheckedOutputStream im Paket java.util.zip Stefan Podlipnig Programmiermethodik (SS 08) 30 SPEZIELLE THEMEN Stefan Podlipnig Programmiermethodik (SS 08) 31 Scanning und Formatting • Programme müssen mit dem Benutzer entsprechend interagieren – Benutzereingaben • Benutzer möchte Daten auf lesbare Art eingeben • Programm zerlegt dann Eingabedaten für die Weiterverarbeitung – Bildschirmausgabe • Programm stellt lesbare Ausgabe zusammen • Java I/O bietet dazu zwei APIs an – Scanner-API zum Einlesen – Formatting-API für die Ausgabe Stefan Podlipnig Programmiermethodik (SS 08) 32 Scanner • Scanner wird für das Zerlegen des Inputs verwendet – Input wird in Tokens zerlegt – Tokens werden dann entsprechend weiterverarbeitet – Seit Java 1.5 (früher StringTokenizer-Klasse für Strings) • Methoden – hasNext, hasNextInteger, hasNextDouble… • Überprüfen ob noch ein Token (String), ein Integer-Wert, ein Double-Wert etc. im Strom vorhanden ist – next, nextInteger, nextDouble …. • Auslesen des nächsten Tokens (String), Integer-Werts, Double-Werts etc. Stefan Podlipnig Programmiermethodik (SS 08) 33 Beispiel import import import import java.io.File; java.io.IOException; java.util.Locale; java.util.Scanner; public final class StreamTest3 { private StreamTest3() { } public static void main(final String[] args) throws IOException { Scanner s = new Scanner(new File("usnumbers.txt")); s.useLocale(Locale.US); double sum = 0; while (s.hasNext()) { if (s.hasNextDouble()) { sum += s.nextDouble(); } else { s.next(); } } s.close(); System.out.println(sum); } } Stefan Podlipnig Programmiermethodik (SS 08) 34 Formatierung • Klassen, die Formatierung berücksichtigen – PrintWriter – PrintStream • System.out und System.err sind PrintStream-Instanzen • Zwei Stufen der Formatierung werden unterstützt – print und println formatieren individuelle Werte in der Standardform – format formatiert jeden Wert an Hand eines Formatierungsstrings – Für Formatstrings im printf-Stil • Es gibt daher auch eine printf-Methode (äquivalent zu format) – Etwas strikter als in C • z.B. Exception, wenn Formatstring Fehler enthält Stefan Podlipnig Programmiermethodik (SS 08) 35 format-Methode (1) • Formatiert Argumente mit einem Formatierungsstring • Formatstring enthält Formatspezifizierer – Formatierungsangaben folgen einem %-Zeichen und folgendem Syntax: %[argument_index$][flags][width][.precision]conversion – [argument_index] bezieht sich auf die Position in der Argumentenliste (erstes Arg – 1$, zweites Arg - 2$ ..) – [flags] ist eine Menge von Zeichen zur Modifikation der Ausgabe – [width] ist die minimale Anzahl der Zeichen, die ausgegeben werden – [precision] ist die maximale Anzahl der Zeichen oder Genauigkeit bei Gleitkommazahlen – conversion ist ein Zeichen, das die Formatierung des Arguments bestimmt erlaubte Formatierungen hängen vom jeweiligen Datentyp ab • 1 oder 2 Buchstaben, die die entsprechende Konvertierung beschreiben • Genaue Beschreibung siehe API • Beispiele %d, %f, %x, … • Ist als einziger Teil nicht optional Stefan Podlipnig Programmiermethodik (SS 08) 36 format-Methode (2) • Unterschiedliche Kategorien der Konvertierung – – General – allgemein anwendbar Character – anwendbar auf alle Typen die Unicode-Zeichen repräsentieren • – char, Character, byte, Byte, short und Short Numeric • Integral – anwendbar auf – • Floating Point – anwendbar auf – – float, Float, double, Double und BigDecimal Date/Time – anwendbar auf • – – byte, Byte, short, Short, int, Integer, long, Long, BigInteger long, Long, Calendar und Date Percent – für '%' ('\u0025') Line Separator – für plattformspezifisches“\n” Stefan Podlipnig Programmiermethodik (SS 08) 37 Beispiel import java.io.IOException; public final class StreamTest4 { private StreamTest4() { } public static void main(final String[] args) throws IOException { int i = 2; double r = Math.sqrt(i); System.out.format("The square root of %d is %f.%n", i, r); System.out.format("%f, %1$+020.10f %n", Math.PI); System.out.format("%4$s %3$s %2$s %1$s %4$s %3$s %2$s %1$s %n", "a", "b", "c", "d"); System.out.format("%s %s %<s %<s %n", "a", "b", "c", "d"); System.out.format("%s %s %s %s %n", "a", "b", "c", "d"); System.out.format("%1$5s %s %s %s %n", "a", "b", "c", "d"); } } Stefan Podlipnig Ausgabe: The square root of 2 is 1,414214. 3,141593, +00000003,1415926536 d c b a d c b a a b b b a b c d a a b c Programmiermethodik (SS 08) 38 RandomAccessFile • Bisher wurden Ströme besprochen, die nur einen sequentiellen Zugriff gestatten • Oft will man bei einer Datei nur einen bestimmten Teil lesen • Java bietet eine Klasse RandomAccessFile an – Wird für Lesen und Schreiben verwendet (unterschiedliche Argumente beim Konstruktor) new RandomAccessFile("in.txt", "r"); new RandomAccessFile("in.txt", "w"); new RandomAccessFile("in.txt", "rw"); – Wird von keiner Stream-Klasse abgeleitet – Implementiert aber die zwei Interfaces DataOutput und DataInput Stefan Podlipnig Programmiermethodik (SS 08) 39 RandomAccessFile (File-Pointer) • Die Klasse RandomAccessFile unterstützt das Konzept eines File-Pointers – File-Pointer zeigt auf die aktuelle Position in der Datei – Bei der Erzeugung einer Datei zeigt er auf 0 – Aufrufe von read und write passen die Position abhängig von der Anzahl der gelesenen/geschriebenen Bytes an • Neben den Operationen read und write etc. gibt es Methoden für die explizite Verwaltung des File-Pointers – int skipBytes(int) — Überspringt die angegebene Anzahl von Bytes (File-Pointer wird vorwärts bewegt) – void seek(long) — Positioniert den File-Pointer vor der angegebenen Position – long getFilePointer() — Liefert die aktuelle Position des FilePointers Stefan Podlipnig Programmiermethodik (SS 08) 40 SERIALISIERUNG Stefan Podlipnig Programmiermethodik (SS 08) 41 Serialisierung von Objekten • Der Zustand eines Objekts wird so abgespeichert, dass er wieder rekonstruiert (ausgelesen) werden kann – Serialisierung • Objekt wird als Folge von Bytes in einen Strom geschrieben – Deserialisierung • Objekt wird als Folge von Bytes aus einem Strom gelesen • Objekt existiert über die Ausführung eines Programms hinaus • Objekt wird mit all seinen Komponenten in den Strom geschrieben, d.h. Referenzen werden auch serialisiert • Serialisierung – ObjectOutputStream – Ein Objekt, das serialisiert werden soll, muss als Argument der writeObject-Methode übergeben werden • Deserialisierung – ObjectInputStream – Mit der readObject-Methode kann ein Objekt eingelesen werden • Dabei wird nur der Zustand des Objekts eingelesen • Es werden keine Konstruktoren aufgerufen Stefan Podlipnig Programmiermethodik (SS 08) 42 Beispiel import import import import import java.io.FileInputStream; java.io.FileOutputStream; java.io.IOException; java.io.ObjectInputStream; java.io.ObjectOutputStream; public final class StreamTest5 { private StreamTest5() { } public static void main(final String[] args) { try { FileOutputStream out = new FileOutputStream("MyObjects"); ObjectOutputStream s = new ObjectOutputStream(out); s.writeObject("Today"); s.writeObject(1); s.flush(); FileInputStream in = new FileInputStream("MyObjects"); ObjectInputStream sin = new ObjectInputStream(in); String today = (String) sin.readObject(); Integer i = (Integer) sin.readObject(); System.out.println(today + " " + i); } catch (IOException ioe) { ioe.printStackTrace(); } catch (ClassNotFoundException cnfe) { cnfe.printStackTrace(); } } } Stefan Podlipnig Programmiermethodik (SS 08) 43 Serialisierung (Voraussetzung) • Ein Objekt kann nur serialisiert werden, wenn die entsprechende Klasse das Interface Serializable implementiert • Ist ein Marker-Interface (leeres Interface) • Beispiel – public class MySerClass implements Serializable { ... } • Damit kann jede Instanz der Klasse serialisiert werden • Bei der Serialisierung werden geschrieben – Klasse – Klassensignatur – Werte der nicht statischen und nicht transienten Elemente (auch Referenzen) Stefan Podlipnig Programmiermethodik (SS 08) 44 Anpassen der Serialisierung • Serialisierung/Deserialisierung kann angepasst werden • Implementieren der Methoden – writeObject • Für das Schreiben eines Objekts (Anpassen, zusätzliche Informationen etc.) – readObject • Für das Lesen eines Objekts (Lesen, Anpassen, Updates etc.) • Form der writeObject-Methode private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); // Benutzerspezifische Anpassung ….. } • Form der readObject-Methode private void readObject(ObjectInputStream s) throws IOException { s.defaultReadObject(); // Benutzerspezifische Anpassung ….. // Zusätzliche Updates … } Stefan Podlipnig Programmiermethodik (SS 08) 45 transient • Oft soll ein Teil eines Objekts nicht serialisiert werden • Schlüsselwort transient bei der Deklaration von Feldern verwenden – Das entsprechende Feld wird nicht serialisiert – Beim Einlesen wird das entsprechende Feld mit einem Defaultwert initialisiert – Wenn das nicht gewünscht wird – überschreiben von readObject mit einer entsprechenden Initialisierung • Siehe externes Beispiel StreamTest6.java Stefan Podlipnig Programmiermethodik (SS 08) 46 Externalizable - Interface • Will man die komplette Kontrolle über den Serialisierungsprozess, dann muss die Klasse das Interface Externalizable implementieren • Externalizable erweitert Serializable – 2 Methoden (writeExternal, readExternal) • Eine Klasse muss – das Interface implementieren – Die Methoden writeExternal und readExternal implementieren und miteinander koordinieren (und mit der Superklasse koordinieren) • Die Methoden sind public und daher kann sie jedes Programm benutzen, d.h. nur für nicht-sensitive Daten geeignet Stefan Podlipnig Programmiermethodik (SS 08) 47 Serialisierung unterbinden • Beispiel – Klasse B erbt von A – A implementiert das Interface Serializable – B sollte aber nicht serialisierbar sein • Serialisierung unterbinden durch entsprechendes Überschreiben (werfen einer Exception) der Methoden writeObject und readObject • Beispiel private void writeObject(ObjectOutputStream s) throws IOException,ClassNotFoundException { throw new NotSerializableException(); } Stefan Podlipnig Programmiermethodik (SS 08) 48 Serialisierung und Vererbung • Ist eine Basisklasse serialisierbar – In einem Objekt einer abgeleiteten Klasse werden alle ererbten Attribute der Basisklasse serialisiert • Ist eine Basisklasse nicht serialisierbar – Werden alle Attribute der Basisklasse serialisiert – Dazu muss in der abgeleiteten Klasse der Zugriff auf einen DefaultKonstruktor der Basisklasse möglich sein • Wird für die Initialisierung der Attribute benutzt • Wenn dieser nicht vorhanden ist, wird eine Ausnahme geworfen Stefan Podlipnig Programmiermethodik (SS 08) 49 Versionsverwaltung (1) • Verschiedene Versionen einer Klasse können Probleme bereiten – Objekt wird serialisiert – Klasse wird verändert • Attribute löschen • Typen ändern – Deserialisieren funktioniert dann nicht mehr • Erkennung in Java – Bei der Serialisierung wird eine eindeutige Kennung geschrieben (UID) • Hashcode aus Namen, Attributen, Parametern, Sichtbarkeit usw. – Ändert sich eine Klasse, dann ändert sich der Hashcode • Keine Kompatibilität mehr Stefan Podlipnig Programmiermethodik (SS 08) 50 Versionsverwaltung (2) • SUID – Benutzer kann die SUID (serialVersionUID) selbst berechnen • Händisch – Aufruf des Hilfsprogramms serialver mit Klassenname – Ausgabe des Programms in das eigene Programm kopieren • Eclipse unterstützt die Generierung • Beispiel static final long serialVersionUID = 9027745268614067035L; – Man kann eine eigene SUID angeben (z.B. 1L) – Bestimmte Änderungen (nicht alle) können vorgenommen werden wenn die SUID gleich bleibt • Neue Felder (werden beim Einlesen standardmäßig initialisiert) • Fehlende Felder (werden ignoriert) – Bei inkompatiblen Änderungen muss die SUID verändert werden • Neu generieren oder eigene hochzählen Stefan Podlipnig Programmiermethodik (SS 08) 51