Objektorientierte Implementierung mit Java-Datenstrukturen Objektorientierte Implementierung 10 Verfeinern von Assoziationen mit dem Java-2 Collection Framework 11 Programmieren gegen Schnittstellen Auswahl von Datenstrukturen 11) Programmieren gegen Schnittstellen Persistente Datenhaltung "Der Aufrufer programmiert gegen die Schnittstelle, er befindet sich sozusagen im luftleeren Raum." Siedersleben/Denert, Wie baut man Informationssysteme, Informatik-Spektrum, August 2000 Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann 1 Softwaretechnologie Typanpassungen mit Schnittstellen: Geordnete Listen mit ArrayList (1) Schnittstellen und Implementierungen im Collection-Framework <<interface>> List import java.util.ArrayList; ... class Bestellung { private String kunde; private ArrayList liste; private int anzahl = 0; Vererbung (extends) <<interface>> Collection Implementierung (implements) <<interface>> Set 2 <<interface>> Map public Bestellung(String kunde) { this.kunde = kunde; this.liste = new ArrayList(); } <<interface>> SortedSet ArrayList LinkedList Softwaretechnologie HashSet <<interface>> SortedMap public void neuePosition (Bestellposition b) { liste.add(b); } public void loeschePosition (int pos) { liste.remove(pos); } ... HashMap TreeSet TreeMap 3 Softwaretechnologie 4 Anwendungsbeispiel mit ArrayList (falsch!) Typanpassungen auf Elementtypen * ... public void sonderpreis (int pos, int preis) { liste.get(pos).einzelpreis(preis); } ... ► Object Bestellung – kunde: String – anzahl: int „Method einzelpreis(int) not found in class java.lang.Object.“ ? defi niert auf Bestellposition hier: (Bestellposition)liste.get(pos) 5 Softwaretechnologie 6 Geordnete Collections II java.util.LinkedList (Auszug) Anwendungsbeispiel mit ArrayList (2) public void sonderpreis (int pos, int preis) { ((Bestellposition)liste.get(pos)).einzelpreis(preis); } public int auftragssumme() { int s = 0; for(int i=0; i<liste.size(); i++) s += ((Bestellposition)liste.get(i)).positionspreis(); return s; } public void print () { System.out.println("Bestellung fuer Kunde "+kunde); for(int i=0; i<liste.size(); i++) System.out.println(liste.get(i)); System.out.println("Auftragssumme: "+auftragssumme()); System.out.println(); } Online: Bestellung1.java Softwaretechnologie Bestellposition ( Typ ) Objekt Spezialisierung von Object auf Bestellposition? Softwaretechnologie Zusicherung: Alle von einem Bestellung-Objekt über die liste-Assoziation erreichbaren Objekte sind aus der Klasse Bestellposition. Typanpassung (cast): • Operationen der Oberklasse passen immer auch auf Objekte der Unterklasse • Operationen der Unterklasse auf Objekte einer Oberklasse anzuwenden, erfordert explizite Typanpassung (dynamic cast): liste.get(pos).einzelpreis(preis); } java.util.ArrayList add(Object o) liste get(pos: int): Object ... * Compilermeldung: ArrayList Object 1 7 public class LinkedList implements List { public boolean add (Object o); public boolean remove (Object o); public void clear(); public boolean isEmpty(); public boolean contains (Object o); public int size(); public Object get (int index); public Object set (int index, Object element) public Object remove (int index); public int indexOf (Object o); public void addFirst (Object o); public void addLast (Object o); ... Anwendungsbeispiel Online: } mit LinkedList: Bestellung3.java Softwaretechnologie 8 Programmieren gegen Schnittstellen -- Polymorphe Container Polymorphe Container durch Schnittstellen class Bestellung { ! List ist ein Interface, keine Klasse ! private String kunde; private List liste; ... // Konstruktor sh. nächste Folien public void neuePosition (Bestellposition b) { liste.add(b); } public void loeschePosition (int pos) { liste.remove(pos); } public void sonderpreis (int pos, int preis) { ((Bestellposition)liste.get(pos)).einzelpreis(preis); } Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann Polymorphe Container: Wechsel der Datenstruktur • ArrayList: class Bestellung { private String kunde; private List liste; public Bestellung(String kunde) { this.kunde = kunde; this.liste = new ArrayList(); } ... 9 Softwaretechnologie Standardalgorithmen in der Algorithmenklasse java.util.Collections ! List ist ein Interface, keine Klasse ! ► ■ ■ Hier: java.util.Collections enthält Algorithmen auf beliebigen Klassen, die das Collection- bzw. List-Interface implementieren Bei manchen Operationen ist Ordnung auf Elementen vorausgesetzt. Achtung: Statische Operationen! public class Collections { public static Object max (Collection coll); class Bestellung { Softwaretechnologie Algorithmenklassen: enthalten Algorithmen, die auf einer Familie von anderen Klassen arbeiten ■ • LinkedList: private String kunde; private List liste; public Bestellung(String kunde) { this.kunde = kunde; this.liste = new LinkedList(); } ... 10 public static Object min (Collection coll); public static int binarySearch(List list, Object key); Code muß bei Wechsel der Datenstruktur nur an einer Stelle (Konstruktor) geändert werden ! 11 public static void reverse (List list); public static void sort (List list) ... } Softwaretechnologie 12 Entwurfsmuster Iterator (Implementierungsmuster) Prädikat-Schnittstellen (...able Schnittstellen) ► Schnittstellen, die die Eigenschaft einer Klasse ausdrücken, werden oft mit dem Suffix “able” benannt: ■ ■ ■ ► ► Name: Iterator (auch: Stream, Cursor, Enumeration) ► Problem: Sequentielles Durchlaufen der Elemente eines zusammengesetzten Objekts oder einer Collection. Iterable Clonable Serializable Beispiel: geordnete Standarddatentypen (z.B. String oder List) implementieren Comparable: ► ■ Aufzählen der in einem “Behälter” befindlichen Elemente durch Herausziehen (pull) ■ Keine Aussage über die Reihenfolge! Lösung: Iterator {abstract} public interface Comparable { public int compareTo (Object o); } ► pull.. next() hasNext() Aggregate elements(): Iterator Resultat ist kleiner/gleich/größer 0: genau dann wenn "this" kleiner/gleich/größer als Objekt o <<create>> ConcreteIterato r Element 13 Softwaretechnologie 14 Softwaretechnologie Iterator-Implementierungsmuster Iterator-Beispiel in der JDK (ArrayList) ► Verwendungsbeispiel: <<interface>> java.util.Iterator Iterator hasNext() next() Aggregate Bestellung – kunde: String – anzahl: int 1 java.util.ArrayList add(o: Object) liste get(pos: int): Object <<create>> iterator(): Iterator ... Klassenname nicht * Element Softwaretechnologie List list; .. Iterator i = list.iterator(); while (i.hasNext()) { doSomeThing(i.next()); } Concrete Iterator bekannt, weil privat (z.B. ArrayListIterator) Object 15 Softwaretechnologie 16 Anwendungsbeispiel mit Iteratoren Objektorientierte Implementierung mit Java-Datenstrukturen import java.util.Iterator; ... class Bestellung { private String kunde; private ArrayList liste; Auswahl von Datenstrukturen ... public int auftragssumme() { Iterator i = liste.iterator(); int s = 0; while (i.hasNext()) s += ((Bestellposition)i.next()).positionspreis(); return s; } ... } Online: Bestellung2.java 17 Softwaretechnologie Weitere Implementierungen in der CollectionHierarchie Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann 18 Welche Listen-Implementierung soll man wählen? Gemessener relativer Aufwand für Operationen auf Listen: (aus Eckel, Thinking in Java, 2nd ed., 2000) Typ Lesen Iteration Einfügen Entfernen array 1430 3850 --ArrayList 3070 12200 500 46850 LinkedList 16320 9110 110 60 Vector 4890 16250 550 46850 ► Vererbung (extends) <<interface>> Collection <<interface>> List Implementierung (implements) <<interface>> Set <<interface>> Map <<interface>> SortedSet <<interface>> SortedMap Vector Softwaretechnologie HashSet HashMap TreeSet Hashtable TreeMap 19 Stärken von ArrayList: ■ ► ArrayList LinkedList ► ► wahlfreier Zugriff Stärken von LinkedList: ■ Iteration ■ Einfügen und Entfernen irgendwo in der Liste Vector generell die langsamste Lösung Softwaretechnologie 20 Collection Framework (Überblick) Vererbung (extends) <<interface>> Collection <<interface>> List Ungeordnete Mengen: java.util.Set (Auszug) public interface Set { Implementierung (implements) <<interface>> Set <<interface>> SortedSet public public public public public public ... public public ... public <<interface>> Map <<interface>> SortedMap ArrayList LinkedList HashSet HashMap TreeSet TreeMap 21 Softwaretechnologie Anwendungsbeispiel für Set boolean add (Object o); boolean remove (Object o); void clear(); boolean isEmpty(); boolean contains (Object o); int size(); boolean equals (Object o); int hashCode(); Iterator iterator(); } Softwaretechnologie 22 java.util.HashSet (Auszug) public class HashSet implements Set ... { public HashSet (int initialCapacity, float loadFactor); ... public boolean add (Object o); public boolean remove (Object o); public void clear(); public boolean isEmpty(); public boolean contains (Object o); public int size(); public boolean equals (Object o); public int hashCode(); ... public Iterator iterator(); } Warengruppe – name: String – lagerplatz: String + add (a: Artikel) + anzahl(): int 1 * Artikel – name: String – preis: int + preis(): int (Anmerkung: Erläuterung von Hashfunktionen folgt etwas später !) Softwaretechnologie 23 Softwaretechnologie 24 Anwendungsbeispiel mit HashSet Wann sind Objekte gleich? (1) class Warengruppe { private String name; private String lagerplatz; private Set inhalt; public Warengruppe (String name, String lagerplatz) { this.name = name; this.lagerplatz = lagerplatz; this.inhalt = new HashSet(); } public void add (Artikel a) { inhalt.add(a); } public int anzahl() { return inhalt.size(); } public String toString() { String s = "Warengruppe "+name+"\n"; Iterator it = inhalt.iterator(); while (it.hasNext()) { s += " "+(Artikel)it.next(); }; Online: } Warengruppe0.java } ► 25 Softwaretechnologie ► Vergleich mit Operation == : ■ Referenzgleichheit, d.h. physische Identität der Objekte ■ Typischer Fehler: Stringvergleich mit "==" (ist nicht korrekt, geht aber meistens gut!) Vergleich mit o.equals(): ■ deklariert in java.lang.Object ■ überdefiniert in vielen Bibliotheksklassen . ■ z.B. java.lang.String für selbstdefinierte Klassen . Standardbedeutung Referenzgleichheit . bei Bedarf selbst überdefinieren ! (Ggf. für kompatible Definition der Operation o.hashCode() aus java.lang.Object sorgen) Online: Warengruppe1.java 26 Softwaretechnologie Wann sind Objekte gleich? (2) Wann sind Objekte gleich? (3) public static void main (String[] args) { Warengruppe w1 = new Warengruppe("Moebel","L1"); w1.add(new Artikel("Tisch",200)); w1.add(new Artikel("Stuhl",100)); w1.add(new Artikel("Schrank",300)); w1.add(new Artikel("Tisch",200)); System.out.println(w1); } public static void main (String[] args) { Artikel tisch = new Artikel("Tisch",200); Artikel stuhl = new Artikel("Stuhl",100); Artikel schrank = new Artikel("Schrank",300); } Warengruppe w2 = new Warengruppe("Moebel","L2"); w2.add(tisch); w2.add(stuhl); w2.add(schrank); w2.add(tisch); System.out.println(w1); Systemausgabe beim Benuten der Standard-Gleichheit: Systemausgabe: Warengruppe Moebel Tisch(200) Tisch(200) Schrank(300) Stuhl(100) Warengruppe Moebel Schrank(300) Tisch(200) Stuhl(100) Es wurde zweifach dasselbe Tisch-Objekt übergeben ! (Gleiches Verhalten bei Strukturgleichheit, s. Warengruppe1.java) Online: Warengruppe0.java Softwaretechnologie 27 Softwaretechnologie 28 Delegation vs. Vererbung class Warengruppe { … private Set inhalt; } java.util.SortedSet (Auszug) public interface SortedSet extends Set { Delegation public public public public public public ... public public public ... public public public Warengruppe (…) { … this.inhalt = new HashSet(); } public void add (Artikel a) { inhalt.add(a); } … class Warengruppe extends HashSet { … Vererbung public Warengruppe (…) { super(); … } … // keine explizite add-Operation nötig ! } 29 ► java.util.TreeSet implementiert ein geordnete Menge und benötigt Schnittstelle Comparable ► Modifi kation der Klasse Warengruppe: class Warengruppe { private Set inhalt; public Warengruppe (…) { … this.inhalt = new TreeSet(); } … Systemreaktion: } ► Artikel muss von Schnittstelle Comparable erben ► Modifikation der Klasse „Artikel“: class Artikel implements Comparable { ... public int compareTo (Object o) { return name.compareTo(((Artikel)o).name); } } Systemausgabe: Warengruppe Moebel Schrank(300) Stuhl(100) Tisch(200) java.util.TreeSet: public class TreeSet … implements SortedSet … { … } Softwaretechnologie 30 Softwaretechnologie Exception in thread "main" java.lang.ClassCastException: Artikel at java.util.TreeMap.compare(TreeMap.java, Compiled Code) ► Object first(); Object last(); ... Anwendungsbeispiel mit TreeSet java.util.TreeSet ► boolean equals (Object o); int hashCode(); Iterator iterator(); } Warengruppe2.java Softwaretechnologie boolean add (Object o); boolean remove (Object o); void clear(); boolean isEmpty(); boolean contains (Object o); int size(); Online: Warengruppe3.java 31 Softwaretechnologie 32 HashSet oder TreeSet? ► Enthalten 106,5 177,4 Iteration 39,39 40,04 <<interface>> List <<interface>> Map <<interface>> SortedSet in allen Fällen schneller ! HashSet LinkedList erlaubt Operationen für sortierte Mengen HashMap TreeSet Softwaretechnologie 33 java.util.Map (Auszug) TreeMap 34 Softwaretechnologie Anwendungsbeispiel public interface Map { ... public boolean containsKey (Object key); public boolean containsValue (Object value); public Object get (Object key); public Object put (Object key, Object value); public Object remove (Object key); public int size(); public Set keySet(); public Collection values(); ... } Katalog – name: String + put (code: String, a: Artikel) + get (code: String): Artikel + anzahl(): int code: String * 1 Artikel – name: String – preis: int HashMap ist eine sehr günstige Umsetzung für qualifizierte Assoziationen: Der Qualifikator bildet den Schlüssel; die Zielobjeke den Wert + preis(): int Eine Map ist ein „assoziativer Speicher“ (associative array) Softwaretechnologie <<interface>> SortedMap ArrayList Stärken von TreeSet: ■ Implementierung (implements) <<interface>> Set Stärken von HashSet: ■ ► Einfügen 36,14 150,6 Vererbung (extends) <<interface>> Collection Gemessener relativer Aufwand für Operationen auf Mengen: (aus Eckel, Thinking in Java, 2nd ed., 2000) Typ HashSet TreeSet ► Collection Framework (Überblick) 35 Softwaretechnologie 36 Testprogramm für Anwendungsbeispiel: Speicherung der Waren mit Schlüsseln Anwendungsbeispiel mit HashMap class Katalog { private String name; private Map inhalt; public Katalog (String name) { this.name = name; this.inhalt = new HashMap(); } public void put (String code, Artikel a) { inhalt.put(code,a); } public int anzahl() { return inhalt.size(); } public Artikel get (String code) { return (Artikel)inhalt.get(code); } ... Online: } Katalog.java 37 Softwaretechnologie Prinzip der Hashtabelle ► Katalog k = new Katalog("Katalog1"); Systemausgabe: k.put("M01",tisch); Katalog Katalog1 k.put("M02",stuhl); M03 -> Schrank(300) M02 -> Stuhl(100) k.put("M03",schrank); M01 -> Tisch(200) System.out.println(k); Katalog Katalog1 k.put("M03",regal); M03 -> Regal(200) M02 -> Stuhl(100) System.out.println(k); M01 -> Tisch(200) } put(...) überschreibt vorhandenen Eintrag (Ergebnis = vorhandener Eintrag). Ordnung auf den Schlüsseln: SortedMap (Implementierung z.B.TreeMap). 38 Softwaretechnologie Kollision beim Einstechen Typischerweise wird der Schlüssel (key) vor dem Einstechen auf einen Zahlenbereich modulo der Kapazität der Hashtabelle abgebildet, d.h., der Schlüssel wird auf die Hashtabelle “normiert” (hash code) hashtab Object public static void main (String[] args) { Artikel tisch = new Artikel("Tisch",200); Artikel stuhl = new Artikel("Stuhl",100); Artikel schrank = new Artikel("Schrank",300); Artikel regal = new Artikel("Regal",200); 0 ► Die Hashfunktion ist mehrdeutig (nicht injektiv): ■ Bei nicht eindeutigen Schlüsseln, oder auch durch die Normierung, werden Einträge doppelt “adressiert” (Kollision) 0 key1: Object hashCode(): int value1: Object key2: Object key: Object key.hashCode() value: Object value2: Object value: Object Verfahren zur Kollisionsauflösung: – Überlauflisten – Überlauf in der Hashtabelle Effekt von hashtab.put(key,value) Softwaretechnologie key1.hashCode() value?: Object = key2.hashCode() capacity 39 Softwaretechnologie capacity 40 Suche nach vorgefertigten Lösungen (Collection-Klassen der Bibliothek) Vorgehensweise beim Datenstruktur-Entwurf Collection Identifi kation der Anforderungen an die Datenstruktur: Funktionalität, häufi g benutzte Operationen Map Einfügen eines Elements Entfernen eines Elements Aufzählen aller Elemente "ist enthalten"-Abfrage dynamisch erweiterbar Abstraktion auf die wesentlichen Eigenschaften Einfügen eines Werts für einen Schlüssel Entfernen eines Schlüssel/Wert-Paars Abfrage eines Werts für einen Schlüssel "ist enthalten"-Abfrage für Schlüssel dynamisch erweiterbar Suche nach vorgefertigten Lösungen (Nutzung der Collection-Bibliothek) Einfügereihenfolge relevant? Sortierung der Schlüssel relevant? SortedMap nein ja Ggf. Experimente (experimentelle Prototypen) List Set Abfrage an i-ter Position Anpassung an vorgefertigte Lösung Entwicklung einer neuartigen Lösung 41 Softwaretechnologie * assoc Ersetzen an i-ter Position SortedSet kleinstes/größtes Element Entfernen an i-ter Position Elemente "über"/"unter" x 42 Softwaretechnologie Realisierung von ungeordneten Assoziationen mit Set Beispiel: Realisierung von Assoziationen A Sortierung relevant? B A assoc * B Datenstruktur im A-Objekt für B-Referenzen Anforderung 1) Assoziation anlegen 2) Assoziation entfernen 3) Durchlaufen aller bestehenden Assoziationen zu B-Objekten 4) Manchmal: Abfrage, ob Assoziation zu einem B-Objekt besteht 5) Keine Obergrenze der Multiplizität gegeben class A { private Set assoc; ... Realisierung 1) Einfügen (ohne Reihenfolge) 2) Entfernen (ohne Reihenfolge) 3) Aufzählen aller Elemente public void addAssoc (B b) { assoc.add(b); } 4) "ist enthalten"-Abfrage public boolean testAssoc (B b) { return assoc.contains(b); } 5) Maximalanzahl der Elemente unbekannt; dynamisch erweiterbar public A { ... assoc = new HashSet(); } Set Softwaretechnologie 43 Softwaretechnologie 44 Beispiel: Raumverwaltung Raumverwaltung: Freien Raum suchen static Besprechungsraum freienRaumSuchen (int groesse, Hour beginn, int dauer) class Raumverwaltung { ► Suche unter vorhandenen Räumen nach Raum mit mindestens der Kapazität groesse, aber möglichst klein. ■ Datenstruktur für vorhandene Räume in Klasse Raumverwaltung » SortedSet (Elemente: Besprechungsraum) ► Überprüfung eines Raumes, ob er für die Zeit ab beginn für die Länge dauer bereits belegt ist. ■ Operation in Klasse Besprechungsraum: ■ Datenstruktur in Klasse Besprechungsraum für Zeiten (Stunden): boolean frei (Hour beginn, int dauer) » Set (Elemente: Hour) ► Zusatzanforderung (Variante): Überprüfung, welcher andere Termin eine bestimmte Stunde belegt. ■ } private static SortedSet vorhandeneRaeume = new TreeSet(); // Vorhandene Raeume, aufsteigend nach Groesse sortiert static Besprechungsraum freienRaumSuchen (int groesse, Hour beginn, int dauer) { Besprechungsraum r = null; boolean gefunden = false; Iterator it = vorhandeneRaeume.iterator(); while (! gefunden && it.hasNext()) { r = (Besprechungsraum)it.next(); if (r.grossGenug(groesse)&& r.frei(beginn,dauer)) gefunden = true; }; if (gefunden) return r; else return null; } ... Datenstruktur in Klasse Besprechungsraum: » Map (Schlüssel: Hour, Wert: Teambesprechung) 45 Softwaretechnologie Softwaretechnologie 46 Temporäre und persistente Daten Objektorientierte Implementierung mit Java-Datenstrukturen ► Persistente Datenhaltung Daten sind ■ temporär, wenn sie mit Beendigung des Programms verloren gehen, das sie verwaltet; ■ persistent, wenn sie über die Beendigung des verwaltenden Programms hinaus erhalten bleiben. ► Objektorientierte Programme benötigen Mechanismen zur Realisierung der Persistenz von Objekten. ► Möglichkeiten zur Realisierung von Objekt-Persistenz: ■ Art is long, and Time is fleeting. H. W. Longfellow ■ Einsatz eines Datenbank-Systems . Objektorientiertes Datenbank-System . Relationales Datenbank-System Java: Java Data Base Connectivity (JDBC) . Zugriffsschicht auf Datenhaltung Java: Java Data Objects (JDO) Speicherung von Objektstrukturen in Dateien . Softwaretechnologie, © Prof. Uwe Aßmann, Prof. Heinrich Hussmann 47 Objekt-Serialisierung (Object Serialization) Softwaretechnologie 48 Objekt-Serialisierung in Java ► ► Objekt-Serialisierung: Abspeichern Die Klassen java.io.ObjectOutputStream und java.io.ObjectInputStream stellen Methoden bereit, um ein Geflecht von Objekten linear darzustellen (zu serialisieren) bzw. aus dieser Darstellung zu rekonstruieren. Eine Klasse, die Serialisierung zulassen will, muß die (leere!) Schnittstelle java.io.Serializable implementieren. class ObjectOutputStream { public ObjectOutputStream (OutputStream out) throws IOException; public void writeObject (Object obj) throws IOException; } Softwaretechnologie import java.io.*; class XClass implements Serializable { private int x; public XClass (int x) { this.x = x; } } ... XClass xobj; ... FileOutputStream fs = new FileOutputStream("Xfile.dat"); ObjectOutputStream os = new ObjectOutputStream(fs); os.writeObject(xobj); ... 49 Softwaretechnologie Objekt-Serialisierung: Einlesen The End import java.io.*; ► class XClass implements Serializable { private int x; public XClass (int x) { this.x = x; } } 50 Diese Folien sind eine überarbeitete Version der Vorlesungsfolien zur Vorlesung Softwaretechnologie von © Prof. H. Hussmann, 2002. used by permission. ... XClass xobj; ... FileInputStream fs = new FileInputStream("Xfile.dat"); ObjectInputStream os = new ObjectInputStream(fs); xobj = (XClass) os.readObject(); Softwaretechnologie 51 Softwaretechnologie 52