5. Objektorientiertes Programmieren 5.3 Subtypen und Vererbung 5. Objektorientiertes Programmieren Beispiel: (geschütztes Zugriffsrecht) (3) Zusammenfassende Bemerkungen zu 5.3 • Subtypen erlauben es, spezialisierte Objekte anstelle von public class Main { public static void main( String [] args ) { A_doch_Null adn = new A_doch_Null (); adn.setA( 0 ); A_nicht_Null ann = adn; ... // hier koennte die Herkunft von ann verschleiert sein Anwendung .m(ann); } } Supertyp-Objekten zu verwenden. Dadurch können Programme auf der Ebene allgemeinerer Objekte formuliert und wiederverwendet werden. • Vererbung erlaubt die Weitergabe und damit Wiederverwendung von Programmteilen der Superklasse an die Subklasse. • Subtypen in Kombination mit Vererbung erlauben eine direkte Realisierung von Klassifikationen im Rahmen der Programmierung. Um Szenarien wie im obigen Beispiel zu vermeiden, sollten Subklassen-Objekte das Verhalten der Superklassen-Objekte spezialisieren und sich ansonsten konform verhalten. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 5.3 Subtypen und Vererbung • Die Vorteile wirken sich vor allem bei der Entwicklung von Programmbibliotheken und Programmgerüsten/Frameworks aus. 1349 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren Abschnitt 5.4 1350 5.4 Objektorientierte Bausteine und Bibliotheken Objektorientierte Bausteine und Bibliotheken Dieser Abschnitt führt in den Komponenten-/Bausteinbegriff und in die Java-Bibliothek ein. Ziel ist die Vertiefung der in 5.3 erläuterten Konzepte und deren Anwendung. Objektorientierte Bausteine und Bibliotheken Überblick: • Bausteine, Schnittstellen und Bibliotheken • Klassen zur Ausnahmebehandlung • Ströme zur Ein- und Ausgabe ©Arnd Poetzsch-Heffter TU Kaiserslautern 1351 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1352 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Unterabschnitt 5.4.1 5.4 Objektorientierte Bausteine und Bibliotheken Bausteine, Schnittstellen und Bibliotheken • Klärung und Diskussion der Begriffe Bausteine, Schnittstellen und Bibliotheken I Programmbaustein, -komponente I API, Programmierschnittstelle I Bibliothek • Überblick über die Java-Bibliothek Dabei verwenden wir die Begriffe ”Programmbaustein” und ”Programmkomponente” hier synonym. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1353 5.4 Objektorientierte Bausteine und Bibliotheken • Wie anpassbar, wie allgemein sind die Bausteine? • Anpassen der Bausteine: • Sind die Bausteine direkt einsetzbar oder müssen sie noch vervollständigt werden? Instanzieren von Parametern Spezialisierung • Sind die Bausteine unabhängig voneinander, hierarchisch strukturiert, wechselseitig abhängig? • Verbinden der Bausteine/Komposition: I • Wie werden sie zusammengesetzt? Verbindungsmechanismen der Komponenten zusätzlicher Programmcode (engl. glue code) ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken Wichtige Fragestellungen: Konstruiere Softwaresysteme aus vorgefertigten Bausteinen durch I 1354 Programmbausteine & Komponenten (2) Idee der komponentenbasierten Softwarekonstruktion: I TU Kaiserslautern 5. Objektorientiertes Programmieren Programmbausteine & Komponenten I ©Arnd Poetzsch-Heffter TU Kaiserslautern • Wie kann man sie auffinden? 1355 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1356 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Programmbausteine & Komponenten (3) Begriffsklärung: (unabhängige Bausteine) Vereinfachend gehen wir davon aus, dass ein Baustein durch eine oder mehrere Typdeklarationen realisiert ist. Die Schnittstelle eines Bausteins entspricht der öffentlichen Schnittstelle dieser Typen. Wir nennen Bausteine oder Programmkomponenten unabhängig, wenn sie ohne Kenntnis und Existenz anderer Bausteine bzw. Komponenten angewandt werden können. Wir betrachten drei Arten von Bausteinen: In der Schnittstelle unabhängiger Bausteine kommen im Wesentlichen nur vordefinierte und Standardtypen vor. • unabhängige Bausteine • eigenständige Bausteine Typische Beispiele sind einfache Behälterbausteine (z.B. SLinkedList), die Klasse String oder die Wrapper-Klassen, aber auch vollständige Anwendungsprogramme. • kooperierende Bausteine Wir erläutern diese Aufteilung jeweils durch Begriffsklärung und Beispiele in Java. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1357 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken Boolean ( boolean value ){ this.value = value; } Boolean ( String s) { this( toBoolean (s) ); } boolean booleanValue (){ return value; } static Boolean valueOf ( String s){...} String toString () { ... } int hashCode () { ... } TU Kaiserslautern 1358 5.4 Objektorientierte Bausteine und Bibliotheken Beispiel: (unabhängiger "Baustein") (2) public final class Boolean implements java.io. Serializable { public static final Boolean TRUE = new Boolean (true); public static final Boolean FALSE = new Boolean ( false); public static final Class <Boolean > TYPE = ...; private final boolean value ; ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren Beispiel: (unabhängiger "Baustein") public public public public public public 5.4 Objektorientierte Bausteine und Bibliotheken } 1359 public boolean equals ( Object obj) { if (obj instanceof Boolean ) { return value == (( Boolean )obj). booleanValue (); } return false ; } public static boolean getBoolean ( String n){..} ©Arnd Poetzsch-Heffter TU Kaiserslautern 1360 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken Bemerkungen: Begriffsklärung: (eigenständige Bausteine) Unabhängigkeit erleichtert das Verständnis von Bausteinen. Trotzdem sind unabhängige Bausteine in Programmbibliotheken eher selten. Wir nennen Bausteine oder Programmkomponenten eigenständig, wenn die Kenntnis und Existenz ihrer Supertypen für ihr Verständnis und ihre Anwendung ausreicht und sie eingesetzt werden können, ohne mit anderen Bausteinen kooperieren zu müssen. Häufig sind unterschiedliche, aber ähnliche Bausteine Teil einer Klassen- bzw. Typhierarchie. Dadurch sind speziellere Bausteine oft von allgemeineren abhängig. In der Schnittstelle eigenständiger Bausteine kommen im Wesentlichen nur vordefinierte Typen, Standardtypen und Supertypen der Klassen vor, die den Baustein implementieren. Typische Beispiele sind komplexere Behälterbausteine und Stromklassen. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1361 5.4 Objektorientierte Bausteine und Bibliotheken 1362 5.4 Objektorientierte Bausteine und Bibliotheken Beispiel: (eigenstängiger Baustein) (2) public interface ListIterator extends Iterator { boolean hasNext (); Object next (); boolean hasPrevious (); Object previous (); int nextIndex (); int previousIndex (); void remove (); void set( Object o); void add( Object o); } Listen mit Iteratoren bilden einen Baustein. Als Beispiel betrachten wir die Typen LinkedList, Iterator und ListIterator aus dem Paket java.util (Version ohne Parametrisierung; Java 4 und früher). public interface Iterator { boolean hasNext (); Object next (); void remove (); } TU Kaiserslautern TU Kaiserslautern 5. Objektorientiertes Programmieren Beispiel: (eigenstängiger Baustein) ©Arnd Poetzsch-Heffter ©Arnd Poetzsch-Heffter 1363 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1364 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Beispiel: (eigenstängiger Baustein) (3) Beispiel: (eigenstängiger Baustein) (4) public class LinkedList extends AbstractSequentialList implements List , Cloneable , Serializable { public LinkedList () public LinkedList ( Collection c) public Object getFirst () public Object getLast () public Object removeFirst () public Object removeLast () public void addFirst ( Object o) public void addLast ( Object o) public boolean contains ( Object o) public int size () public boolean add( Object o) public boolean remove ( Object o) public boolean addAll ( Collection c) ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren public public public public public public public public // ... 1365 } ©Arnd Poetzsch-Heffter boolean addAll (int ix , Collection c) void clear () Object get(int index) Object set(int ix , Object elem) void add(int index , Object elem) Object remove (int index ) int indexOf ( Object o) int lastIndexOf ( Object o) weiter naechste Seite ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren Beispiel: (eigenstängiger Baustein) (5) // ... public public public public public public public public public ... // 5.4 Objektorientierte Bausteine und Bibliotheken 1366 5.4 Objektorientierte Bausteine und Bibliotheken Bemerkung: In Abschnitt 5.4.3 werden wir weitere eigenständige Bausteine kennen lernen. ListIterator listIterator () ListIterator listIterator (int ix) Iterator iterator () List subList (int from , int to) boolean equals ( Object o) int hashCode () Object clone () Object [] toArray () Object [] toArray ( Object a[]) Methoden aus Object Im Allg. agieren Bausteine nicht eigenständig, sondern müssen mit anderen und andersartigen Bausteinen kooperieren, um ihre Funktionalität zu erbringen. Bausteine können eng oder nur lose kooperieren. Enge Kooperation findet man typischerweise in Programmgerüsten (engl. program frameworks). Die Kooperation zwischen Bausteinen kann man syntaktisch an den (rekursiven) Abhängigkeiten der Typdeklarationen erkennen. TU Kaiserslautern 1367 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1368 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Beispiel: (Abhängigkeiten bei Kooperation) 5.4 Objektorientierte Bausteine und Bibliotheken Bemerkung: Folgende Fragmente stammen aus dem AWT (Pakete java.awt, etc.): class Component ... { ... void addComponentListener ( ComponentListener c) ... } • Die Grenzen eines Bausteins werden vom Bausteinentwickler festgelegt und lassen sich im Allg. nicht aus dem Programmtext erschließen. interface ComponentListener ... { ... void componentResized ( ComponentEvent e ); ... } • Die Unterscheidung zwischen den Bausteinarten ist nicht scharf. class ComponentEvent ... { ... Component getComponent () ... ... } ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1369 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren Begriffsklärung: (Programmierschnittstelle) 1370 5.4 Objektorientierte Bausteine und Bibliotheken Beispiele: (Programmierschnittstellen) Es gibt Programmierschnittstellen für den: • Zugriff aufs Dateisystem Die Programmierschnittstelle eines Bausteins (einer Komponente) besteht aus den öffentlichen Typen und Methoden, mit denen der Baustein aus Programmen heraus gesteuert werden kann. • Zugriff auf andere Teile des Betriebssystems • Zugriff aufs Netzwerk In gleicher Weise spricht man von der Programmierschnittstelle einer Anwendung oder eines Systems (engl. application programming interface, API). • Zugriff auf eine Anwendung, etwa ein Spiel Bemerkung Nicht alles, was sich API nennt, ist in obigem Sinne eine Programmierschnittstelle. ©Arnd Poetzsch-Heffter TU Kaiserslautern 1371 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1372 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Begriffsklärung: (Programmbibliothek) 5.4 Objektorientierte Bausteine und Bibliotheken Beispiele: (Programmbibliotheken) • zu Programmiersprachen gehörende Standardbibliotheken (z.B. Java-Bibliothek) Eine Programmbibliothek oder einfach Bibliothek ist eine strukturierte Ansammlung von Programmteilen, die für die Wiederverwendung entwickelt und organisiert sind. • Bibliotheken für Datenstrukturen: STL, Leda, ... • Bibliotheken für graphische Bedienoberflächen, für allgemeine Die Programmteile können unterschiedlicher Art sein (z.B. standardisierte Bausteine der Sprache, eigenständige Bausteine, Programmierschnittstellen, Programmgerüste). Anwendungsbaukästen • Bibliotheken für Graphik, CAD, virtuelle Welten, ... • Anwendungsspezifische Bibliotheken ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1373 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren Wichtige Pakete der Java-Bibliothek 1374 5.4 Objektorientierte Bausteine und Bibliotheken Bemerkung: Die obige Darstellung der Java-Bibliothek ist unvollständig. Beispielsweise enthält das Paket javax.swing ein leistungsfähigeres Programmgerüst zur Realisierung graphischer Bedienoberflächen (GUI Framework). ©Arnd Poetzsch-Heffter TU Kaiserslautern 1375 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1376 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Unterabschnitt 5.4.2 5.4 Objektorientierte Bausteine und Bibliotheken Klassen zur Ausnahmebehandlung Realisierung der Ausnahmebehandlung in Java demonstriert zwei Aspekte: • erweiterbare Hierarchie einfacher Bausteine • Zusammenspiel von Sprache und Standardbibliothek Klassen zur Ausnahmebehandlung Darüber hinaus ist das Verständnis der Ausnahmebehandlung von allgemeinem Interesse für die Softwareentwicklung. Die möglichen Ausnahmesituationen werden in Java durch eine Typhierarchie klassifiziert. Alle Ausnahmeklassen sind Subklassen von java.lang.Throwable . ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1377 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Klassifikation von Ausnahmesituationen 1378 5.4 Objektorientierte Bausteine und Bibliotheken Klassifikation von Ausnahmesituationen (2) 2. Programmierfehler (RuntimeException): Es gibt drei Arten von Ausnahmesituationen: Typische Beispiele: 1. Nicht korrigierbare Ausnahmesituationen (Error): • Dereferenzieren von null (NullPointerException): Drei typische Beispiele: Object ov = null; ov. equals ( new Object () ); • kein Speicherplatz mehr verfügbar zum Erzeugen von Objekten (OutOfMemoryError) • Feldzugriff mit unzulässigem Index • zuviele unbeendete Methodenaufrufe (StackOverflowError) (IndexOutOfBoundsException): int [] iav = new int [37]; int n = iav [333]; • Inkonsistenzen zwischen übersetzten Klassen (z.B. AbstractMethodError) ©Arnd Poetzsch-Heffter TU Kaiserslautern TU Kaiserslautern 1379 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1380 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Klassifikation von Ausnahmesituationen (3) 5.4 Objektorientierte Bausteine und Bibliotheken Beispiel: (anwendungsspezifische Ausnahme) 3. Nicht vermeidbare, aber behandelbare Situationen: Beispiele sind der Zugriff auf eine Ressource, etwa das Netz oder eine Datei, die augenblicklich anderweitig genutzt wird. Abhilfe: • zeitverzögert nochmaligen Zugriff • Anwendung einer vergleichbaren Ressource. In diese Kategorie fallen auch die meisten anwendungsspezifischen Ausnahmen. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1381 public class KeinKaffeeException extends Exception { private float restMenge ; KeinKaffeeException ( float kaffeeMenge ){ restMenge = kaffeeMenge ; } public float getRestMenge () { return restMenge ; } } ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren Hierarchie der Ausnahmetypen 1382 5.4 Objektorientierte Bausteine und Bibliotheken Zusammenspiel von Sprache und Bibliothek Die Ausnahmebehandlung in Java hat vier Aspekte: 1. Welche Ausnahmen gibt es? 2. Wodurch werden Ausnahmen ausgelöst? 3. Wie werden Ausnahmen ggf. über Methodengrenzen hinweg weitergereicht? 4. Wie kann man Ausnahmen abfangen und behandeln? ©Arnd Poetzsch-Heffter TU Kaiserslautern 1383 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1384 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Zusammenspiel von Sprache und Bibliothek (2) 5.4 Objektorientierte Bausteine und Bibliotheken Zusammenspiel von Sprache und Bibliothek (3) 1. Aspekt: 3. Aspekt: Ausnahmen als Subklassen von Throwable realisiert; d.h. Behandlung von Ausnahmen: • vordefinierte Ausnahmen in der Standardbibliothek • im umfassenden try-Block; • benutzerdefinierte Ausnahmen als Subklassen • die aktuelle Methode terminiert abrupt und reicht die Ausnahme an die Aufrufstelle weiter. 2. Aspekt: Fehler und Laufzeitausnahmen werden durch das Laufzeitsystem von Java (Java Virtual Machine) ausgelöst. Der Java-Übersetzer prüft, welche Ausnahmen eine Methode möglicherweise auslöst, ohne sie abzufangen. Andere Ausnahmen durch Systemschnittstellen oder Anwenderprogramme mittels der throw-Anweisung. Alle nicht-abgefangenen Ausnahmen, die weder Subklassen von Error noch von RunTimeException sind, müssen in der Signatur der Methode deklariert werden (siehe Beispiel). Der Ausdruck in der throw-Anweisung muss von einem Subtyp von Throwable sein. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1385 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren Zusammenspiel von Sprache und Bibliothek (4) 1386 5.4 Objektorientierte Bausteine und Bibliotheken Beispiel: (Ausnahmebehandlung) 4. Aspekt: Mittels der try-catch-Anweisung kann man Ausnahmen (und Fehler) abfangen: try { <Anweisungsblock1 > } catch( <Subtyp von Throwable > eb ) { <Anweisungsblock2 > } ... Tritt im Anweisungsblock1 eine Ausnahme vom Typ E auf und ist E ein Subtyp des Typs, der in der catch-Klausel genannt ist, dann wird die Ausnahme abgefangen und der Anweisungsblock2 ausgeführt. public class KaffeeMaschine { private KaffeeSpeicher speicher ; ... void fuellenFilter ( float benoetigteMenge ) throws KeinKaffeeException { float restMenge ; restMenge = speicher . messenFuellung (); if( restMenge < benoetigteMenge ) { throw new KeinKaffeeException ( restMenge ); } ... } } Andernfalls wird die Ausnahme weitergereicht. ©Arnd Poetzsch-Heffter TU Kaiserslautern 1387 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1388 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Bemerkung: 5.4 Objektorientierte Bausteine und Bibliotheken Unterabschnitt 5.4.3 • Häufig kann die Behandlung der Ausnahme erst von einem weiter außen liegenden Aufrufer erledigt werden. Ströme zur Ein- und Ausgabe • Eine überschreibende Methode darf nur die Ausnahmen auslösen, die auch die überschriebene Methode auslösen darf. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1389 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren 1390 5.4 Objektorientierte Bausteine und Bibliotheken Ströme zur Ein- und Ausgabe Ströme zur Ein- und Ausgabe (2) Ein- und Ausgabe von Daten wird heutzutage meist durch Ströme modelliert. Sowohl beim Schreiben in einen Strom als auch beim Lesen aus einen Strom kann es zu Verzögerungen kommen: Begriffsklärung: (Datenstrom) • beim Lesen, weil augenblicklich kein Zeichen vorhanden, der Strom aber noch nicht zu Ende ist; Ein Strom ist eine potentiell unendliche Folge von Daten. Er wird von einer oder mehrerer Quellen mit Daten versorgt und erlaubt es, diese Daten der Reihe nach aus dem Strom herauszulesen. Die Verzögerungen führen zu einer Blockierung der ausgeführten Methode. Das Ende eines Stromes wird durch ein spezielles Datum (in Java ist das -1) markiert. ©Arnd Poetzsch-Heffter TU Kaiserslautern • beim Schreiben, weil ggf. kein Platz im Strom vorhanden ist. 1391 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1392 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Bemerkung: 5.4 Objektorientierte Bausteine und Bibliotheken Einführung in Ströme • Stromklassen sind in diesem Kontext interessant: I als wichtige Programmierschnittstelle I als Beispiel für Typhierarchien und eigenständige Bausteine I als Beispiel für Komposition von Bausteinen Wir betrachten zunächst Ströme zum Lesen: interface CharEingabeStrom { int read () throws IOException ; } • vergleiche auch unendliche Listen in Haskell (vgl. F. 306). ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1393 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken Einführung in Ströme (2) Lesen aus einer Datenstruktur: Diese Schnittstelle abstrahiert von der Quelle aus der gelesen wird. Mögliche Quellen: Wir betrachten das schrittweise Lesen der Zeichen eines Strings. Die Quelle des Stroms wird dem Stromkonstruktor übergeben. public class StringLeser implements CharEingabeStrom { private char [] dieZeichen ; private int index = 0; 1. Datenstruktur wie Feld, Liste, String. 2. Datei public StringLeser ( String s ) { dieZeichen = s. toCharArray (); } 3. Netzwerk 4. Standardeingabe, z.B. interaktive Eingabe vom Anwender 5. andere Programme 6. andere Ströme } Wir betrachten hier die Fälle 1, 2 und 6 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1394 1395 public int read () { if( index == dieZeichen . length ) return -1; else return dieZeichen [index ++]; } ©Arnd Poetzsch-Heffter TU Kaiserslautern 1396 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Zusammenbauen von Strömen: 5.4 Objektorientierte Bausteine und Bibliotheken Zusammenbauen von Strömen: (2) public class GrossBuchstabenFilter implements CharEingabeStrom { private CharEingabeStrom eingabeStrom ; Wir betrachten zwei Stromklassen, die aus anderen Strömen lesen und die Ströme modifizieren. public GrossBuchstabenFilter ( CharEingabeStrom cs ) { eingabeStrom = cs; } Die Konstruktoren nehmen dabei einen beliebigen CharEingabeStrom als Quelle: → Subtyping at its best! } ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1397 public int read () throws IOException { int z = eingabeStrom .read (); if( z == -1 ) { return -1; } else { return Character . toUpperCase ( (char)z ); } } ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Zusammenbauen von Strömen: (3) public UmlautSzFilter ( CharEingabeStrom cs ){ eingabeStrom = cs; } public int read () throws IOException { if( puffer != -1 ) { int z = puffer ; puffer = -1; return z; } else { ... TU Kaiserslautern 1398 5.4 Objektorientierte Bausteine und Bibliotheken Zusammenbauen von Strömen: (4) public class UmlautSzFilter implements CharEingabeStrom { private CharEingabeStrom eingabeStrom ; private int puffer = -1; ©Arnd Poetzsch-Heffter TU Kaiserslautern } } } int z = eingabeStrom .read (); if( z == -1 ) return -1; switch ( (char)z ) { case ’\u00C4 ’: puffer = ’e’; case ’\u00D6 ’: puffer = ’e’; case ’\u00DC ’: puffer = ’e’; case ’\u00E4 ’: puffer = ’e’; case ’\u00F6 ’: puffer = ’e’; case ’\u00FC ’: puffer = ’e’; case ’\u00DF ’: puffer = ’s’; default : return z; } return return return return return return return ’A’; ’O’; ’U’; ’a’; ’o’; ’u’; ’s’; Folgendes Programm zeigt Zusammenbau und Anwendung von Strömen: 1399 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1400 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken Zusammenbauen von Strömen: (5) Adaption von Strömen: public class Main { public static void main( String [] a) throws IOException { String s = new String ("\ u00C4neas opfert den " + "G\ u00D6ttern edle \u00D6le ,\ nauf da\u00DF " + "\ u00FCberall das \ u00DCbel sich \ u00E4ndert ."); Adaption bedeutet in der Objektorientierung meist das Anpassen einer Schnittstelle an die Bedürfnisse eines Anwenders. } } Als kleines Beispiel einer Adaption betrachten wir die typmäßige Anpassung der Klasse FileReader aus java.io an CharEingabeStrom: CharEingabeStrom cs = new StringLeser ( s ); cs = new UmlautSzFilter ( cs ); cs = new GrossBuchstabenFilter ( cs ); int z = cs.read (); while ( z != -1 ) { System .out. print ( (char)z ); z = cs.read (); } System .out. println (""); ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1401 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken Adaption von Strömen: (2) Javas Stromklassen Da FileReader eine Methode read mit der gleichen Signatur und Bedeutung wie in CharEingabeStrom bereitstellt, reicht folgende fast triviale Adaptionsklasse: Stromklassen werden nach den Datentypen, die sie verarbeiten, und ihre Quellen bzw. Senken klassifiziert. public class DateiLeser extends FileReader implements CharEingabeStrom { } Stromklassen sind wichtige programmiertechnische Hilfsmittel und ihre Hierarchien ein gutes Beispiel für eigenständige Bausteine. public DateiLeser ( String s ) throws IOException { super (s); } ©Arnd Poetzsch-Heffter TU Kaiserslautern 1402 Die Reader-/Writer-Klassen aus dem Paket java.io verarbeiten char-Ströme; die Input-/Output-Stromklassen verarbeiten byte-Ströme. 1403 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1404 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Javas Stromklassen (2) Javas Stromklassen (3) Die Reader-Klassen unterstützen: Die Writer-Klassen unterstützen: • das Schreiben einzelner Zeichen: • das Lesen einzelner Zeichen: int read(); void write( int ) ; • das Lesen mehrerer Zeichen aus der Quelle und Ablage in ein char-Feld: int read(char[]); • das Schreiben mehrerer Zeichen eines char-Feldes: • das Überspringen einer Anzahl von Zeichen der Eingabe: long skip(long); void write(char []) u. ä.; • die Abfrage, ob der Strom für das Lesen des nächsten Zeichens bereit ist; • das Schreiben mehrerer Zeichen eines String: • das Schließen des Eingabestroms: void close(); void write( String ) • Methoden zum Markieren und Zurücksetzen des Stroms. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken u. ä.; 1405 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren Javas Stromklassen (4) 1406 5.4 Objektorientierte Bausteine und Bibliotheken Reader-/Writer-Klassen: Die Reader-Klassen unterscheiden sich im Wesentlichen durch ihre Quelle: • die Ausgabe ggf. im Strom gepufferter Zeichen: void flush () ; • das Schließen des Ausgabestroms: void close (). Die genannten Methoden lösen möglicherweise eine IOException aus. Die von InputStream bzw. OutputStream abgeleiteten Klassen leisten Entsprechendes für Daten vom Typ byte. ©Arnd Poetzsch-Heffter TU Kaiserslautern 1407 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1408 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Reader-/Writer-Klassen: (2) Reader-Klasse InputStreamReader FileReader BufferedReader LineNumberReader PipedReader FilterReader PushBackReader CharArrayReader StringReader ©Arnd Poetzsch-Heffter Quelle InputStream byte-Strom aus Datei Reader Reader PipedWriter Reader Reader char[] String Reader-/Writer-Klassen: (3) Bemerkung puffernd; können zeilenweise lesen Methode unread Writer arbeiten analog zu Reader-Klassen, nur in umgekehrter Richtung. PrintWriter unterstützen die formatierte Ausgabe von Daten durch die Methoden print und println, die alle Standarddatentypen als Parameter nehmen. TU Kaiserslautern 5. Objektorientiertes Programmieren 1409 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren Bemerkung: 1410 5.4 Objektorientierte Bausteine und Bibliotheken Beispiel: (Reader-/Writer-Klassen) public class DateiZugriff { public static String lesen( String datei ) throws FileNotFoundException , IOException { BufferedReader in = new BufferedReader (new FileReader (datei)); String line , inputstr = ""; line = in. readLine (); while ( line != null ){ inputstr = inputstr . concat ( line+"\n"); line = in. readLine (); } in. close (); return inputstr ; } Die Konstruktoren ermöglichen das Zusammenhängen von Strömen; hier am Beispiel eines Konstruktors der Klasse PrintWriter: public PrintWriter ( OutputStream o, boolean af ) { this( new BufferedWriter ( new OutputStreamWriter (o)), af ); } ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 1411 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1412 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Beispiel: (Reader-/Writer-Klassen) (2) Beispiel: (Reader-/Writer-Klassen) (3) public class DateiZugriffTest { public static void main( String [] argf ){ String s; try { s = DateiZugriff .lesen ( argf [0] ); } catch( FileNotFoundException e ){ System .out. println ("Can ’t open "+ argf [0]); return ; } catch( IOException e ){ System .out. println (" IOException : "+ argf [0]); return ; } public static void schreiben ( String datei , String s) throws IOException { PrintWriter out; out = new PrintWriter ( new FileWriter ( datei ) ); out. print ( s ); out. close (); } } ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1413 } ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren Beispiel: (Reader-/Writer-Klassen) (4) } 5.4 Objektorientierte Bausteine und Bibliotheken 1414 5.4 Objektorientierte Bausteine und Bibliotheken Input-/Outputstream-Klassen: try { DateiZugriff . schreiben (" ausgabeDatei ",s); } catch ( IOException e ){ System .out. println ("Can ’t open "+ argf [0] ); } ©Arnd Poetzsch-Heffter TU Kaiserslautern 1415 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1416 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken Objektströme Objektströme (2) Das Lesen und Schreiben von den Werten der elementaren Datentypen ist relativ einfach. Sie besitzen eindeutige Repräsentationen. Andererseits ist Ein- und Ausgabe von Objekten wichtig, um Die Ein- und Ausgabe von Objekten ist komplexer: • Objekte zwischen Prozessen auszutauschen; • Der Zustand reicht zur Repräsentation eines Objektes nicht aus. • Objekte für nachfolgende Programmläufe zu speichern, d.h. • Objektreferenzen besitzen nur innerhalb des aktuellen Prozesses persistent zu machen. eine Gültigkeit. • Bei Objekten ist häufig ihre Rolle im Objektgeflecht von entscheidender Bedeutung. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1417 5.4 Objektorientierte Bausteine und Bibliotheken 1418 5.4 Objektorientierte Bausteine und Bibliotheken Beispiel: (Objekte: Wie ausgeben?) (2) Was bedeutet es, das von ll referenzierte Objekt auszugeben(?): LinkedList ll = new LinkedList (); StringBuffer s = new StringBuffer ("Sand"); ll.add("Sich "); ll.add("mit "); ll.add(s); ll.add("alen "); ll.add("im "); ll.add(s); ll.add(" aalen "); TU Kaiserslautern TU Kaiserslautern 5. Objektorientiertes Programmieren Beispiel: (Objekte: Wie ausgeben?) ©Arnd Poetzsch-Heffter ©Arnd Poetzsch-Heffter • nur das LinkedList-Objekt ausgeben; • das LinkedList-Objekt und die zugehörigen Entry-Objekte ausgeben; • das LinkedList-Objekt, die zugehörigen Entry-Objekte sowie die String-Objekte und das StringBuffer-Objekt ausgeben. 1419 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1420 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken Ausgabe von Objektgeflechten Beispiel: (Ausgabe von Objektgeflechten) Um Objekte in ihrem Zusammenwirken mit anderen Objekten wieder einlesen zu können, müssen sie gemeinsam mit allen erreichbaren Objekten ausgegeben werden. Sei die Variable ll wie in obigem Beispiel: OutputStream os = new FileOutputStream (" ausgabeDatei "); ObjectOutputStream oos = new ObjectOutputStream ( os ); oos. writeObject ( ll ); Dabei bekommen sie eine Kennung, die relativ zu den anderen Objekten des Geflechts eindeutig ist. Der Methodenaufruf in der letzten Zeile führt zur Ausgabe aller von ll aus erreichbaren Objekte in die Datei mit Namen „ausgabeDatei“. Wg. möglicher Zyklen ist die Implementierung der Ausgabe und des Einlesens von Geflechten nicht einfach. Darum gibt es dafür eine Unterstützung in der Bibliothek. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1421 5.4 Objektorientierte Bausteine und Bibliotheken 1422 5.4 Objektorientierte Bausteine und Bibliotheken Beispiel: (Einlesen von Objektgeflechten) Das Einlesen von Objekten und den mit ihnen abgelegten erreichbaren Objekten birgt eine weitere Schwierigkeit: Beim Einlesen müssen Objekte erzeugt werden. Dafür müssen alle Klassen der einzulesenden Objekte und geeignete Konstruktoren zur Verfügung stehen. (Zum Auffinden benutzt Java die Mechanismen der Reflexion.) TU Kaiserslautern TU Kaiserslautern 5. Objektorientiertes Programmieren Ausgabe von Objektgeflechten ©Arnd Poetzsch-Heffter ©Arnd Poetzsch-Heffter 1423 LinkedList inll; InputStream is = new FileInputStream (" ausgabeDatei "); ObjectInputStream ois = new ObjectInputStream ( is ); try { inll = ( LinkedList )ois. readObject (); } catch( ClassNotFoundException exc ) { System .out. println (" Klasse zu Objekt fehlt"); } Der Methodenaufruf ois.readObject() liest ein Objektgeflecht aus der Datei mit Namen „ausgabeDatei“ ein. ©Arnd Poetzsch-Heffter TU Kaiserslautern 1424 5. Objektorientiertes Programmieren 5.4 Objektorientierte Bausteine und Bibliotheken 5. Objektorientiertes Programmieren Zur Beachtung: 5.4 Objektorientierte Bausteine und Bibliotheken Beispiel: (Ausgabe u. Einlesen von Objekten) Ausgabe und Einlesen der von a und c referenzierten Objekte und Geflechte: • Gibt man ein Objekt mit den erreichbaren Objekten aus und liest es wieder ein, entsteht eine Kopie. • Referenziert man von mehreren Variablen Teile des gleichen Geflechts, kommt es beim Einlesen ggf. zu mehreren Kopien eines Objekts des ursprünglichen Geflechts. ©Arnd Poetzsch-Heffter TU Kaiserslautern 5. Objektorientiertes Programmieren 1425 ©Arnd Poetzsch-Heffter 5.4 Objektorientierte Bausteine und Bibliotheken TU Kaiserslautern 5. Objektorientiertes Programmieren Begriffsklärung: (Serialisieren) 1426 5.4 Objektorientierte Bausteine und Bibliotheken Bemerkung: • Serialisieren hat zwei zentrale Anwendungen: Serialisieren bedeutet alle von einem Objekt aus erreichbaren Objekte der Reihe nach in kodierter Form in einen Strom zu schreiben. I Persistenz von Objekten zu unterstützen; I Parameterübergabe bei der verteilten objektorientierten Programmen zu realisieren. • Der Serialisierungsmechanismus muss im Allg. Zugriff auf private Deserialisieren bezeichnet den umgekehrten Prozess. Daten haben und adaptierbar sein. • In Java wird die Serialisierbarkeit der Objekte einer Klasse K dadurch ausgedrückt, dass K die Schnittstelle Serializable implementiert. ©Arnd Poetzsch-Heffter TU Kaiserslautern 1427 ©Arnd Poetzsch-Heffter TU Kaiserslautern 1428