2 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 1 ► JDK Tutorial für J2SE oder J2EE, Abteilung Collections http://www.oracle.com/technetwork/java/javase/documentation/index.html Obligatorische Literatur ► 1) Verfeinerung von Assoziationen 2) Generische Container 3) Polymorphe Container 4) Weitere Arten von Klassen 5) Ungeordnete Collections 6) Kataloge 7) Optimierte Auswahl von Implementierungen für Datenstrukturen Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik Version 14-0.4, 03.05.14 TU Dresden Fakultät für Informatik Lehrstuhl Softwaretechnologie Institut für Software- und Multimediatechnik Prof. Dr. rer. nat. Uwe Aßmann 21) Verfeinern von UML-Assoziationen mit dem Java-2 Collection Framework 3 4 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden http://download.oracle.com/javase/6/docs/ Tutorials http://download.oracle.com/javase/tutorial/ Generics Tutorial: http://download.oracle.com/javase/tutorial/extra/generics/index.html ■ Im Wesentlichen sind die Dokumentationen aller Versionen von Java 6 an nutzbar: ► ► ► Beispiel “Kataloge mit Maps” Katalog-Mit-Abbildung/Katalog.java Katalog-Mit-Abbildung/Katalog2.java Beispiel “Warengruppen mit Mengen” Warengruppe-Mengen/Warengruppe0.java .. Warengruppe-Mengen/Warengruppe4.java Beispiel "Bestellung mit Listen": Bestellung-Collections/Bestellung0.java .. Bestellung-Collections/Bestellung4.java Über die Homepage der Lehrveranstaltung finden Sie verschiedene JavaDateien dieser Vorlesung. Hinweis: Online-Ressourcen ► ► ► ► Empfohlene Literatur ut 6 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 5 ► ► TestTestTreiber Treiber Test-Umgebung Eingabedaten Programm Programm (SUT) (SUT) Ausgabe-Netz (Ist) NetzNetzKomparator Komparator Ausgabe-Netz (Soll) Solange Solangeein einProgramm Programmkeine keineTests Testshat, hat,ist istes eskeine keineSoftware Software Testen beinhaltet die Ist-Soll-Analyse für Objektnetze Stimmt mein Netz mit meinem Entwurf überein? Objektorientierte Software hat eine testgetriebene Architektur für Objektnetze Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik 21.1 Verfeinern von Assoziationen Ok Error 7 8 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Strange-null-pointer-exception-The-Official-Microsoft-ASP.pdf Bitte mal nach “strange null pointer exception” suchen: https://forums.oracle.com/forums/thread.jspa?threadID=2056540 http://stackoverflow.com/questions/8089798/strange-java-string-array-nullpointer-exception Schon mal 3 Tage nach einem Zeiger-Fehler (pointer error) gesucht? + preis(): int + preis(): int 1 * Artikel – name: String – preis: int für Artikel – name: String – preis: int 1 * + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int für Bestellposition – anzahl: String – preis: int 1 * Bestellposition – anzahl: String – preis: int {ordered} 1 * <<interface>> Array 1 {ordered} Online: Bestellung0.java Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() Modell einer Bestellungsabwicklung, eines einfachen Objektnetzes (Hierarchie): Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() ► Verfeinern von Assoziationen (Netzverfeinerung) ► ► ► ► Warum ist das wichtig? 9 Bestellung0.java public public void void sonderpreis sonderpreis (int pos, int preis) {{ liste[pos].einzelpreis(preis); liste[pos].einzelpreis(preis); }} public public int int auftragssumme() auftragssumme() { int int ss = 0; 0; for(int for(int i=0; i<anzahl; i++) i++) ss += += liste[i].positionspreis(); liste[i].positionspreis(); return return s; }} Online: Bestellung("TUD"); Bestellposition(tisch,1)); Bestellposition(stuhl,4)); Bestellposition(schrank,2)); Bestellung fuer Kunde TUD 0. 1 x Tisch Einzelpreis: 200 Summe: 200 1. 4 x Stuhl Einzelpreis: 100 Summe: 400 2. 2 x Schrank Einzelpreis: 300 Summe: 600 Auftragssumme: 1200 Bestellung b1 = new b1.neuePosition(new b1.neuePosition(new b1.neuePosition(new b1.print(); ...} public static void main (String[] args) { Artikel tisch = new Artikel("Tisch",200); Artikel stuhl = new Artikel("Stuhl",100); Artikel schrank = new Artikel("Schrank",300); Testprogramm für Anwendungsbeispiel (1) }} String String kunde; kunde; Bestellposition[] Bestellposition[] liste; liste; int anzahl = 0; int anzahl = 0; public public Bestellung(String Bestellung(String kunde) kunde) {{ this.kunde = kunde; this.kunde kunde; liste liste == new new Bestellposition[20]; Bestellposition[20]; }} public public void void neuePosition neuePosition (Bestellposition (Bestellposition b) b) {{ liste[anzahl] liste[anzahl] == b; b; anzahl++; // anzahl++; // was was passiert passiert bei bei mehr mehr als als 20 20 Positionen Positionen ?? }} public public void void loeschePosition loeschePosition (int (int pos) pos) {{ // // geht geht mit mit Arrays Arrays nicht nicht einfach zu zu realisieren realisieren ! }} private private private private private private class class Bestellung { Einfache Realisierung mit Arrays – Was ist problematisch? Online: Bestellung0.java 10 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 11 12 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Fest zur Allokationszeit – Automatisches Verschieben bei Löschen und Mitten-Einfügen – Antwort 2: durch Abbildung auf die Schnittstelle Collection ► Viele Algorithmen laufen auf sortierten Universen wesentlich schneller als auf unsortierten (z.B. Anfragen in Datenbanken) Wie bilde ich einseitige Assoziationen aus UML auf Java ab? – Was passiert, wenn keine Ordnung benötigt wird? Kann das Array sortiert werden? http://en.wikipedia.org/wiki/Dynamic_array – Dynamische Arrays sind dynamisch erweiterbar: Fest zur Übersetzungszeit – Java Arrays besitzen eine feste Obergrenze für die Zahl der enthaltenen Elemente ► ► ► ► ► Probleme der Realisierung von Assoziationen mit Arrays Bestellung Bestellungfuer fuerKunde KundeTUD TUD 0.0.11xxTisch Einzelpreis: Tisch Einzelpreis:200 200Summe: Summe:200 200 1.1.44xxStuhl Einzelpreis: 50 Summe: 200 Stuhl Einzelpreis: 50 Summe: 200 2.2.22xxSchrank SchrankEinzelpreis: Einzelpreis:300 300Summe: Summe:600 600 Auftragssumme: 1000 Auftragssumme: 1000 public static void main (String[] args) { ... b1.sonderpreis(1,50); b1.print(); } Testprogramm für Anwendungsbeispiel (2) 13 14 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Verwendung von Vererbung zur Strukturierung Flexibel auch zur eigenen Erweiterung – – Antwort: Einziehen von Behälterklassen (collections) aus dem CollectionFramework Flachklopfen (lowering) von Sprachkonstrukten: Wir klopfen Assoziationen zu Java-Behälterklassen flach. – – Zentrale Frage: Wie bilde ich einseitige Assoziationen aus UML flexibel auf Java ab? Meiste Standard-Datenstrukturen abgedeckt – Probleme werden durch das Java-Collection-Framework gelöst, eine objektorientierte Datenstrukturbibliothek für Java + preis(): int + preis(): int 1 * Artikel – name: String – preis: int für Artikel – name: String – preis: int 1 * + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int für Bestellposition – anzahl: String – preis: int 1 * Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() * Bestellposition – anzahl: String – preis: int {ordered} 1 Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() Ersetzen von “*”-Assoziationen durch Behälterklassen <<interface>> Collection 1 {ordered} Bsp.: Verfeinern von bidir. Assoziationen durch Behälterklassen ► ► Collections 15 16 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Online: Bestellung2LinkedList.java ► ► Hilfsmittel: ● Typisierung weglassen ● Ev. dynamische Typisierung, damit Fehler zur Laufzeit identifiziert werden können ● Mächtige Operationen einer Skriptsprache – Java 1.6 Mehr Entwurfswissen aus dem Entwurf in die Implementierung übertragen Hilfsmittel: ● Statische Typisierung, damit der Übersetzer viele Fehler entdeckt ● Generische Klassen Aus der Definition einer Datenstruktur können Bedingungen für ihre Anwendung abgeleitet werden Generische Collections für typsicheres Aufbauen von Objektnetzen (Java) – – – – Zuverlässigkeit Java groovy Guten, stabilen, wartbaren Code schreiben Zeit – Safe Application Development (SAD) Schneller viel Code schreiben – Rapid Application Development (RAD) Orthogonale Trends in der Softwareentwicklung }} public public Bestellung(String kunde) {{ this.kunde this.kunde == kunde; liste liste == new new LinkedList<Bestellposition>(); // // Erklärung Erklärung später später } public public void void neuePosition (Bestellposition (Bestellposition b) b) { liste.set(anzahl,b); liste.set(anzahl,b); anzahl++; // anzahl++; // was was passiert passiert jetzt jetzt bei bei mehr mehr als als 20 20 Positionen ?? } public public void void loeschePosition loeschePosition (int pos) pos) { liste.remove(pos); liste.remove(pos); } public public void void sonderpreis sonderpreis (int (int pos, pos, int int preis) { liste.get(pos).einzelpreis(preis); liste.get(pos).einzelpreis(preis); } public public int int auftragssumme() {{ int s int s == 0; 0; for(int for(int i=0; i=0; i<anzahl; i++) s += += liste.get(i).positionspreis(); liste.get(i).positionspreis(); return return s; s; } class class Bestellung Bestellung {{ private private String String kunde; private private List<Bestellposition> List<Bestellposition> liste; liste; private int anzahl = 0; private int anzahl = 0; Einfache Realisierung mit Collection-Klasse “List” 18 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 17 Bestellung Lieferschein Formular Rechnung Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik Generische Behälterklassen Collection<Object> Bsp.: Elemente einer Hierarchie 21.2 Die Collection-Bibliothek 19 20 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden List<Lieferschein> List<Rechnung> mit Duplikaten ohne Duplikate geordnet ungeordnet sortiert unsortiert Sortierung mit Schlüssel ohne Schlüssel Schlüssel Facetten sind orthogonale Dimensionen einer Klassifikation oder eines Modells Duplikate – Behälterklassen können anhand von verschiedenen Facetten klassifiziert werden Ordnung ► Facetten von Behälterklassen (Collections) List<Bestellung> List<Formular> Bsp.: Hierarchie von Listen 21 <<interface>> SortedSet Sortierung <<interface>> Set Duplikate <<interface>> SortedMap <<interface>> Map Schlüssel TreeSet HashMap TreeMap <<interface>> SortedMap <<interface>> Map Implementierung (implements) Vererbung (extends) <<interface>> SortedSet <<interface>> Set HashSet Implementierungsklassenschicht LinkedList ArrayList <<interface>> List <<interface>> Collection Schnittstellen und Implementierungen im unsicheren, ungetypten Collection-Framework (vor Java 1.5) /home/ua1/Courses/ST1/Material/jdk-docs/index.html <<interface>> List Ordnung <<interface>> Collection Java Collection Framework: Prinzipielle Struktur Schnittstellenschicht 22 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 23 24 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Programmierfehler! Laufzeitfehler!! for (int i = 0; i < listOfRechnung.size(); i++) { for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.get(i); rechnung = (Rechnung)listOfRechnung.get(i); } } List listOfRechnung = new ArrayList(); List listOfRechnung = new ArrayList(); Rechnung rechnung = new Rechnung(); Rechnung rechnung = new Rechnung(); listOfRechnung.add(rechnung); listOfRechnung.add(rechnung); Bestellung best = new Bestellung(); Bestellung best = new Bestellung(); listOfRechnung.add(best); listOfRechnung.add(best); Bei der Konstruktion von Collections werden oft Fehler programmiert, die bei der Dekonstruktion zu Laufzeitfehlern führen Kann in Java < 1.5 nicht durch den Übersetzer entdeckt werden ArrayList add(Object o) get(pos: int): Object ... Zusicherung: Zusicherung:Alle Allevom vomObjekt Objekterreichbaren erreichbarenObjekte Objekte sind sindaus ausder derKlasse KlasseRechnung. Rechnung. listOfRechung:List * Rechnung * Object for (int i = 0; i < listOfRechnung.size(); i++) { for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.get(i); rechnung = (Rechnung)listOfRechnung.get(i); } } Cast nötig, obwohl alles Rechnungen Diesmal ok Bei der Dekonstruktion von Collections müssen unnötig Typumwandlungen (Casts) spezifiziert werden Typisierte Collections erhöhen die Lesbarkeit, da sie mehr Information geben List listOfRechnung = new ArrayList(); List listOfRechnung = new ArrayList(); Rechnung rechnung = new Rechnung(); Rechnung rechnung = new Rechnung(); listOfRechnung.add(rechnung); listOfRechnung.add(rechnung); Rechnung rechnung2 = new Rechnung(); Rechnung rechnung2 = new Rechnung(); listOfRechnung.add(rechnung2); listOfRechnung.add(rechnung2); ► ► Problem 2 ungetypter Schnittstellen: Unnötige Casts ► ► Problem 1 ungetypter Schnittstellen: Laufzeitfehler 25 26 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden In UML E Collection<E> content E – Sprachregelung: “Collection of E” In Java } E content[]; class Collection<E> { ► ► List – E SortedSet Set Collection E E E E: Element, K: Key, V: Value Blocking Queue Queue E E K,V SortedMap Map K,V Die generische Schnittstellen-Hierarchie der Collections (seit Java 1.5) Collection-Hierarchie mit generischen Schnittstellen Collection ► Eine generische Behälterklasse ist eine Klassenschablone einer Eine generische Behälterklasse ist eine Klassenschablone einer Behälterklasse, die mit einem Typparameter für den Typ der Behälterklasse, die mit einem Typparameter für den Typ der Elemente versehen ist. Elemente versehen ist. Generische Behälterklassen 28 List <Formular> E Queue <Formular> Blocking Queue <Formular> SortedSet <Formular> Set E E SortedMap <Nr,Formular> Map <Nr,Formular> SortedSet <<instantiates>> Set <Formular> Collection <Formular> List Collection E ► E E K,V SortedMap K,V Darf man Rechnungen, Bestellungen und Lieferscheine in diese Collections stecken? Ja. Blocking Queue Queue Map TreeMap<K,V> Instanziierung der generischen Hierarchie TreeSet<E> HashMap<K,V> <<interface>> SortedMap<K,V> <<interface>> Map<K,V> Implementierung (implements) Vererbung (extends) <<interface>> SortedSet<E> <<interface>> Set<E> HashSet<E> Implementierungsklassenschicht LinkedList<E> ArrayList<E> <<interface>> List<E> <<interface>> Collection<E> Schnittstellen und Implementierungen im CollectionFramework bilden generische Behälterklassen Schnittstellenschicht 27 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 29 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 30 Bei der Konstruktion von Collections werden jetzt Äpfel von Birnen unterschieden Casts sind nicht nötig, der Übersetzer kennt den feineren Typ Das ist Safe Application Development (SAD) Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik 21.2.2 Schnittstellen im Detail Kein Cast mehr nötig for (int i = 0; i < listOfRechnung.size(); i++) { for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = listOfRechnung.get(i); rechnung = listOfRechnung.get(i); } } List<Rechnung> listOfRechnung = new ArrayList<Rechnung>(); List<Rechnung> listOfRechnung = new ArrayList<Rechnung>(); Rechnung rechnung = new Rechnung(); Rechnung rechnung = new Rechnung(); listOfRechnung.add(rechnung); listOfRechnung.add(rechnung); Bestellung best = new Bestellung(); Bestellung best = new Bestellung(); Compilerfehler listOfRechnung.add(best); listOfRechnung.add(best); ► ► ► SAD löst Probleme 31 32 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden } // Zustandsveränderer + boolean remove (E o); + void clear(); // Monotone Zustandsveränderer + boolean add (E o); // Repräsentations-Trans// formierer + E[] toArray(); // Query methods + boolean isEmpty(); + boolean contains(E o); + boolean equals(E o); + int hashCode(); + Iterator iterator(); <<interface>> Collection<E> } ... public int indexOf (E o); public E remove (int index); public E set (int index, E element); public E get (int index); public void clear(); public boolean remove (E o); public boolean add (E o); public int size(); public boolean contains (E o); public boolean isEmpty(); public interface List extends Collection { // Zustandsveränderer + E remove (int index,E o); + E set (int index, E o); + int indexOf (E o); // Query methods + E get(int index); <<interface>> List <<interface>> Collection Unterschnittstelle java.util.List (Auszug) … public void clear(); public boolean remove (E o); // Nicht-Monotone Zustandsveränderer public boolean add (E o); // Monotone Zustandserweiterer // Zustandsveränderer public E[] toArray(); // Repräsentations-Transformierer public Iterator iterator(); public int hashCode(); public int size(); public boolean equals(E o); public boolean contains (E o); public boolean isEmpty(); // Anfragen (Queries) public interface Collection<E> { Schnittstelle java.util.Collection (Auszug) 33 35 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Spezifische Schnittstellen sowie konkrete Implementierungen in der Collection-Hierarchie können spezialisiertes Verhalten aufweisen. Bsp.: Was ändert sich bei Set im Vergleich zu List in der Semantik von add()? // Zustandsveränderer + boolean add (E o); <<interface>> Set <<interface>> Collection + preis(): int + preis(): int 1 * Artikel – name: String – preis: int für Artikel – name: String – preis: int 1 * + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int für Bestellposition – anzahl: String – preis: int 1 1 {ordered} * <<interface>> List<Bestellposition> Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() * Bestellposition – anzahl: String – preis: int {ordered} 1 Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() Ersetzen von “*”-Assoziationen durch Behälterklassen Verfeinern von bidir. Assoziationen durch getypte Behälterklassen ► ► Unterschnittstelle java.util.Set (Auszug) 36 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 37 }} Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik Siedersleben/Denert, Siedersleben/Denert, Wie Wiebaut bautman manInformationssysteme, Informationssysteme, Informatik-Spektrum Informatik-Spektrum, ,August August2000 2000 "Der "DerAufrufer Aufruferprogrammiert programmiertgegen gegendie die Schnittstelle, Schnittstelle, er erbefindet befindetsich sichsozusagen sozusagenim imluftleeren luftleerenRaum." Raum." 21.3 Programmieren gegen Schnittstellen von polymorphen Containern public public Bestellung(String kunde) {{ this.kunde this.kunde == kunde; liste liste == new new LinkedList<Bestellposition>(); // // Konkrete Konkrete Implementierungsklasse Implementierungsklasse } public public void void neuePosition (Bestellposition (Bestellposition b) b) { liste.set(anzahl,b); liste.set(anzahl,b); anzahl++; // anzahl++; // was was passiert passiert jetzt jetzt bei bei mehr mehr als als 20 20 Positionen ?? } public public void void loeschePosition loeschePosition (int pos) pos) { liste.remove(pos); liste.remove(pos); } public public void void sonderpreis sonderpreis (int (int pos, pos, int int preis) { liste.get(pos).einzelpreis(preis); liste.get(pos).einzelpreis(preis); } public public int int auftragssumme() {{ int int ss == 0; 0; for(int for(int i=0; i=0; i<anzahl; i++) s += += liste.get(i).positionspreis(); liste.get(i).positionspreis(); return return s; s; Online: } Bestellung2LinkedList.java class class Bestellung Bestellung {{ private private String String kunde; private private List<Bestellposition> List<Bestellposition> liste; liste; private int anzahl = 0; private int anzahl = 0; Wdh. Einfache Realisierung mit Collection-Klasse “List” 39 TreeMap<K,V> ► ► ► ► Algebraische Spezifikationen ● Axiomensysteme Interfaces – – List Beispiel: Abstrakte Klassen – Praxis: – ► ► ► Ausführbare Operationen Instantiierbare Klassen Komplexität – Alternativen Verkettete Liste (LinkedList) Liste durch Feld (ArrayList) – – Beispiel: – Praxis: Datenstrukturen – Theorie: – Verhalten der Operationen – Theorie: – Konkretisierung: Operationen ► Konkreter Datentyp (Implementierung) – Abstraktion: Abstrakter Datentyp (Schnittstelle) Polymorphie – zwischen abstrakten und konkreten Datentypen TreeSet<E> HashMap<K,V> <<interface>> SortedMap<K,V> <<interface>> Map<K,V> Implementierung (implements) Vererbung (extends) <<interface>> SortedSet<E> <<interface>> Set<E> HashSet<E> Implementierungsklassenschicht LinkedList<E> ArrayList<E> <<interface>> List<E> <<interface>> Collection<E> Schnittstellen und Implementierungen im CollectionFramework bilden generische Behälterklassen Schnittstellenschicht 38 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 40 41 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden List<Bestellposition> ist ein Interface, keine Klasse ! public Bestellung(String kunde) { this.kunde = kunde; this.liste = new LinkedList< Bestellposition>(); } ... Bei polymorphen Containern muß der Code bei Wechsel der Datenstruktur nur an einer Stelle im Konstruktor geändert werden! public Bestellung(String kunde) { this.kunde = kunde; this.liste = new ArrayList< Bestellposition>(); } ... ! + LinkedList<E>(); + addFirst(E o) + addLast(E o) class class Bestellung Bestellung {{ private private String String kunde; kunde; private private List<Bestellposition> List<Bestellposition> liste; liste; ... // Konstruktor s. u. ... // Konstruktor s. u. public public void void neuePosition neuePosition (Bestellposition (Bestellposition b) b) {{ liste.add(b); }} liste.add(b); public public void void loeschePosition loeschePosition (int (int pos) pos) {{ liste.remove(pos); }} liste.remove(pos); public public void void sonderpreis sonderpreis (int (int pos, pos, int int preis) preis) {{ liste.get(pos).einzelpreis(preis); }} liste.get(pos).einzelpreis(preis); -- Polymorphe Container <<interface>> List<E> LinkedList<E> Programmieren gegen Schnittstellen + ArrayList<E>(int initialCapacity); + void ensureCapacity (int minCapacity); ArrayList<E> public class ArrayList<E> implements List<E> { public ArrayList<E> (int initialCapacity); public void ensureCapacity (int minCapacity); ... } public class LinkedList<E> implements List<E> { public void addFirst (E o); public void addLast (E o); ... } Beispiel: Implementierungsklassen java.util.ArrayList, LinkedList 42 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 43 Iteration 3850 12200 9110 16250 Einfügen -500 110 550 Entfernen -46850 60 46850 Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik 21.4) Weitere Arten von Klassen und Methoden Lesen 1430 3070 16320 4890 Gemessener relativer Aufwand für Operationen auf Listen: (aus Eckel, Thinking in Java, 2nd ed., 2000) Innere Schleifen bilden die „heißen Punkte“ (hot spots) eines Programms Typ array ArrayList LinkedList Vector ► ► Aus Ausalternativen alternativenImplementierungen Implementierungeneiner einerSchnittstelle Schnittstellewählt wähltman mandiejenige, diejenige,die diefür für das dasBenutzungsprofil Benutzungsprofilder derOperationen Operationendie diegrößte größteEffizienz Effizienzbereitstellt bereitstellt (Geschwindigkeit, (Geschwindigkeit,Speicherverbrauch, Speicherverbrauch,Energieverbrauch) Energieverbrauch) Welche Listen-Implementierung soll man wählen? 44 45 Prof. U. Aßmann, Softwaretechnologie, TU Dresden + LinkedList<E>(); + addFirst(E o) + addLast(E o) Tester Checker Zustandsinvariante Methoden Zustandsmodifikatoren Netzmodifikatoren RepräsentationsWechsler ManagementMethoden Zustandsverändernde Methoden Modifikatoren (Mutatoren) Methode Optimierer Allgemeine Methoden LinkedList<E> <<interface>> List<E> Erweiterung: Taxonomie der Methodenarten + ArrayList<E>(int initialCapacity); // Management-Methode + void ensureCapacity (int minCapacity); ArrayList<E> public class ArrayList<E> implements List<E> { public ArrayList<E> (int initialCapacity); // Management-Methode (Optimierer-Methode) public void ensureCapacity (int minCapacity); ... } public class LinkedList<E> implements List<E> { public void addFirst (E o); public void addLast (E o); ... } Management-Methoden in java.util.ArrayList, LinkedList Anfrage (query) Prof. U. Aßmann, Softwaretechnologie, TU Dresden 46 47 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Generische Klasse Schnittstelle (interface) Abstrakte Klasse Partielle Klasse Klasse Algorithmenklasse (Konkrete) Klasse Begriffshierarchie von Klassen (Erweiterung) file://localhost/Users/ua1/Courses/ST1/Material/jdk-docs/api/java/util/Collections.html public public class class Collections<E> Collections<E> {{ public public static static EE max max (Collection<E> (Collection<E> coll); coll); public static E min (Collection<E> coll); public static E min (Collection<E> coll); public public static static int int binarySearch(List<E> binarySearch(List<E> list, list, EE key); key); public public static static void void reverse reverse (List<E> (List<E> list); list); public static void sort (List<E> list) public static void sort (List<E> list) ... ... }} Algorithmenklassen Algorithmenklassen(Hilfsklassen) (Hilfsklassen)enthalten enthaltenAlgorithmen, Algorithmen, die auf einer Familie von anderen Klassen arbeiten die auf einer Familie von anderen Klassen arbeiten Standardalgorithmen in der Algorithmenklasse java.util.Collections 48 49 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Clonable Serializable – – Resultat ist kleiner/gleich/größer 0: genau dann wenn "this" kleiner/gleich/größer als Objekt o public public interface interface Comparable<E> Comparable<E> {{ public public int int compareTo compareTo (E (E o); o); }} Beispiel: geordnete Standarddatentypen (z.B. String oder List) implementieren die Prädikatschnittstelle Comparable: Iterable – Prädikat-Schnittstellen drücken bestimmte Eigenschaft einer Klasse aus. Sie werden oft mit dem Suffix “able” benannt: Prädikatschnittstellen können für einen Typparameter einfache Prädikate ausdrücken Beispiel: Comparable<E> als Return-typ in der Collections-Klasse sichert zu, dass die Methode compareTo() existiert public static <E extends Comparable<E>> min(Collection<E> ce) { public static <E extends Comparable<E>> min(Collection<E> ce) { Iterator<E> iter = ce.iterator(); Iterator<E> iter = ce.iterator(); E curMin = iter.next; E curMin = iter.next; if (curMin == null) return curMin; if (curMin == null) return curMin; for (E element = curMin; for (E element = curMin; iter.hasNext(), element = iter.next) { iter.hasNext(), element = iter.next) { if (element.compareTo(curMin) < 0) { if (element.compareTo(curMin) < 0) { curMin = element; curMin = element; } } } } return curMin; return curMin; } } class Collections { class Collections { /** minimum function for a Collection. Return value is typed /** minimum function for a Collection. Return value is typed * with a generic type with a type bound */ * with a generic type with a type bound */ ► ► Typschranken generischer Parameter (type bounds), mit Prädikatsschnittstellen ► ► ► Prädikat-Schnittstellen (...able Schnittstellen) 50 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 51 Prädikat-Schnittstelle Schnittstelle (interface) Abstrakte Klasse Algorithmenklasse (Konkrete) Klasse Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik 21.5 Ungeordnete Collections mit Set Generische Klasse Partielle Klasse Klasse Begriffshierarchie von Klassen (Erweiterung) 52 53 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden E E K,V TreeMap<K,V> TreeSet<E> HashMap<K,V> K,V E HashSet<E> E // Zustandsveränderer + boolean add (E o); + boolean remove (E o); + void clear(); // Repräsentations-Trans// formierer + E[] toArray(); // Query methods + boolean isEmpty(); + boolean contains(E o); + boolean equals(E o); + int hashCode(); + Iterator iterator(); <<interface>> Collection<E> K,V <<interface>> SortedMap<K,V> <<interface>> Map<K,V> K,V Implementierung (implements) Vererbung (extends) // Zustandsveränderer + boolean add (E o); // Query methods + E get(int index); <<interface>> Set<E> Ungeordnete Mengen: java.util.Set<E> (Auszug) LinkedList<E> ArrayList<E> E <<interface>> Set<E> <<interface>> List<E> <<interface>> SortedSet<E> E E <<interface>> Collection<E> E Mengen (ohne Mehrfacheintrag) im Collection Framework 54 + preis(): int Artikel – name: String – preis: int * {unordered} + add (a: Artikel) + anzahl(): int 1 Warengruppe – name: String – lagerplatz: String <<interface>> Collection<E> (Anmerkung: Erläuterung von Hashfunktionen folgt etwas später !) // Zustandsveränderer + boolean add (E o); + boolean remove (E o); + void clear(); // Repräsentations-Trans// formierer + E[] toArray(); <<class>> HashSet<E> // Zustandsveränderer + boolean add (E o); // Konstruktor # HashSet<E>(int initialCapacity, float loadFactor); + E get(int index); + int hashCode() // Zustandsveränderer + boolean add (E o); // Query methods + E get(int index); <<interface>> Set<E> Set<E> Eine Assoziation in UML kann als {unordered} gekennzeichnet sein Konkreter Datentyp java.util.HashSet<E> (Auszug) ► Anwendungsbeispiel für Set<E> // Query methods + boolean isEmpty(); + boolean contains(E o); + boolean equals(E o); + int hashCode(); + Iterator iterator(); 55 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 56 57 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Online: Warengruppe0.java ► ► Typischer Fehler: Stringvergleich mit "==" (ist nicht korrekt, geht aber meistens gut!) – bei Bedarf selbst überdefinieren ! ● (Ggf. für kompatible Definition der Operation o.hashCode() aus java.lang.Object sorgen) Standardbedeutung Referenzgleichheit ● für selbstdefinierte Klassen z.B. java.lang.String überdefiniert in vielen Bibliotheksklassen – ● deklariert in java.lang.Object – Alternative: Vergleich mit Gleichheitsfunktion o.equals(): – Der Vergleich mit Operation == prüft auf Referenzgleichheit, d.h. physische Identität der Objekte Duplikatsprüfung für Elemente in Mengen: Wann sind Objekte gleich? (1) } public String toString() { String s = "Warengruppe "+name+"\n"; Iterator it = inhalt.iterator(); while (it.hasNext()) { s += " "+(Artikel)it.next(); }; } public int anzahl() { return inhalt.size(); } public void add (Artikel a) { inhalt.add(a); } public Warengruppe (String name, String lagerplatz) { this.name = name; this.lagerplatz = lagerplatz; this.inhalt = new HashSet<Artikel>(); } private String name; private String lagerplatz; private Set<Artikel> inhalt; class Warengruppe { Anwendungsbeispiel mit HashSet<E> 58 59 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden } Es wurde zweifach dasselbe Tisch-Objekt übergeben ! (Gleiches Verhalten bei Strukturgleichheit, s. Warengruppe1.java) Online: Online: Warengruppe1.java Warengruppe2.java Warengruppe Moebel Schrank(300) Tisch(200) Stuhl(100) Systemausgabe bei Referenzgleichheit: Warengruppe w2 = new Warengruppe("Moebel","L2"); w2.add(tisch); w2.add(stuhl); w2.add(schrank); w2.add(tisch); 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); Wann sind Objekte gleich? (3) Referenzgleichheit Online: Warengruppe0.java Warengruppe Moebel Tisch(200) Tisch(200) Schrank(300) Stuhl(100) Systemausgabe beim Benutzen der Standard-Gleichheit: 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); } Wann sind Objekte gleich? (2) Referenzgleichheit <<interface>> Collection<E> 61 + E first(); + E last() <<interface>> SortedSet<E> ► ► Modifi kation der konkreten Klasse Warengruppe: ► Aber Systemreaktion: Exception in thread "main" java.lang.ClassCastException: Artikel at java.util.TreeMap<K,V>.compare(TreeMap<K,V>.java, Compiled Code) in java.util.TreeSet<E>: public class TreeSet<E> … implements SortedSet<E> … { … class Warengruppe<E> { private Set<E> inhalt; public Warengruppe (…) { … this.inhalt = new TreeSet<E>(); } … } java.util.TreeSet<E> implementiert ein geordnete Menge mit Hilfe eines Baumes und benötigt zum Sortieren dessen die Prädikat-Schnittstelle Comparable<E> ► Sortierung von Mengen mit TreeSet nutzt Vergleichbarkeit von Elementen // Zustandsveränderer + boolean add (E o); + boolean remove (E o); + void clear(); // Repräsentations-Trans// formierer + E[] toArray(); // Zustandsveränderer + boolean add (E o); // Query methods + E get(int index); <<interface>> Set<E> java.util.SortedSet<E> (Auszug) // Query methods + boolean isEmpty(); + boolean contains(E o); + boolean equals(E o); + int hashCode(); + Iterator iterator(); 60 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 62 63 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Modifikation der Klasse „Artikel“: ► ► ► in allen Fällen schneller ! – Enthalten 106,5 177,4 erlaubt Operationen für sortierte Mengen Stärken von TreeSet: – Stärken von HashSet: Einfügen 36,14 150,6 Iteration 39,39 40,04 Gemessener relativer Aufwand für Operationen auf Mengen: (aus Eckel, Thinking in Java, 2nd ed., 2000) Typ HashSet TreeSet ► HashSet oder TreeSet? Online: Warengruppe3.java Warengruppe Moebel Schrank(300) Stuhl(100) Tisch(200) Systemausgabe: class Artikel implements Comparable<Artikel> { ... public int compareTo (Artikel o) { return name.compareTo(o.name); } } Artikel muss von Schnittstelle Comparable<Artikel> erben ► Anwendungsbeispiel mit TreeSet<E> 65 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 64 E LinkedList<E> ArrayList<E> E <<interface>> Set<E> <<interface>> List<E> K,V K,V TreeMap<K,V> TreeSet<E> HashMap<K,V> K,V <<interface>> SortedMap<K,V> <<interface>> Map<K,V> K,V Implementierung (implements) Vererbung (extends) E HashSet<E> E <<interface>> SortedSet<E> E E <<interface>> Collection<E> E Collection Framework (Überblick) (Maps) Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik 21.6 Kataloge mit Map 66 67 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden + preis(): int 1 Artikel – name: String – preis: int * code: String Katalog – name: String + put (code: String, a: Artikel) + get (code: String): Artikel + anzahl(): int HashMap ist eine sehr günstige Umsetzung für qualifizierte Assoziationen: Der Qualifikator bildet den Schlüssel; die Zielobjeke den Wert Hier: ► Schlüssel: code:String ► Wert: a:Artikel ► ► Anwendungsbeispiel: Verfeinerung von qualifizierten Assoziationen in UML // Zustandsveränderer + void clear(); + V put (K key, V value); + boolean remove (V o); <<class>> HashMap<K,V> Map liefert funktionale Abhängigkeit zwischen Schlüssel und Wert – <<interface>> Map<K,V> Ein Schlüssel liefert einen Wert (Funktion). – Eine Map ist ein „assoziativer Speicher“ (associative array), der Objekte als Werte (value) unter Schlüsseln (key) zugreifbar macht // Anfragen (query methods) + int size(); + boolean isEmpty(); + boolean containsKey(K key); + boolean containsValue(V value); + V get (K key); + int hashCode(); + Iterator iterator(); + Set<K> keySet<E>(); + Set<V> values(); ► java.util.Map<K,V> (Auszug) 68 69 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Ordnung auf den Schlüsseln: SortedMap (Implementierung z.B.TreeMap). put(...) überschreibt vorhandenen Eintrag (Ergebnis = vorhandener Eintrag). } 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) 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); Testprogramm für Anwendungsbeispiel: Speicherung der Waren mit Schlüsseln class class Katalog Katalog {{ private private String String name; name; private private Map<String,Artikel> Map<String,Artikel> inhalt; inhalt; // // Polymorphe Polymorphe Map Map public public Katalog Katalog (String (String name) name) {{ this.name = name; this.name = name; this.inhalt this.inhalt == new new HashMap< HashMap<String,Artikel String,Artikel>(); >(); }} public public void void put put (String (String code, code, Artikel Artikel a) a) {{ inhalt.put(code,a); inhalt.put(code,a); }} public public int int anzahl() anzahl() {{ return return inhalt.size(); inhalt.size(); }} public public Artikel Artikel get get (String (String code) code) {{ return return (Artikel)inhalt.get(code); (Artikel)inhalt.get(code); }} ... ... }} Online: Katalog.java Anwendungsbeispiel mit HashMap 70 71 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden ■ ■ ■ key: K key.hashCode() hashcode % capacity entry index value: V value2: V key2: K value1: V capacity key1.hashCode() = key2.hashCode() 0 value?: V Überlaufliste Bei nicht eindeutigen Schlüsseln, oder auch durch die Normierung, werden Einträge doppelt “adressiert” (Kollision) key1: K – Die Hashfunktion ist mehrdeutig (nicht injektiv): Verfahren zur Kollisionsauflösung: Überlauflisten (z.B. mit List) Überlaufbaum (TreeSet) Überlauf in der Hashtabelle ► Kollision beim Einstechen value: V V K hashCode(): int 0 hashtab Mit dem Eintragswert wird in eine Hashtabelle eingestochen Der Hashwert wird auf einen Zahlenbereich modulo der Kapazität der Hashtabelle abgebildet, d.h., der Hashwert wird auf die Hashtabelle “normiert” Das Objekt liefert seinen Hashwert mit der Hash-Funktion hashCode() Typischerweise wird der Schlüssel (key) transformiert: Object ► Effekt von hashtab.put(key:K,value:V) Prinzip der Hashtabelle 72 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 73 E E E TreeSet<E> HashMap<K,V> HashSet<E> K,V Hashtable<K,V> TreeMap<K,V> K,V K,V E E K,V <<interface>> SortedMap<K,V> <<interface>> Map<K,V> K,V Implementierung (implements) Vererbung (extends) Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik 21.7 Optimierte Auswahl von Implementierungen von Datenstrukturen Vector<E> LinkedList<E> ArrayList<E> E <<interface>> Set<E> <<interface>> List<E> <<interface>> SortedSet<E> E E <<interface>> Collection<E> E Weitere Implementierungen in der CollectionHierarchie 74 ► ► Effizienz {unique} {non-unique} {set} {bag} {sequence} {union} {subsets} Eindeutigkeit: Kollektionsart: Zusammenhang: ■ ■ ■ mit Duplikaten ohne Duplikate geordnet ungeordnet sortiert unsortiert Sortierung mit Schlüssel ohne Schlüssel Schlüssel Anpassung an vorgefertigte Lösung Entwicklung Entwicklungeiner einer neuartigen Lösung neuartigen Lösung Effizienz-Verbesserung: Effizienz-Verbesserung:Ggf. Ggf.Experimente Experimentemit mitLaufzeiten, Laufzeiten, Speicherverbrauch, Energieverbrauch Speicherverbrauch, Energieverbrauch Suche nach vorgefertigten Lösungen (Nutzung der Collection-Bibliothek) Abstraktion auf die wesentlichen Eigenschaften Identifikation Identifikationder derfunktionalen funktionalenAnforderungen Anforderungenan andie dieDatenstruktur: Datenstruktur: Facetten der Funktionalität, häufig benutzte Operationen (Benutzungsprofil) Facetten der Funktionalität, häufig benutzte Operationen (Benutzungsprofil) Vorgehensweise beim funktionalen und effizienzbasierten Datenstruktur-Entwurf Duplikate Ordnung Beim Übergang zum Implementierungsmodell müssen diese Bedingungen auf Unterklassen von Collections abgebildet werden {ordered} {unordered} Ordnung: ■ An das Ende einer UML-Assoziation können folgende Bedingungen notiert werden: Facetten und Assoziationsarten Funktion 75 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 76 77 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden nein SortedMap<K,V> Sortierung relevant? Elemente "über"/"unter" x kleinstes/größtes Element SortedSet<E> Set<E> Sortierung der Schlüssel relevant? dynamisch erweiterbar "ist enthalten"-Abfrage für Schlüssel Abfrage eines Werts für einen Schlüssel Entfernen eines Schlüssel/Wert-Paars Einfügen eines Werts für einen Schlüssel Map<K,V> inhalt * {mod} Artikel (Z) 1) Assoziation anlegen 2) Assoziation entfernen 3) Durchlaufen aller bestehenden Assoziationen zu Z-Objekten 4) Manchmal: Abfrage, ob Assoziation zu einem Z-Objekt besteht 5) Keine Obergrenze der Multiplizität gegeben Anforderung Set<E> 5) Maximalanzahl der Elemente unbekannt; dynamisch erweiterbar 4) "ist enthalten"-Abfrage 1) Einfügen (ohne Reihenfolge) 2) Entfernen (ohne Reihenfolge) 3) Aufzählen aller Elemente Realisierung Datenstruktur im A-Objekt für Z-Referenzen Warengruppe (A) Beispiel: Realisierung von unidirektionalen Assoziationen Entfernen an i-ter Position Ersetzen an i-ter Position Abfrage an i-ter Position List<E> ja Einfügereihenfolge relevant? Elemente doppelt? Collection<E> Einfügen eines Elements Entfernen eines Elements Aufzählen aller Elemente "ist enthalten"-Abfrage dynamisch erweiterbar Suche nach vorgefertigten Lösungen (anhand der Facetten der Collection-Klassen) 78 79 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden * {unique} inhalt Artikel (Z) Artikel (Z) } public A { assoc = new TreeSet<Z>(); } public boolean testAssoc (Z ziel) { return assoc.contains(ziel); } class A { private Set<Z> assoc; ... public void addAssoc (Z ziel) { assoc.add(ziel); } Warengruppe (A) * {unique, sorted} inhalt Realisierung von sortierten Assoziationen mit Set<E> } public A { assoc = new HashSet<Z>(); } public boolean testAssoc (Z ziel) { return assoc.contains(ziel); } class A { private Set<Z> assoc; ... public void addAssoc (Z ziel) { assoc.add(ziel); } Warengruppe (A) Realisierung von ungeordneten Assoziationen mit Set<E> ► ► ► 80 81 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden ► ► ► ► ► Testfälle Testfälle Objektimplementierung Objektimplementierung Netzimplementierung Netzimplementierung Testfälle Feinentwurf Feinentwurf Verfeinerung von Assoziationen Grobentwurf Grobentwurf Testfälle Zusicherungen Zusicherungen Methodentest Methodentest Klassentest Klassentest Netztest Netztest Integrationstest Komponententest Systemtest Abnahmetest Weniger Casts, mehr Typsicherheit ■ Die Java Collection Library bietet geordnete, ungeordnete Collections sowie Kataloge Element-Typ verfeinert Object ■ Static vs. dynamic vs. no typing Safe Application Development (SAD) nur mit statischen Typisierung möglich Rapid Application Development (RAD) benötigt dynamische Typisierung Generische Collections besitzen den Element-Typ als Typ-Parameter Was haben wir gelernt Zum Schluss der Akzeptanztest (Abnahmetest) Dann der beta-Test Dann das System Dann das Netz testen Dann die Komponente Dann die einzelne Klasse testen Verträge und Testfälle für das Netz entwerfen Analyse Zuerst Verträge und Testfälle für die Klasse bilden Analyse Netze werden im Grob- und Feinentwurf in UML modelliert In der Phase “Netzimplementierung” in Java umgesetzt Die Tests werden bottom-up erledigt: Ziel: V-Modell mit Standard-Testprozess mit Netz-Entwurf und -Test 82 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 83 ► Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik Appendix A Generische Command Objekte Diese Folien bauen auf der Vorlesung Softwaretechnologie auf von © Prof. H. Hussmann, 2002. Used by permission. The End 84 85 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden .. ist ab Java 1.5 ohne Probleme nebeneinander möglich funktioniert for (int jahr = 0; jahr < archiv.size(); jahr++) { for (int jahr = 0; jahr < archiv.size(); jahr++) { listOfRechnung = archiv.get(jahr); listOfRechnung = archiv.get(jahr); for (int i = 0; i < listOfRechnung.size(); i++) { for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.get(i); rechnung = (Rechnung)listOfRechnung.get(i); } } } } archiv.add(listOfRechnung); archiv.add(listOfRechnung); Rechnung rechnung = new Rechnung(); Rechnung rechnung = new Rechnung(); archiv.get(0).add(rechnung); archiv.get(0).add(rechnung); Bestellung best = new Bestellung(); Bestellung best = new Bestellung(); archiv.get(0).add(best); archiv.get(0).add(best); Übersetzt auch, aber Laufzeitfehler beim Cast... // Das Archiv fasst alle Rechnungen aller bisherigen Jahrgänge zusammen // Das Archiv fasst alle Rechnungen aller bisherigen Jahrgänge zusammen List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>(); List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>(); // listOfRechnung fasst die Rechnungen des aktuellen Jahres zusammen // listOfRechnung fasst die Rechnungen des aktuellen Jahres zusammen List listOfRechnung = new ArrayList(); List listOfRechnung = new ArrayList(); ► Benutzung von getypten und ungetypten Schnittstellen // Das Archiv listOfRechnung fasst die Rechnungen des // Das Archiv listOfRechnung fasst die Rechnungen des // aktuellen Jahres zusammen // aktuellen Jahres zusammen List<Rechnung> listOfRechnung = new ArrayList<Rechnung>(); List<Rechnung> listOfRechnung = new ArrayList<Rechnung>(); List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>; List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>; archiv.add(listOfRechnung); archiv.add(listOfRechnung); Rechnung rechnung = new Rechnung(); Rechnung rechnung = new Rechnung(); funktioniert archiv.get(0).add(rechnung); archiv.get(0).add(rechnung); Bestellung best = new Bestellung(); Bestellung best = new Bestellung(); archiv.get(0).add(best); Übersetzungsarchiv.get(0).add(best); Fehler for (int jahr = 0; jahr < archiv.size(); jahr++) { for (int jahr = 0; jahr < archiv.size(); jahr++) { listOfRechnung = archiv.get(jahr); listOfRechnung = archiv.get(jahr); for (int i = 0; i < listOfRechnung.size(); i++) { for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = listOfRechnung.get(i); rechnung = listOfRechnung.get(i); } } } } Generizität auf Containern funktioniert auch geschachtelt 86 87 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden z.B. sind alle Instanzen mit unboxed objects als boxed objects realisiert – } T attribute<T> Templateparameter können Variablen umbenennen C++ bietet Code-Templates (snippets, fragments) an, mit denen man mehr parameterisieren kann, z.B. Methoden In C++ können Templateparameter Variablen umbenennen: template class C <class T> { Verliert etwas Effizienz, da der Übersetzer alle Typinformation im generierten Code vergisst und nicht ausnutzt – In Java: einmalige Übersetzung des generischen Datentyps ► ► Es gibt eine Standard-Funktion in der Klasse des Funktionalobjektes, das die Berechnung ausführt (Standard-Name, z.B. execute() oder doIt()) // A functional object that is like a constant // A functional object that is like a constant interface NullaryOpCommand { void execute(); interface NullaryOpCommand { void execute(); void undo(); } void undo(); } // A functional object that takes one parameter // A functional object that takes one parameter interface UnaryOpCommand<P> { P execute(P p1); interface UnaryOpCommand<P> { P execute(P p1); void undo(); } void undo(); } // A functional object that operates on two parameters // A functional object that operates on two parameters interface BinOp<P> { P execute(P p1, P p2); interface BinOp<P> { P execute(P p1, P p2); void undo(); } void undo(); } Zur Laufzeit kann man das Funktionalobjekt mit Parametern versehen, herumreichen, und zum Schluss ausführen – Funktionalobjekte können Berechnungen kapseln und später ausführen (laziness) (Entwurfsmuster Command) Ein Funktionalobjekt (Kommandoobjekt) ist ein Objekt, das eine Funktion Ein Funktionalobjekt (Kommandoobjekt) ist ein Objekt, das eine Funktion darstellt (reifiziert). darstellt (reifiziert). Implementierungsmuster Command: Generische Methoden als Funktionale Objekte ► ► ► Unterschiede zu C++ 88 89 // An interface for a collection of binary operation on // An interface for a collection of binary operation on // collections // collections interface Functional<Collection<P>,B extends BinOp<P>> { interface Functional<Collection<P>,B extends BinOp<P>> { P compute(Collection<P> p); P compute(Collection<P> p); } } class Accumulate<C,E> implements Functional<C,BinOp<E>> { class Accumulate<C,E> implements Functional<C,BinOp<E>> { E curSum; E element; BinOp<E> binaryOperation; E curSum; E element; BinOp<E> binaryOperation; public E compute(C coll) { public E compute(C coll) { for (int i = 0; i < coll.size(); i++) { for (int i = 0; i < coll.size(); i++) { element = coll.get(i); element = coll.get(i); curSum = binaryOperation.execute(curSum,element); curSum = binaryOperation.execute(curSum,element); } } return curSum; return curSum; } } } } Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik Appendix B Bestimmung von konkreten Datentypen C,E Accumulate Functional B P Anwendung: Akkumulatoren und andere generische Listenoperationen BinOp ► Generische Methoden als Funktionale Objekte Collection <P> Prof. U. Aßmann, Softwaretechnologie, TU Dresden 90 91 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden raumFestlegen() einladen() absagen() verschieben() * Teambesprechung titel beginn dauer anzahl * * leitet für 1 2..* Teilnahme 0..1 Ort 1 Leiter 10..* ► ► ► » SortedSet<Besprechungsraum> (Elemente: Besprechungsraum) Datenstruktur für vorhandene Räume in Klasse Raumverwaltung Datenstruktur in Klasse Besprechungsraum für Zeiten (Stunden): – – TerminvTreeSet.java » Map<Hour,Teambesprechung> (Schlüssel: Hour, Wert: Teambesprechung) Online: Datenstruktur in Klasse Besprechungsraum: Zusatzanforderung (Variante): Überprüfung, welcher andere Termin eine bestimmte Stunde belegt. » Set<Hour> (Elemente: Hour) Operation in Klasse Besprechungsraum: boolean frei (Hour beginn, int dauer) – Überprüfung eines Raumes, ob er für die Zeit ab beginn für die Länge dauer bereits belegt ist. – Suche unter vorhandenen Räumen nach Raum mit mindestens der Kapazität groesse, aber möglichst klein. static Besprechungsraum freienRaumSuchen (int groesse, Hour beginn, int dauer) 1 Teammitglied name abteilung terminBestätigen() 0..1 1 name Team Beispiel 2: Sortierte Liste von Räumen in der Raumverwaltung * Privater Termin beschreibg beginn dauer ort wegzeit genehmigen() verschieben() Termin reservieren() freigeben() freienRaumSuchen() Besprechungsraum raumNr kapazität Beispiel 2: Analysemodell der Terminverwaltung 92 Prof. U. Aßmann, Softwaretechnologie, TU Dresden } 1 1) Verfeinerung von Assoziationen 2) Generische Container 3) Polymorphe Container 4) Weitere Arten von Klassen 5) Ungeordnete Collections 6) Kataloge 7) Optimierte Auswahl von Implementierungen für Datenstrukturen Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik Version 14-0.4, 03.05.14 TU Dresden Fakultät für Informatik Lehrstuhl Softwaretechnologie Institut für Software- und Multimediatechnik Prof. Dr. rer. nat. Uwe Aßmann 21) Verfeinern von UML-Assoziationen mit dem Java-2 Collection Framework // Suche freien Raum aufsteigend nach Größe 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; } ... class Raumverwaltung { // Vorhandene Raeume, aufsteigend nach Größe sortiert // statisches Klassenattribut und -methode private static SortedSet<E> vorhandeneRaeume = new TreeSet<Besprechungsraum>(); Raumverwaltung: Freien Raum suchen 2 3 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden http://www.oracle.com/technetwork/java/javase/documentation/index.html ► ► ► ► http://download.oracle.com/javase/6/docs/ Tutorials http://download.oracle.com/javase/tutorial/ Generics Tutorial: http://download.oracle.com/javase/tutorial/extra/generics/index.html ■ Im Wesentlichen sind die Dokumentationen aller Versionen von Java 6 an nutzbar: Empfohlene Literatur JDK Tutorial für J2SE oder J2EE, Abteilung Collections ► Obligatorische Literatur 5 4 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Beispiel “Kataloge mit Maps” Katalog-Mit-Abbildung/Katalog.java Katalog-Mit-Abbildung/Katalog2.java Beispiel “Warengruppen mit Mengen” Warengruppe-Mengen/Warengruppe0.java .. Warengruppe-Mengen/Warengruppe4.java Beispiel "Bestellung mit Listen": Bestellung-Collections/Bestellung0.java .. Bestellung-Collections/Bestellung4.java Über die Homepage der Lehrveranstaltung finden Sie verschiedene JavaDateien dieser Vorlesung. Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik 21.1 Verfeinern von Assoziationen ► ► ► ► Hinweis: Online-Ressourcen Input 6 7 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden TestTestTreiber Treiber Test-Umgebung Eingabedaten Programm Programm (SUT) (SUT) ► ► ► ► Ok Error Strange-null-pointer-exception-The-Official-Microsoft-ASP.pdf Bitte mal nach “strange null pointer exception” suchen: https://forums.oracle.com/forums/thread.jspa?threadID=2056540 http://stackoverflow.com/questions/8089798/strange-java-string-array-nullpointer-exception Schon mal 3 Tage nach einem Zeiger-Fehler (pointer error) gesucht? Ausgabe-Netz (Ist) NetzNetzKomparator Komparator Ausgabe-Netz (Soll) Solange Solangeein einProgramm Programmkeine keineTests Testshat, hat,ist istes eskeine keineSoftware Software Testen beinhaltet die Ist-Soll-Analyse für Objektnetze Stimmt mein Netz mit meinem Entwurf überein? Warum ist das wichtig? ► ► Objektorientierte Software hat eine testgetriebene Architektur für Objektnetze 8 * * + preis(): int 1 + preis(): int für Artikel – name: String – preis: int 1 Artikel – name: String – preis: int für + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int 1 Bestellposition – anzahl: String – preis: int 1 * Bestellposition – anzahl: String – preis: int {ordered} * 1 {ordered} <<interface>> Array Online: Bestellung0.java Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() Modell einer Bestellungsabwicklung, eines einfachen Objektnetzes (Hierarchie): Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() ► Verfeinern von Assoziationen (Netzverfeinerung) 9 } Bestellung0.java public void void sonderpreis (int pos, pos, int int preis) { liste[pos].einzelpreis(preis); } public int int auftragssumme() { int s = 0; for(int i=0; i<anzahl; i++) s += += liste[i].positionspreis(); liste[i].positionspreis(); return s; } Online: public public Bestellung(String kunde) {{ this.kunde = kunde; kunde; liste = new Bestellposition[20]; }} public public void void neuePosition neuePosition (Bestellposition (Bestellposition b) { liste[anzahl] liste[anzahl] == b; b; anzahl++; // was passiert passiert bei bei mehr als als 20 20 Positionen ? }} public public void loeschePosition (int pos) pos) {{ // geht mit Arrays nicht einfach einfach zu realisieren ! }} private private String String kunde; kunde; private private Bestellposition[] liste; private private int anzahl = 0; class Bestellung { Einfache Realisierung mit Arrays – Was ist problematisch? •Einfache Antwort 1: durch Abbildung auf Java Arrays •Zentrale Frage: Wie bilde ich einseitige Assoziationen aus UML auf Java ab? Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 11 Bestellung("TUD"); Bestellposition(tisch,1)); Bestellposition(stuhl,4)); Bestellposition(schrank,2)); Bestellung Bestellungfuer fuerKunde KundeTUD TUD 0.0.11xxTisch TischEinzelpreis: Einzelpreis:200 200Summe: Summe:200 200 1.1.44xxStuhl StuhlEinzelpreis: Einzelpreis:50 50Summe: Summe:200 200 2.2.22xxSchrank Einzelpreis: 300 Summe: Schrank Einzelpreis: 300 Summe:600 600 Auftragssumme: Auftragssumme:1000 1000 public static void main (String[] args) { ... b1.sonderpreis(1,50); b1.print(); } Testprogramm für Anwendungsbeispiel (2) Bestellung fuer Kunde TUD 0. 1 x Tisch Einzelpreis: 200 Summe: 200 1. 4 x Stuhl Einzelpreis: 100 Summe: 400 2. 2 x Schrank Einzelpreis: 300 Summe: 600 Auftragssumme: 1200 Bestellung b1 = new b1.neuePosition(new b1.neuePosition(new b1.neuePosition(new b1.print(); ...} public static void main (String[] args) { Artikel tisch = new Artikel("Tisch",200); Artikel stuhl = new Artikel("Stuhl",100); Artikel schrank = new Artikel("Schrank",300); Testprogramm für Anwendungsbeispiel (1) Online: Bestellung0.java 10 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 12 13 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Fest zur Allokationszeit – Automatisches Verschieben bei Löschen und Mitten-Einfügen – ► ► Verwendung von Vererbung zur Strukturierung Flexibel auch zur eigenen Erweiterung – – Antwort: Einziehen von Behälterklassen (collections) aus dem CollectionFramework Flachklopfen (lowering) von Sprachkonstrukten: Wir klopfen Assoziationen zu Java-Behälterklassen flach. – – Zentrale Frage: Wie bilde ich einseitige Assoziationen aus UML flexibel auf Java ab? Meiste Standard-Datenstrukturen abgedeckt – Probleme werden durch das Java-Collection-Framework gelöst, eine objektorientierte Datenstrukturbibliothek für Java Collections Antwort 2: durch Abbildung auf die Schnittstelle Collection ► Viele Algorithmen laufen auf sortierten Universen wesentlich schneller als auf unsortierten (z.B. Anfragen in Datenbanken) Wie bilde ich einseitige Assoziationen aus UML auf Java ab? – Was passiert, wenn keine Ordnung benötigt wird? Kann das Array sortiert werden? http://en.wikipedia.org/wiki/Dynamic_array – Dynamische Arrays sind dynamisch erweiterbar: Fest zur Übersetzungszeit – Java Arrays besitzen eine feste Obergrenze für die Zahl der enthaltenen Elemente ► ► ► ► ► Probleme der Realisierung von Assoziationen mit Arrays 14 15 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden * * 1 {ordered} <<interface>> Collection } Online: Bestellung2LinkedList.java public Bestellung(String kunde) { this.kunde this.kunde = kunde; liste liste == new new LinkedList<Bestellposition>(); LinkedList<Bestellposition>(); // Erklärung Erklärung später später } public void neuePosition (Bestellposition b) b) {{ liste.set(anzahl,b); anzahl++; // anzahl++; // was passiert passiert jetzt bei mehr als als 20 20 Positionen ? } public void loeschePosition (int pos) pos) { liste.remove(pos); } public void sonderpreis (int pos, int int preis) preis) {{ liste.get(pos).einzelpreis(preis); liste.get(pos).einzelpreis(preis); } public int auftragssumme() { int int s = 0; for(int for(int i=0; i=0; i<anzahl; i<anzahl; i++) ss += liste.get(i).positionspreis(); liste.get(i).positionspreis(); return return s; s; } class Bestellung { private String kunde; private List<Bestellposition> liste; private int anzahl = 0; Einfache Realisierung mit Collection-Klasse “List” + preis(): int + preis(): int 1 Artikel – name: String – preis: int für Artikel – name: String – preis: int 1 * + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int für Bestellposition – anzahl: String – preis: int 1 Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() * Bestellposition – anzahl: String – preis: int {ordered} 1 Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() Ersetzen von “*”-Assoziationen durch Behälterklassen Bsp.: Verfeinern von bidir. Assoziationen durch Behälterklassen 16 ► ► Hilfsmittel: ● Typisierung weglassen ● Ev. dynamische Typisierung, damit Fehler zur Laufzeit identifiziert werden können ● Mächtige Operationen einer Skriptsprache – 17 Java 1.6 Mehr Entwurfswissen aus dem Entwurf in die Implementierung übertragen Hilfsmittel: ● Statische Typisierung, damit der Übersetzer viele Fehler entdeckt ● Generische Klassen Aus der Definition einer Datenstruktur können Bedingungen für ihre Anwendung abgeleitet werden Generische Collections für typsicheres Aufbauen von Objektnetzen (Java) – – – – Zuverlässigkeit Java groovy Guten, stabilen, wartbaren Code schreiben Zeit – Safe Application Development (SAD) Schneller viel Code schreiben – Rapid Application Development (RAD) Orthogonale Trends in der Softwareentwicklung Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik Generische Behälterklassen Collection<Object> 21.2 Die Collection-Bibliothek •Gradual Typing für beides – Typen werden Schritt für Schritt annotiert – http://ecee.colorado.edu/~siek/gradual-obj.pdf Prof. U. Aßmann, Softwaretechnologie, TU Dresden 18 19 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Lieferschein List<Bestellung> List<Lieferschein> List<Formular> Bsp.: Hierarchie von Listen Bestellung Formular Bsp.: Elemente einer Hierarchie List<Rechnung> Rechnung 21 20 Prof. U. Aßmann, Softwaretechnologie, TU Dresden mit Duplikaten ohne Duplikate Sortierung sortiert unsortiert <<interface>> SortedSet Sortierung <<interface>> Set Duplikate Schlüssel Schlüssel <<interface>> SortedMap <<interface>> Map mit Schlüssel ohne Schlüssel /home/ua1/Courses/ST1/Material/jdk-docs/index.html <<interface>> List Ordnung <<interface>> Collection Java Collection Framework: Prinzipielle Struktur Duplikate Facetten sind orthogonale Dimensionen einer Klassifikation oder eines Modells geordnet ungeordnet – Behälterklassen können anhand von verschiedenen Facetten klassifiziert werden Ordnung ► Facetten von Behälterklassen (Collections) •Collection (Behälter, Kollektion): – Ansammlung von Datenelementen – Hinzufügen, Entfernen, Suchen, Durchlaufen •Set (Menge): – Reihenfolge des Einfügens, Mehrfachvorkommen spielen keine Rolle – SortedSet (geordnete Menge): Ordnung auf den Elementen + Sortierung •List (Liste): – Mehrfachvorkommen werden separat abgelegt – Reihenfolge des Einfügens bleibt erhalten •Map (Abbildung, mapping, associative array ): – Zuordnung von Schlüsselwerten auf Eintragswerte – Menge von Tupeln: Mehrfachvorkommen bei Schlüsseln verboten, bei Einträgen erlaubt – SortedMap (geordnete Abbildung): Ordnung auf den Schlüsseln + Sortierung danach Prof. U. Aßmann, Softwaretechnologie, TU Dresden TreeMap 23 Programmierfehler! Laufzeitfehler!! for (int i = 0; i < listOfRechnung.size(); i++) { for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.get(i); rechnung = (Rechnung)listOfRechnung.get(i); } } List listOfRechnung = new ArrayList(); List listOfRechnung = new ArrayList(); Rechnung rechnung = new Rechnung(); Rechnung rechnung = new Rechnung(); listOfRechnung.add(rechnung); listOfRechnung.add(rechnung); Bestellung best = new Bestellung(); Bestellung best = new Bestellung(); listOfRechnung.add(best); listOfRechnung.add(best); Bei der Konstruktion von Collections werden oft Fehler programmiert, die bei der Dekonstruktion zu Laufzeitfehlern führen Kann in Java < 1.5 nicht durch den Übersetzer entdeckt werden Klassische Behälterklassen arbeiten auf “Object”, können also nicht näher qualifizieren, was sie beinhalten. Das führt leicht zu Fehlern. Behälterklassen müssen das genau qualifizieren, was sie beinhalten. ► ► Problem 1 ungetypter Schnittstellen: Laufzeitfehler Die Java-Collection-Hierarchie ist in zwei Ebenen eingeteilt: Oben liegen Schnittstellen, unten konkrete Implementierungsklassen. Im Wesentlichen werden drei Kategorien unterschieden: geordnete Listen, ungeordnete Mengen und Kataloge (Maps) TreeSet HashMap <<interface>> SortedMap <<interface>> Map Implementierung (implements) Vererbung (extends) <<interface>> SortedSet <<interface>> Set HashSet Implementierungsklassenschicht LinkedList ArrayList <<interface>> List <<interface>> Collection Schnittstellen und Implementierungen im unsicheren, ungetypten Collection-Framework (vor Java 1.5) Schnittstellenschicht 22 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 24 ArrayList add(Object o) get(pos: int): Object ... Zusicherung: Zusicherung:Alle Allevom vomObjekt Objekterreichbaren erreichbarenObjekte Objekte sind sindaus ausder derKlasse KlasseRechnung. Rechnung. listOfRechung:List * Cast nötig, obwohl alles Rechnungen Rechnung * Object for (int i = 0; i < listOfRechnung.size(); i++) { for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.get(i); rechnung = (Rechnung)listOfRechnung.get(i); } } Diesmal ok Bei der Dekonstruktion von Collections müssen unnötig Typumwandlungen (Casts) spezifiziert werden Typisierte Collections erhöhen die Lesbarkeit, da sie mehr Information geben List listOfRechnung = new ArrayList(); List listOfRechnung = new ArrayList(); Rechnung rechnung = new Rechnung(); Rechnung rechnung = new Rechnung(); listOfRechnung.add(rechnung); listOfRechnung.add(rechnung); Rechnung rechnung2 = new Rechnung(); Rechnung rechnung2 = new Rechnung(); listOfRechnung.add(rechnung2); listOfRechnung.add(rechnung2); ► ► Problem 2 ungetypter Schnittstellen: Unnötige Casts 25 In UML E Collection<E> content E – Sprachregelung: “Collection of E” In Java } E content[]; class Collection<E> { ► Auch Collection-Klassen können mit einem Typparameter versehen werden. Collection ► Eine generische Behälterklasse ist eine Klassenschablone einer Eine generische Behälterklasse ist eine Klassenschablone einer Behälterklasse, die mit einem Typparameter für den Typ der Behälterklasse, die mit einem Typparameter für den Typ der Elemente versehen ist. Elemente versehen ist. Generische Behälterklassen Wenn man aus einer ungetypten Behälterklasse ein Element herausholt, muss es von “Object” auf einen spezielleren Typ gewandelt (gecastet) werden. Das führt zu “Codeverschmutzung”, d.h. unübersichtlichem Code. Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 26 ► List – E SortedSet Set Collection E E E E: Element, K: Key, V: Value Blocking Queue Queue E E K,V K,V SortedMap Map Die generische Schnittstellen-Hierarchie der Collections (seit Java 1.5) Collection-Hierarchie mit generischen Schnittstellen TreeMap<K,V> HashMap<K,V> Diese Ansicht zeigt beide Ebenen, generische Schnittstellen und Implementierungsklassen TreeSet<E> HashSet<E> Implementierungsklassenschicht LinkedList<E> ArrayList<E> <<interface>> SortedMap<K,V> <<interface>> Map<K,V> Implementierung (implements) Vererbung (extends) <<interface>> SortedSet<E> <<interface>> Set<E> <<interface>> Collection<E> <<interface>> List<E> Schnittstellenschicht 27 Schnittstellen und Implementierungen im CollectionFramework bilden generische Behälterklassen Neben den hier betrachteten List, Set, Map gibt es weitere Unterschnittstellen von Collection, z.B. Queue. Eine “Schlange” ist ein zirkuläre Liste von Elementen. Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 28 E Blocking Queue <Formular> SortedSet <Formular> SortedMap <Nr,Formular> Map <Nr,Formular> E E E ► E E K,V K,V SortedMap Map Darf man Rechnungen, Bestellungen und Lieferscheine in diese Collections stecken? Ja. Blocking Queue Queue 29 Bei der Konstruktion von Collections werden jetzt Äpfel von Birnen unterschieden Casts sind nicht nötig, der Übersetzer kennt den feineren Typ Das ist Safe Application Development (SAD) Mit generischen Behälterklassen können jetzt die Elemente unterschieden werden, und es braucht keine “Casts”. Kein Cast mehr nötig for (int i = 0; i < listOfRechnung.size(); i++) { for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = listOfRechnung.get(i); rechnung = listOfRechnung.get(i); } } List<Rechnung> listOfRechnung = new ArrayList<Rechnung>(); List<Rechnung> listOfRechnung = new ArrayList<Rechnung>(); Rechnung rechnung = new Rechnung(); Rechnung rechnung = new Rechnung(); listOfRechnung.add(rechnung); listOfRechnung.add(rechnung); Bestellung best = new Bestellung(); Bestellung best = new Bestellung(); Compilerfehler listOfRechnung.add(best); listOfRechnung.add(best); ► ► ► SAD löst Probleme Man kann die Hierarchie von generischen Behälterklassen insgesamt auf einen konkreten Typ instanziieren. Queue <Formular> Set SortedSet <<instantiates>> Set <Formular> Collection <Formular> List Collection Instanziierung der generischen Hierarchie List <Formular> Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 31 } … public void clear(); public boolean remove (E o); // Nicht-Monotone Zustandsveränderer public boolean add (E o); // Monotone Zustandserweiterer // Zustandsveränderer public E[] toArray(); // Repräsentations-Transformierer public Iterator iterator(); public int hashCode(); public int size(); public boolean equals(E o); public boolean contains (E o); public boolean isEmpty(); // Anfragen (Queries) public interface Collection<E> { // Zustandsveränderer + boolean remove (E o); + void clear(); // Monotone Zustandsveränderer + boolean add (E o); // Repräsentations-Trans// formierer + E[] toArray(); // Query methods + boolean isEmpty(); + boolean contains(E o); + boolean equals(E o); + int hashCode(); + Iterator iterator(); <<interface>> Collection<E> Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik Schnittstelle java.util.Collection (Auszug) 30 21.2.2 Schnittstellen im Detail An Behälterklassen sieht man schön, welche Arten von Methoden es gibt (siehe Kapitel “Klassen”). Man sieht hier: Query-Methoden, Repräsentationswechsler, monotone und nicht-monotone Zustandsveränderer, Prof. U. Aßmann, Softwaretechnologie, TU Dresden 32 } ... public int indexOf (E o); public E remove (int index); public E set (int index, E element); public E get (int index); public void clear(); public boolean remove (E o); public boolean add (E o); public int size(); public boolean contains (E o); public boolean isEmpty(); public interface List extends Collection { // Zustandsveränderer + E remove (int index,E o); + E set (int index, E o); + int indexOf (E o); // Query methods + E get(int index); <<interface>> List <<interface>> Collection Unterschnittstelle java.util.List (Auszug) 33 Spezifische Schnittstellen sowie konkrete Implementierungen in der Collection-Hierarchie können spezialisiertes Verhalten aufweisen. Bsp.: Was ändert sich bei Set im Vergleich zu List in der Semantik von add()? // Zustandsveränderer + boolean add (E o); <<interface>> Set <<interface>> Collection Set besitzt zur Schnittstelle List eine unterschiedliche Semantik von “add()”, denn Mengen dürfen Elemente nur einmal enthalten (Duplikate werden eliminiert). ► ► Unterschnittstelle java.util.Set (Auszug) Listen erlauben es, per Index auf die Elemen te der Collection zuzugreifen. Entsprechend werden alle Kategorien von Methoden mit neuen Methoden erweitert, die Zugriff per Index ermöglichen. Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 35 36 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden * 1 {ordered} * <<interface>> List<Bestellposition> } Bestellung2LinkedList.java public Bestellung(String kunde) { this.kunde this.kunde = kunde; liste liste == new new LinkedList<Bestellposition>(); LinkedList<Bestellposition>(); // // Konkrete Implementierungsklasse Implementierungsklasse } public void neuePosition (Bestellposition b) b) {{ liste.set(anzahl,b); anzahl++; // anzahl++; // was passiert passiert jetzt bei mehr als als 20 20 Positionen ? } public void loeschePosition (int pos) pos) { liste.remove(pos); } public void sonderpreis (int pos, int int preis) preis) {{ liste.get(pos).einzelpreis(preis); liste.get(pos).einzelpreis(preis); } public int auftragssumme() { int int s = 0; for(int for(int i=0; i=0; i<anzahl; i<anzahl; i++) ss += liste.get(i).positionspreis(); liste.get(i).positionspreis(); return return s; s; Online: } class Bestellung { private String kunde; private List<Bestellposition> liste; private int anzahl = 0; Wdh. Einfache Realisierung mit Collection-Klasse “List” + preis(): int + preis(): int 1 Artikel – name: String – preis: int für Artikel – name: String – preis: int 1 * + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int + einzelpreis(): int + einzelpreis(p: int) + positionspreis(): int für Bestellposition – anzahl: String – preis: int 1 Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() * Bestellposition – anzahl: String – preis: int {ordered} 1 Bestellung – kunde: String + neuePosition(b: Bestellposition) + löschePosition(pos int) +sonderpreis(pos: int, preis: int) + auftragssumme(): int + print() Ersetzen von “*”-Assoziationen durch Behälterklassen Verfeinern von bidir. Assoziationen durch getypte Behälterklassen Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik Siedersleben/Denert, Siedersleben/Denert, Wie Wiebaut bautman manInformationssysteme, Informationssysteme, Informatik-Spektrum Informatik-Spektrum, ,August August2000 2000 "Der "DerAufrufer Aufruferprogrammiert programmiertgegen gegendie die Schnittstelle, Schnittstelle, er erbefindet befindetsich sichsozusagen sozusagenim imluftleeren luftleerenRaum." Raum." TreeSet<E> TreeMap<K,V> HashMap<K,V> <<interface>> SortedMap<K,V> <<interface>> Map<K,V> Implementierung (implements) Vererbung (extends) <<interface>> SortedSet<E> <<interface>> Set<E> HashSet<E> Implementierungsklassenschicht LinkedList<E> ArrayList<E> <<interface>> List<E> <<interface>> Collection<E> Schnittstellen und Implementierungen im CollectionFramework bilden generische Behälterklassen 37 21.3 Programmieren gegen Schnittstellen von polymorphen Containern Schnittstellenschicht 38 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 39 40 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Operationen Verhalten der Operationen Algebraische Spezifikationen ● Axiomensysteme Abstrakte Klassen Interfaces – List Beispiel: – – Praxis: – Theorie: – – Abstraktion: ► ► ► ► Instantiierbare Klassen Ausführbare Operationen Komplexität – Alternativen Liste durch Feld (ArrayList) – + ArrayList<E>(int initialCapacity); + void ensureCapacity (int minCapacity); ArrayList<E> LinkedList<E> + LinkedList<E>(); + addFirst(E o) + addLast(E o) public class ArrayList<E> implements List<E> { public ArrayList<E> (int initialCapacity); public void ensureCapacity (int minCapacity); ... } public class LinkedList<E> implements List<E> { public void addFirst (E o); public void addLast (E o); ... } <<interface>> List<E> Verkettete Liste (LinkedList) – Beispiel: – Praxis: Datenstrukturen – Theorie: – – Konkretisierung: Konkreter Datentyp (Implementierung) Beispiel: Implementierungsklassen java.util.ArrayList, LinkedList ► ► ► ► Abstrakter Datentyp (Schnittstelle) Polymorphie – zwischen abstrakten und konkreten Datentypen Polymorphe Containerklassen erlauben das Programmieren gegen Schnittstellen der gemeinsamen Oberklasse. Polymorphe generische Containerklassen sind zusätzlich typsicher, was die Verwendung von Elementen betrifft. Prof. U. Aßmann, Softwaretechnologie, TU Dresden 41 public Bestellung(String kunde) { this.kunde = kunde; this.liste = new LinkedList< Bestellposition> (); } ... Bei polymorphen Containern muß der Code bei Wechsel der Datenstruktur nur an einer Stelle im Konstruktor geändert werden! public Bestellung(String kunde) { this.kunde = kunde; this.liste = new ArrayList< Bestellposition> (); } ... ! List<Bestellposition> ist ein Interface, keine Klasse ! class class Bestellung Bestellung {{ private private String String kunde; kunde; private private List<Bestellposition> List<Bestellposition> liste; liste; ... // Konstruktor ... // Konstruktor s. s. u. u. public void neuePosition (Bestellposition public void neuePosition (Bestellposition b) b) {{ liste.add(b); }} liste.add(b); public public void void loeschePosition loeschePosition (int (int pos) pos) {{ liste.remove(pos); }} liste.remove(pos); public public void void sonderpreis sonderpreis (int (int pos, pos, int int preis) preis) {{ liste.get(pos).einzelpreis(preis); }} liste.get(pos).einzelpreis(preis); -- Polymorphe Container Programmieren gegen Schnittstellen 42 Iteration 3850 12200 9110 16250 Einfügen -500 110 550 Entfernen -46850 60 46850 •Gemessener relativer Aufwand für Operationen auf Listen:(aus Eckel, Thinking in Java, 2nd ed., 2000) – Stärken von ArrayList: wahlfreier Zugriff – Stärken von LinkedList: Iteration, Einfügen und Entfernen irgendwo in der Liste – Vector (deprecated) ist generell die langsamste Lösung – Optimierung von inneren Schleifen durch Auswahl von Implementierungen mit geeignetem Zugriffsprofil •Innere Schleifen bilden die „heißen Punkte“ (hot spots) eines Programms Lesen 1430 3070 16320 4890 Gemessener relativer Aufwand für Operationen auf Listen: (aus Eckel, Thinking in Java, 2nd ed., 2000) Innere Schleifen bilden die „heißen Punkte“ (hot spots) eines Programms Typ array ArrayList LinkedList Vector ► ► Aus Ausalternativen alternativenImplementierungen Implementierungeneiner einerSchnittstelle Schnittstellewählt wähltman mandiejenige, diejenige,die diefür für das dasBenutzungsprofil Benutzungsprofilder derOperationen Operationendie diegrößte größteEffizienz Effizienzbereitstellt bereitstellt (Geschwindigkeit, Speicherverbrauch, Energieverbrauch) (Geschwindigkeit, Speicherverbrauch, Energieverbrauch) Welche Listen-Implementierung soll man wählen? Bei diesem Beispiel von generischen Behälterklassen sieht man •die Typdefinition erlaubt die polymorphe Verwendung •die Allokationen in den Konstruktoren der konkreten Implementierungsklassen geben die spezifische Implementierungsmethode an Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 44 + ArrayList<E>(int initialCapacity); // Management-Methode + void ensureCapacity (int minCapacity); ArrayList<E> LinkedList<E> + LinkedList<E>(); + addFirst(E o) + addLast(E o) public class ArrayList<E> implements List<E> { public ArrayList<E> (int initialCapacity); // Management-Methode (Optimierer-Methode) public void ensureCapacity (int minCapacity); ... } public class LinkedList<E> implements List<E> { public void addFirst (E o); public void addLast (E o); ... } <<interface>> List<E> Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik Management-Methoden in java.util.ArrayList, LinkedList 43 21.4) Weitere Arten von Klassen und Methoden Management-Methoden bilden eine neue Kategorie von Methoden: sie erlauben es, Laufzeitparameter ihrer Datentypen zu verändern und zu optimieren. Prof. U. Aßmann, Softwaretechnologie, TU Dresden 46 Zustandsmodifikatoren RepräsentationsWechsler ManagementMethoden Netzmodifikatoren Modifikatoren (Mutatoren) Zustandsverändernde Methoden Optimierer Allgemeine Methoden einer Familie von anderen Klassen arbeiten – 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 Klassenoperationen! •Algorithmenklassen (Hilfsklassen) enthalten Algorithmen, die auf file://localhost/Users/ua1/Courses/ST1/Material/jdk-docs/api/java/util/Collections.html public public class class Collections<E> Collections<E> {{ public public static static EE max max (Collection<E> (Collection<E> coll); coll); public static public static EE min min (Collection<E> (Collection<E> coll); coll); public static int binarySearch(List<E> public static int binarySearch(List<E> list, list, EE key); key); public static void reverse (List<E> list); public static void reverse (List<E> list); public public static static void void sort sort (List<E> (List<E> list) list) ... ... }} Algorithmenklassen Algorithmenklassen(Hilfsklassen) (Hilfsklassen)enthalten enthaltenAlgorithmen, Algorithmen, die dieauf aufeiner einerFamilie Familievon vonanderen anderenKlassen Klassenarbeiten arbeiten Standardalgorithmen in der Algorithmenklasse java.util.Collections Tester Checker Zustandsinvariante Methoden Methode Erweiterung: Taxonomie der Methodenarten Anfrage (query) Prof. U. Aßmann, Softwaretechnologie, TU Dresden 45 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 47 48 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Schnittstelle (interface) Abstrakte Klasse Algorithmenklasse (Konkrete) Klasse ► ► ► Clonable Serializable – – Resultat ist kleiner/gleich/größer 0: genau dann wenn "this" kleiner/gleich/größer als Objekt o public public interface interface Comparable<E> Comparable<E> {{ public public int int compareTo compareTo (E (E o); o); }} Beispiel: geordnete Standarddatentypen (z.B. String oder List) implementieren die Prädikatschnittstelle Comparable: Iterable – Prädikat-Schnittstellen drücken bestimmte Eigenschaft einer Klasse aus. Sie werden oft mit dem Suffix “able” benannt: Prädikat-Schnittstellen (...able Schnittstellen) Generische Klasse Partielle Klasse Klasse Begriffshierarchie von Klassen (Erweiterung) 49 50 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prädikatschnittstellen können für einen Typparameter einfache Prädikate ausdrücken Beispiel: Comparable<E> als Return-typ in der Collections-Klasse sichert zu, dass die Methode compareTo() existiert Generische Klasse Prädikat-Schnittstelle Schnittstelle (interface) Abstrakte Klasse Partielle Klasse Klasse Algorithmenklasse (Konkrete) Klasse Begriffshierarchie von Klassen (Erweiterung) public static <E extends Comparable<E>> min(Collection<E> ce) { public static <E extends Comparable<E>> min(Collection<E> ce) { Iterator<E> iter = ce.iterator(); Iterator<E> iter = ce.iterator(); E curMin = iter.next; E curMin = iter.next; if (curMin == null) return curMin; if (curMin == null) return curMin; for (E element = curMin; for (E element = curMin; iter.hasNext(), element = iter.next) { iter.hasNext(), element = iter.next) { if (element.compareTo(curMin) < 0) { if (element.compareTo(curMin) < 0) { curMin = element; curMin = element; } } } } return curMin; return curMin; } } class Collections { class Collections { /** minimum function for a Collection. Return value is typed /** minimum function for a Collection. Return value is typed * with a generic type with a type bound */ * with a generic type with a type bound */ ► ► Typschranken generischer Parameter (type bounds), mit Prädikatsschnittstellen 52 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik E E LinkedList<E> ArrayList<E> E K,V K,V TreeMap<K,V> E HashMap<K,V> K,V <<interface>> SortedMap<K,V> <<interface>> Map<K,V> K,V Implementierung (implements) Vererbung (extends) TreeSet<E> HashSet<E> E <<interface>> SortedSet<E> E <<interface>> Set<E> E <<interface>> List<E> <<interface>> Collection<E> E Mengen (ohne Mehrfacheintrag) im Collection Framework 51 21.5 Ungeordnete Collections mit Set 53 54 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden ► // Zustandsveränderer + boolean add (E o); // Query methods + E get(int index); <<interface>> Set<E> + preis(): int Artikel – name: String – preis: int * {unordered} + add (a: Artikel) + anzahl(): int 1 Warengruppe – name: String – lagerplatz: String Set<E> Eine Assoziation in UML kann als {unordered} gekennzeichnet sein Anwendungsbeispiel für Set<E> // Zustandsveränderer + boolean add (E o); + boolean remove (E o); + void clear(); // Repräsentations-Trans// formierer + E[] toArray(); // Query methods + boolean isEmpty(); + boolean contains(E o); + boolean equals(E o); + int hashCode(); + Iterator iterator(); <<interface>> Collection<E> Ungeordnete Mengen: java.util.Set<E> (Auszug) <<interface>> Collection<E> 56 <<class>> HashSet<E> } public String toString() { String s = "Warengruppe "+name+"\n"; Iterator it = inhalt.iterator(); while (it.hasNext()) { s += " "+(Artikel)it.next(); }; } Online: Warengruppe0.java public int anzahl() { return inhalt.size(); } public void add (Artikel a) { inhalt.add(a); } public Warengruppe (String name, String lagerplatz) { this.name = name; this.lagerplatz = lagerplatz; this.inhalt = new HashSet<Artikel>(); } private String name; private String lagerplatz; private Set<Artikel> inhalt; class Warengruppe { Anwendungsbeispiel mit HashSet<E> // Zustandsveränderer + boolean add (E o); // Konstruktor # HashSet<E>(int initialCapacity, float loadFactor); + E get(int index); + int hashCode() // Zustandsveränderer + boolean add (E o); (Anmerkung: Erläuterung von Hashfunktionen folgt etwas später !) // Zustandsveränderer + boolean add (E o); + boolean remove (E o); + void clear(); // Repräsentations-Trans// formierer + E[] toArray(); // Query methods + E get(int index); <<interface>> Set<E> Konkreter Datentyp java.util.HashSet<E> (Auszug) // Query methods + boolean isEmpty(); + boolean contains(E o); + boolean equals(E o); + int hashCode(); + Iterator iterator(); 55 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 57 58 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Typischer Fehler: Stringvergleich mit "==" (ist nicht korrekt, geht aber meistens gut!) z.B. java.lang.String bei Bedarf selbst überdefinieren ! ● (Ggf. für kompatible Definition der Operation o.hashCode() aus java.lang.Object sorgen) Standardbedeutung Referenzgleichheit ● für selbstdefinierte Klassen ● überdefiniert in vielen Bibliotheksklassen – – deklariert in java.lang.Object – Alternative: Vergleich mit Gleichheitsfunktion o.equals(): – Der Vergleich mit Operation == prüft auf Referenzgleichheit, d.h. physische Identität der Objekte Online: Warengruppe0.java Warengruppe Moebel Tisch(200) Tisch(200) Schrank(300) Stuhl(100) Systemausgabe beim Benutzen der Standard-Gleichheit: 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); } Wann sind Objekte gleich? (2) Referenzgleichheit ► ► Duplikatsprüfung für Elemente in Mengen: Wann sind Objekte gleich? (1) 59 <<interface>> Collection<E> // Zustandsveränderer + boolean add (E o); + boolean remove (E o); + void clear(); // Repräsentations-Trans// formierer + E[] toArray(); + E first(); + E last() // Zustandsveränderer + boolean add (E o); // Query methods + E get(int index); <<interface>> Set<E> <<interface>> SortedSet<E> Es wurde zweifach dasselbe Tisch-Objekt übergeben ! (Gleiches Verhalten bei Strukturgleichheit, s. Warengruppe1.java) Online: Online: Warengruppe1.java Warengruppe2.java Warengruppe Moebel Schrank(300) Tisch(200) Stuhl(100) Systemausgabe bei Referenzgleichheit: java.util.SortedSet<E> (Auszug) } Warengruppe w2 = new Warengruppe("Moebel","L2"); w2.add(tisch); w2.add(stuhl); w2.add(schrank); w2.add(tisch); 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); Wann sind Objekte gleich? (3) Referenzgleichheit // Query methods + boolean isEmpty(); + boolean contains(E o); + boolean equals(E o); + int hashCode(); + Iterator iterator(); 60 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 61 62 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Aber Systemreaktion: Exception in thread "main" java.lang.ClassCastException: Artikel at java.util.TreeMap<K,V>.compare(TreeMap<K,V>.java, Compiled Code) in java.util.TreeSet<E>: public class TreeSet<E> … implements SortedSet<E> … { … } Modifikation der Klasse „Artikel“: ► Online: Warengruppe3.java Warengruppe Moebel Schrank(300) Stuhl(100) Tisch(200) Systemausgabe: class Artikel implements Comparable<Artikel> { ... public int compareTo (Artikel o) { return name.compareTo(o.name); } } Artikel muss von Schnittstelle Comparable<Artikel> erben ► Anwendungsbeispiel mit TreeSet<E> ► ► Modifi kation der konkreten Klasse Warengruppe: ► class Warengruppe<E> { private Set<E> inhalt; public Warengruppe (…) { … this.inhalt = new TreeSet<E>(); } … } java.util.TreeSet<E> implementiert ein geordnete Menge mit Hilfe eines Baumes und benötigt zum Sortieren dessen die Prädikat-Schnittstelle Comparable<E> ► Sortierung von Mengen mit TreeSet nutzt Vergleichbarkeit von Elementen 63 Prof. U. Aßmann, Softwaretechnologie, TU Dresden in allen Fällen schneller ! – 106,5 177,4 Enthalten 39,39 40,04 Iteration Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik 21.6 Kataloge mit Map erlaubt Operationen für sortierte Mengen Stärken von TreeSet: – Stärken von HashSet: 36,14 150,6 64 ► ► Einfügen HashSet TreeSet Gemessener relativer Aufwand für Operationen auf Mengen: (aus Eckel, Thinking in Java, 2nd ed., 2000) Typ ► HashSet oder TreeSet? 65 66 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden E E K,V K,V TreeMap<K,V> E TreeSet<E> HashMap<K,V> K,V <<interface>> SortedMap<K,V> <<interface>> Map<K,V> K,V Implementierung (implements) Vererbung (extends) // Zustandsveränderer + void clear(); + V put (K key, V value); + boolean remove (V o); <<class>> HashMap<K,V> Map liefert funktionale Abhängigkeit zwischen Schlüssel und Wert – <<interface>> Map<K,V> Ein Schlüssel liefert einen Wert (Funktion). – Eine Map ist ein „assoziativer Speicher“ (associative array), der Objekte als Werte (value) unter Schlüsseln (key) zugreifbar macht // Anfragen (query methods) + int size(); + boolean isEmpty(); + boolean containsKey(K key); + boolean containsValue(V value); + V get (K key); + int hashCode(); + Iterator iterator(); + Set<K> keySet<E>(); + Set<V> values(); ► E HashSet<E> java.util.Map<K,V> (Auszug) LinkedList<E> ArrayList<E> <<interface>> SortedSet<E> E <<interface>> Set<E> E <<interface>> List<E> <<interface>> Collection<E> E Collection Framework (Überblick) (Maps) 67 68 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden HashMap ist eine sehr günstige Umsetzung für qualifizierte Assoziationen: Der Qualifikator bildet den Schlüssel; die Zielobjeke den Wert Hier: ► Schlüssel: code:String ► Wert: a:Artikel ► ► class class Katalog Katalog {{ private private String String name; name; private private Map<String,Artikel> Map<String,Artikel> inhalt; inhalt; // // Polymorphe Polymorphe Map Map public Katalog (String public Katalog (String name) name) {{ this.name this.name == name; name; this.inhalt this.inhalt == new new HashMap< HashMap<String,Artikel String,Artikel>(); >(); }} public public void void put put (String (String code, code, Artikel Artikel a) a) {{ inhalt.put(code,a); inhalt.put(code,a); }} public public int int anzahl() anzahl() {{ return return inhalt.size(); inhalt.size(); }} public public Artikel Artikel get get (String (String code) code) {{ return return (Artikel)inhalt.get(code); (Artikel)inhalt.get(code); }} ... ... }} Online: Katalog.java Anwendungsbeispiel mit HashMap + preis(): int 1 Artikel – name: String – preis: int * code: String Katalog – name: String + put (code: String, a: Artikel) + get (code: String): Artikel + anzahl(): int Anwendungsbeispiel: Verfeinerung von qualifizierten Assoziationen in UML 69 70 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden ■ ■ ■ value: V V key: K K hashCode(): int key.hashCode() hashcode % capacity entry index 0 value: V hashtab Mit dem Eintragswert wird in eine Hashtabelle eingestochen Der Hashwert wird auf einen Zahlenbereich modulo der Kapazität der Hashtabelle abgebildet, d.h., der Hashwert wird auf die Hashtabelle “normiert” Das Objekt liefert seinen Hashwert mit der Hash-Funktion hashCode() Typischerweise wird der Schlüssel (key) transformiert: Object ► Effekt von hashtab.put(key:K,value:V) Prinzip der Hashtabelle Ordnung auf den Schlüsseln: SortedMap (Implementierung z.B.TreeMap). put(...) überschreibt vorhandenen Eintrag (Ergebnis = vorhandener Eintrag). } 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) 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); Testprogramm für Anwendungsbeispiel: Speicherung der Waren mit Schlüsseln 71 value2: V key2: K value1: V capacity key1.hashCode() = key2.hashCode() 0 value?: V 72 E E E Vector<E> LinkedList<E> ArrayList<E> E K,V Hashtable<K,V> TreeMap<K,V> K,V K,V HashMap<K,V> E TreeSet<E> K,V <<interface>> SortedMap<K,V> <<interface>> Map<K,V> K,V Implementierung (implements) Vererbung (extends) HashSet<E> E <<interface>> SortedSet<E> E <<interface>> Set<E> E <<interface>> List<E> <<interface>> Collection<E> E Weitere Implementierungen in der CollectionHierarchie In Java werden in den HashMap-Implementierungen spezielle Auslastungsfaktoren (load factors) berücksichtigt. Standardmäßig wird eine HashMap ab einer Auslastung von 75% automatisch neu organisiert. Beispiel mit Hashtabelle für Strings und Länge als Hashfunktion. Generell ist es wünschenswert, möglichst wenig Kollisionen zu haben. Dies kann z.B. durch eine geschickt gewählte, weit streuende Hashfunktion und ein günstiges Verhältnis Tabellengröße:Datenmenge erreicht werden. • Verwendung einer „Überlaufliste“ • dito, mit steigender Schrittweite bei Iteration Überlaufliste Bei nicht eindeutigen Schlüsseln, oder auch durch die Normierung, werden Einträge doppelt “adressiert” (Kollision) key1: K – Die Hashfunktion ist mehrdeutig (nicht injektiv): Verfahren zur Kollisionsauflösung: Überlauflisten (z.B. mit List) Überlaufbaum (TreeSet) Überlauf in der Hashtabelle ► Kollision beim Einstechen Möglichkeiten zur Kollisionsauflösung: • Verwendung des nächsten Felds der Tabelle, iterativ Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 74 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik ► ► {ordered} {unordered} {unique} {non-unique} {set} {bag} {sequence} {union} {subsets} Ordnung: Eindeutigkeit: Kollektionsart: Zusammenhang: Duplikate mit Duplikaten ohne Duplikate Ordnung geordnet ungeordnet sortiert unsortiert Sortierung mit Schlüssel ohne Schlüssel Schlüssel Beim Übergang zum Implementierungsmodell müssen diese Bedingungen auf Unterklassen von Collections abgebildet werden ■ ■ ■ ■ An das Ende einer UML-Assoziation können folgende Bedingungen notiert werden: Facetten und Assoziationsarten 73 21.7 Optimierte Auswahl von Implementierungen von Datenstrukturen Funktion 75 76 Anpassung an vorgefertigte Lösung Entwicklung Entwicklungeiner einer neuartigen neuartigenLösung Lösung Effizienz-Verbesserung: Effizienz-Verbesserung:Ggf. Ggf.Experimente Experimentemit mitLaufzeiten, Laufzeiten, Speicherverbrauch, Speicherverbrauch,Energieverbrauch Energieverbrauch Suche nach vorgefertigten Lösungen (Nutzung der Collection-Bibliothek) Abstraktion auf die wesentlichen Eigenschaften Identifikation Identifikationder derfunktionalen funktionalenAnforderungen Anforderungenan andie dieDatenstruktur: Datenstruktur: Facetten Facettender derFunktionalität, Funktionalität,häufig häufigbenutzte benutzteOperationen Operationen(Benutzungsprofil) (Benutzungsprofil) Vorgehensweise beim funktionalen und effizienzbasierten Datenstruktur-Entwurf ja Entfernen an i-ter Position Ersetzen an i-ter Position Abfrage an i-ter Position List<E> nein Einfügereihenfolge relevant? Elemente doppelt? Collection<E> Einfügen eines Elements Entfernen eines Elements Aufzählen aller Elemente "ist enthalten"-Abfrage dynamisch erweiterbar SortedMap<K,V> Sortierung relevant? Elemente "über"/"unter" x kleinstes/größtes Element SortedSet<E> Set<E> Sortierung der Schlüssel relevant? dynamisch erweiterbar "ist enthalten"-Abfrage für Schlüssel Abfrage eines Werts für einen Schlüssel Entfernen eines Schlüssel/Wert-Paars Einfügen eines Werts für einen Schlüssel Map<K,V> Suche nach vorgefertigten Lösungen (anhand der Facetten der Collection-Klassen) Effizienz Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden 77 78 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden inhalt * {mod} Artikel (Z) Realisierung Set<E> 5) Maximalanzahl der Elemente unbekannt; dynamisch erweiterbar 4) "ist enthalten"-Abfrage 1) Einfügen (ohne Reihenfolge) 2) Entfernen (ohne Reihenfolge) 3) Aufzählen aller Elemente * {unique} inhalt Artikel (Z) } public A { assoc = new HashSet<Z>(); } public boolean testAssoc (Z ziel) { return assoc.contains(ziel); } class A { private Set<Z> assoc; ... public void addAssoc (Z ziel) { assoc.add(ziel); } Warengruppe (A) Realisierung von ungeordneten Assoziationen mit Set<E> 1) Assoziation anlegen 2) Assoziation entfernen 3) Durchlaufen aller bestehenden Assoziationen zu Z-Objekten 4) Manchmal: Abfrage, ob Assoziation zu einem Z-Objekt besteht 5) Keine Obergrenze der Multiplizität gegeben Anforderung Datenstruktur im A-Objekt für Z-Referenzen Warengruppe (A) Beispiel: Realisierung von unidirektionalen Assoziationen 79 ► ► ► 80 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden * {unique, sorted} inhalt Artikel (Z) Analyse Dann der beta-Test Zum Schluss der Akzeptanztest (Abnahmetest) Dann das Netz testen Dann die Komponente Dann das System Verträge und Testfälle für das Netz entwerfen Dann die einzelne Klasse testen Testfälle Testfälle Testfälle Objektimplementierung Objektimplementierung Netzimplementierung Netzimplementierung Testfälle Feinentwurf Feinentwurf Verfeinerung von Assoziationen Grobentwurf Grobentwurf Zuerst Verträge und Testfälle für die Klasse bilden Analyse Die Tests werden bottom-up erledigt: Netze werden im Grob- und Feinentwurf in UML modelliert In der Phase “Netzimplementierung” in Java umgesetzt Systemtest Abnahmetest Netztest Netztest Integrationstest Komponententest Zusicherungen Zusicherungen Methodentest Methodentest Klassentest Klassentest Ziel: V-Modell mit Standard-Testprozess mit Netz-Entwurf und -Test } public A { assoc = new TreeSet<Z>(); } public boolean testAssoc (Z ziel) { return assoc.contains(ziel); } class A { private Set<Z> assoc; ... public void addAssoc (Z ziel) { assoc.add(ziel); } Warengruppe (A) Realisierung von sortierten Assoziationen mit Set<E> 81 82 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden Weniger Casts, mehr Typsicherheit ■ Die Java Collection Library bietet geordnete, ungeordnete Collections sowie Kataloge Element-Typ verfeinert Object ■ Static vs. dynamic vs. no typing Safe Application Development (SAD) nur mit statischen Typisierung möglich Rapid Application Development (RAD) benötigt dynamische Typisierung Generische Collections besitzen den Element-Typ als Typ-Parameter ► Diese Folien bauen auf der Vorlesung Softwaretechnologie auf von © Prof. H. Hussmann, 2002. Used by permission. The End ► ► ► ► ► Was haben wir gelernt 84 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik // Das Archiv listOfRechnung fasst die Rechnungen des // Das Archiv listOfRechnung fasst die Rechnungen des // aktuellen Jahres zusammen // aktuellen Jahres zusammen List<Rechnung> listOfRechnung = new ArrayList<Rechnung>(); List<Rechnung> listOfRechnung = new ArrayList<Rechnung>(); List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>; List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>; archiv.add(listOfRechnung); archiv.add(listOfRechnung); Rechnung rechnung = new Rechnung(); Rechnung rechnung = new Rechnung(); funktioniert archiv.get(0).add(rechnung); archiv.get(0).add(rechnung); Bestellung best = new Bestellung(); Bestellung best = new Bestellung(); archiv.get(0).add(best); Übersetzungsarchiv.get(0).add(best); Fehler for (int jahr = 0; jahr < archiv.size(); jahr++) { for (int jahr = 0; jahr < archiv.size(); jahr++) { listOfRechnung = archiv.get(jahr); listOfRechnung = archiv.get(jahr); for (int i = 0; i < listOfRechnung.size(); i++) { for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = listOfRechnung.get(i); rechnung = listOfRechnung.get(i); } } } } Generizität auf Containern funktioniert auch geschachtelt 83 Appendix A Generische Command Objekte 85 86 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden .. ist ab Java 1.5 ohne Probleme nebeneinander möglich funktioniert ► ► ► Übersetzt auch, aber Laufzeitfehler beim Cast... z.B. sind alle Instanzen mit unboxed objects als boxed objects realisiert – } T attribute<T> Templateparameter können Variablen umbenennen C++ bietet Code-Templates (snippets, fragments) an, mit denen man mehr parameterisieren kann, z.B. Methoden In C++ können Templateparameter Variablen umbenennen: template class C <class T> { Verliert etwas Effizienz, da der Übersetzer alle Typinformation im generierten Code vergisst und nicht ausnutzt – In Java: einmalige Übersetzung des generischen Datentyps Unterschiede zu C++ for (int jahr = 0; jahr < archiv.size(); jahr++) { for (int jahr = 0; jahr < archiv.size(); jahr++) { listOfRechnung = archiv.get(jahr); listOfRechnung = archiv.get(jahr); for (int i = 0; i < listOfRechnung.size(); i++) { for (int i = 0; i < listOfRechnung.size(); i++) { rechnung = (Rechnung)listOfRechnung.get(i); rechnung = (Rechnung)listOfRechnung.get(i); } } } } archiv.add(listOfRechnung); archiv.add(listOfRechnung); Rechnung rechnung = new Rechnung(); Rechnung rechnung = new Rechnung(); archiv.get(0).add(rechnung); archiv.get(0).add(rechnung); Bestellung best = new Bestellung(); Bestellung best = new Bestellung(); archiv.get(0).add(best); archiv.get(0).add(best); // Das Archiv fasst alle Rechnungen aller bisherigen Jahrgänge zusammen // Das Archiv fasst alle Rechnungen aller bisherigen Jahrgänge zusammen List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>(); List<List<Rechnung>> archiv = new ArrayList<List<Rechnung>>(); // listOfRechnung fasst die Rechnungen des aktuellen Jahres zusammen // listOfRechnung fasst die Rechnungen des aktuellen Jahres zusammen List listOfRechnung = new ArrayList(); List listOfRechnung = new ArrayList(); ► Benutzung von getypten und ungetypten Schnittstellen 87 88 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Es gibt eine Standard-Funktion in der Klasse des Funktionalobjektes, das die Berechnung ausführt (Standard-Name, z.B. execute() oder doIt()) // A functional object that is like a constant // A functional object that is like a constant interface NullaryOpCommand { void execute(); interface NullaryOpCommand { void execute(); void undo(); } void undo(); } // A functional object that takes one parameter // A functional object that takes one parameter interface UnaryOpCommand<P> { P execute(P p1); interface UnaryOpCommand<P> { P execute(P p1); void undo(); } void undo(); } // A functional object that operates on two parameters // A functional object that operates on two parameters interface BinOp<P> { P execute(P p1, P p2); interface BinOp<P> { P execute(P p1, P p2); void undo(); } void undo(); } Zur Laufzeit kann man das Funktionalobjekt mit Parametern versehen, herumreichen, und zum Schluss ausführen – Funktionalobjekte können Berechnungen kapseln und später ausführen (laziness) (Entwurfsmuster Command) B C,E Accumulate Functional P // An interface for a collection of binary operation on // An interface for a collection of binary operation on // collections // collections interface Functional<Collection<P>,B extends BinOp<P>> { interface Functional<Collection<P>,B extends BinOp<P>> { P compute(Collection<P> p); P compute(Collection<P> p); } } class Accumulate<C,E> implements Functional<C,BinOp<E>> { class Accumulate<C,E> implements Functional<C,BinOp<E>> { E curSum; E element; BinOp<E> binaryOperation; E curSum; E element; BinOp<E> binaryOperation; public E compute(C coll) { public E compute(C coll) { for (int i = 0; i < coll.size(); i++) { for (int i = 0; i < coll.size(); i++) { element = coll.get(i); element = coll.get(i); curSum = binaryOperation.execute(curSum,element); curSum = binaryOperation.execute(curSum,element); } } return curSum; return curSum; } } } } Anwendung: Akkumulatoren und andere generische Listenoperationen BinOp ► Generische Methoden als Funktionale Objekte ► ► Ein Funktionalobjekt (Kommandoobjekt) ist ein Objekt, das eine Funktion Ein Funktionalobjekt (Kommandoobjekt) ist ein Objekt, das eine Funktion darstellt (reifiziert). darstellt (reifiziert). Implementierungsmuster Command: Generische Methoden als Funktionale Objekte Collection <P> Prof. U. Aßmann, Softwaretechnologie, TU Dresden Softwaretechnologie, © Prof. Uwe Aßmann Technische Universität Dresden, Fakultät Informatik 90 * * Privater Termin Privater beschreibg Termin beginn beschreibg dauer beginn dauer ort ort wegzeit wegzeit genehmigen() genehmigen() verschieben() verschieben() Termin Termin * 0..1 Ort Teambesprechung * titel Teambesprechung beginn titel dauer beginn anzahl dauer name 1 Team 0..1 name 0..1 1 Leiter 10..* 1Teammitglied Leiter leitet10..* * leitet 1 Teammitglied anzahl name raumFestlegen() 1 name abteilung raumFestlegen() einladen() abteilung Teilnahme einladen() Teilnahme terminBestätigen() absagen() terminBestätigen() absagen() * 2..* 2..* verschieben() * verschieben() 1 1 für für * 1 Besprechungsraum reservieren() raumNr freigeben() kapazität freienRaumSuchen() reservieren() 0..1 Ort freigeben() Team freienRaumSuchen() raumNr kapazität Beispiel 2: AnalysemodellBesprechungsraum der Terminverwaltung Beispiel 2: Analysemodell der Terminverwaltung 89 Appendix B Bestimmung von konkreten Datentypen Operationen werden in der Vorlesung interaktiv eingetragen. Prof. U. Aßmann, Softwaretechnologie, TU Dresden 90 Prof. U. Aßmann, Softwaretechnologie, TU Dresden 91 92 Prof. U. Aßmann, Softwaretechnologie, TU Dresden Prof. U. Aßmann, Softwaretechnologie, TU Dresden » SortedSet<Besprechungsraum> (Elemente: Besprechungsraum) Datenstruktur für vorhandene Räume in Klasse Raumverwaltung Datenstruktur in Klasse Besprechungsraum für Zeiten (Stunden): – – TerminvTreeSet.java » Map<Hour,Teambesprechung> (Schlüssel: Hour, Wert: Teambesprechung) Online: Datenstruktur in Klasse Besprechungsraum: Zusatzanforderung (Variante): Überprüfung, welcher andere Termin eine bestimmte Stunde belegt. » Set<Hour> (Elemente: Hour) Operation in Klasse Besprechungsraum: boolean frei (Hour beginn, int dauer ) – Überprüfung eines Raumes, ob er für die Zeit ab beginn für die Länge dauer bereits belegt ist. – Suche unter vorhandenen Räumen nach Raum mit mindestens der Kapazität groesse, aber möglichst klein. } // Suche freien Raum aufsteigend nach Größe 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; } ... class Raumverwaltung { // Vorhandene Raeume, aufsteigend nach Größe sortiert // statisches Klassenattribut und -methode private static SortedSet<E> vorhandeneRaeume = new TreeSet<Besprechungsraum>(); Raumverwaltung: Freien Raum suchen ► ► ► static Besprechungsraum freienRaumSuchen (int groesse, Hour beginn, int dauer) Beispiel 2: Sortierte Liste von Räumen in der Raumverwaltung