Wo sind wir? • • • • • • • • • • • • • • • • Java-Umgebung Lexikale Konventionen Datentypen Kontrollstrukturen Ausdrücke Klassen, Pakete, Schnittstellen JVM Exceptions Java Klassenbibliotheken Ein-/Ausgabe Collections Threads Applets, Sicherheit Grafik Beans Integrierte Entwicklungsumgebungen Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 338 Container Container sind Behälter, die andere Dinge speichern können. Schon bekannte Beispiele aus der Einführungsvorlesung sind: • Liste • Stack • Schlange • Baum Typische Operationen auf einem Container sind z.B.: • Füge ein Element zu dem Container hinzu • Lösche ein Objekt aus dem Container • Suche ein bestimmtes Objekt im Container • Enthält der Container Elemente (nicht leer)? • Wende eine Operation auf alle Container-Elemente an Man kann sich Container mit unterschiedlichen Eigenschaften vorstellen: • Ein Element darf höchstens ein mal vorkommen (keine Duplikate) • Die Anzahl der Elemente im Container bleibt überwiegend konstant (→Effizienzfrage) • Spezielle Abspeicherungstechniken zur Optimierung von häufig benutzten Operationen (→ Vorlesung "Algorithmen und Datenstrukturen") Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 339 Collection Framework Java kennt das Collection Framework (im Paket java.util; siehe APIDokumentation), in dem Container mit unterschiedlichen Eigenschaften zur Verfügung gestellt werden. Es werden folgende Arten von Collections unterschieden, die jeweils gewisse Eigenschaften haben und ausnutzen: 1. 2. 3. Listen (List; geordnete Menge, d.h. es gibt ein i-tes Element) Mengen (Set; keine Duplikate) Abbildungen (Map; Schlüssel-Wert-Paare) In den drei Kategorien, die als Schnittstellen in Java definiert sind und die die Schnittstelle Collection erweitern, gibt es Klassen, die diese Schnittstellen in einer bestimmten Weise implementieren. Z.B. lässt sich eine Liste durch eine einfach verkettete Liste implementieren, durch eine doppelt verkettete Liste, durch ein dynamisch wachsendes Feld usw. Zum Collection Framework gehören weiterhin Algorithmen, wie z.B. Sortieren einer Liste, (binäres) Suchen in einer Liste usw. Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 340 Collection-Schnittstelle Jeder Container muss die Schnittstelle Collection implementieren. public interface Collection { // Basic Operations int size(); boolean isEmpty(); boolean contains(Object element); boolean add(Object element); // Optional boolean remove(Object element); // Optional Iterator iterator(); // Bulk Operations boolean containsAll(Collection c); boolean addAll(Collection c); // boolean removeAll(Collection c); // boolean retainAll(Collection c); // void clear(); // Optional Optional Optional Optional // Array Operations Object[] toArray(); Object[] toArray(Object a[]); } Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 341 Beispiel zum Prinzip der dynamischen Erweiterbarkeit class MeinDynamischesFeld { private Object[] daten = new Object[1]; // Datenelemente private int anzahl = 0; // Elementanzahl für aktuelle Belegung public boolean add(Object element) { if(anzahl == daten.length) erweitere(); obj[anzahl++] = element; return true; } public Object get(int index) { if((index < 0) || (index >= anzahl)) return null; return obj[index]; } // // // // genug Platz? nein! Feld vergrößern Datenelement abspeichern Element eingefügt // Zulässiger Index? // Element zurückgeben private void erweitere() { Object[] tmp = new Object[obj.length+1]; // größeres Feld anlegen for(int i=0; i<obj.length; i++) tmp[i] = obj[i]; // Daten kopieren daten = tmp; // neues Feld unter daten abspeichern } } Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 342 Schnittstellen- und Klassenhierarchie der Collections Collection List Object AbstractCollection (abstract) Dictionary (abstract) Map AbstractMap (abstract) Set SortedMap HashTable AbstractList (abstract) SortedSet AbstractSet (abstract) HashMap Vector Abstract SequentialList (abstract) ArrayList TreeSet HashSet WeakHashMap TreeMap Properties Stack LinkedList xyz konkrete Klasse x Rudolf Berrendorf FH Bonn-Rhein-Sieg y xyz x von y abgeleitet abstrakte Klasse x Programmiersprache Java y xyz Schnittstelle x implementiert y 343 Listen Listen sind geordnet. Man kann an einer beliebigen Stelle Objekte einfügen oder löschen. • Vector, Stack und ArrayList werden intern über ein Feld implementiert, das dynamisch neu angelegt wird, wenn zusätzlicher Speicherplatz benötigt wird (siehe Beispiel eben zum Prinzip). • LinkedList wird über eine lineare Liste implementiert (siehe Vorlesung "Einführung in die Programmierung"). • Der Unterschied zwischen Vector und ArrayList ist nur bei mehreren Threads von Interesse. • Stack arbeitet nur nach dem LIFO-Prinzip (d.h. nicht an beliebiger Stelle Modifikation möglich). Operationen: empty, peek, pop, push, search. Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 344 Beispiel 1: Vector import java.util.*; class VectorTest { public static void main(String[] args) { Vector vec = new Vector(); // neuen Vector-Container erzeugen vec.add("Bryan Adams"); vec.add("Bruce Springsteen"); vec.add("Frank Sinatra"); System.out.println(vec); // // // // vec.add(2, "Stefan Raab"); System.out.println(vec); // An Indexposition 2 String einfügen // [BA, BS, SR, FS] vec.remove(3); System.out.println(vec); // Element an Position 3 löschen // [BA, BS, SR] vec.remove("Stefan Raab"); System.out.println(vec); // Element löschen (über equals()) // [BA, BS] Stringobjekt hinzufügen noch einen String hinzufügen ditto [BA, BS, FS] } } Frage: Kann ich in obigem Programm zusätzlich noch vec.add(new Integer(5)) schreiben? Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 345 Beispiel 2: Stack import java.util.*; class Person { // Beispielklasse String name; Person(String n) { name = n; } void print() { System.out.println(name); } } public class StackTest { public static void main(String[] args) { Stack s = new Stack(); // neuen Stack-Container erzeugen s.push(new Person("Bryan Adams")); s.push(new Person("Bruce Springsteen")); s.push(new Person("Frank Sinatra")); // Objekt aus Stack legen // noch ein Objekt hinzufügen // ditto while(!s.empty()) ((Person)s.pop() ).print(); // // // // solange Daten auf Stack Hole Element von Stack und rufe Methode print() auf Downcast nötig! } } Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 346 Beispiel 3: Liste import java.util.*; class Person { // Beispielklasse String name; Person(String n) { name = n; } void print() { System.out.println(name); } public String toString() { return name; } } public class ListTest { public static void main(String[] args) { LinkedList l = new LinkedList(); Person p1, p2, p3; // List-Container erzeugen l.add(p1 = new Person("Bryan Adams")); // l.add(p2 = new Person("Bruce Springsteen"));// l.add(p3 = new Person("Frank Sinatra")); // System.out.println(l); // Objekt an Liste anhängen noch ein Objekt anhängen ditto [ BA, BS, FS ] l.remove(p3); // Franky Boy wieder löschen System.out.println(l.contains(p2)); // Enthält Liste BS? } } Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 347 Iterator Eine oft wiederkehrende Aufgabe bei Collections ist das Besuchen jedes Elementes im Collection, z.B. um eine bestimmte Operation auf jedes Datenelement anzuwenden. Dies lässt sich im Zusammenhang mit einer Collection auf einfache Weise mit einem Iterator machen. Dabei ist jedoch keine bestimmte Reihenfolge des Besuchens garantiert! public interface Iterator { boolean hasNext(); Object next(); void remove(); } // Optional Anwendungsschema: CollectionXYZ c = new CollectionXYZ(); ... Iterator it = c.iterator(); while (it.hasNext()) // solange noch unbesuchte Elemente verarbeite(it.next()); // mache etwas mit einem unbesuchten Element Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 348 Beispiel import java.util.*; class Person { String name; int stundenlohn; Person(String n, int knete) int getStundenlohn() } // Beispielklasse { name = n; stundenlohn = knete; } { return stundenlohn; } public class ListTest { public static void main(String[] args) { LinkedList l = new LinkedList(); l.add(new Person("Bryan Adams", 10)); l.add(new Person("Bruce Springsteen", 20)); l.add(new Person("Frank Sinatra", 100)); // // // // Iterator it = l.iterator(); int kosten = 0; // Iterator anlegen List-Container erzeugen Objekt an Liste anhängen noch ein Objekt anhängen ditto while(it.hasNext()) // noch unbesuchte Elemente? kosten += ((Person)it.next()).getStundenlohn(); // Kosten akkumulieren System.out.println("Kosten für Konzert: " + kosten); } } Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 349 Sets In Sets sind wie in mathematischen Mengen keine doppelten Elemente erlaubt, was über die Methode equals() beim Einfügen eines neuen Elements überprüft wird. Ist das Element schon vorhanden, so liefert die add-Methode false als Ergebnis (sonst true). Es gibt zwei konkrete Klassen zu Set: 1. 2. In HashSet werden die Elemente in einer Hash-Tabelle abgespeichert (→Algorithmen und Datenstrukturen). In TreeSet werden die Elemente sortiert in einem Binärbaum abgespeichert. Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 350 Beispiel import java.util.*; public class SetTest { public static void main(String[] args) { HashSet h = new HashSet(); h.add("Bryan Adams"); h.add("Bruce Springsteen"); // Container erzeugen // Objekt hinzufügen // ditto Iterator it = h.iterator(); while(it.hasNext()) System.out.println(it.next()); // Iterator anlegen // noch unbesuchte Elemente? // Elemente ausgeben TreeSet t = new TreeSet(); t.add("Bryan Adams"); t.add("Bruce Springsteen"); // Container erzeugen // Objekt hinzufügen // ditto it = t.iterator(); while(it.hasNext()) System.out.println(it.next()); // Iterator anlegen // noch unbesuchte Elemente? // Elemente ausgeben } } Ausgabe: BS BA BA BS Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 351 Maps Eine Map kann man sich vorstellen als eine Tabelle mit zwei Spalten: In der ersten Spalte steht jeweils ein eindeutiger Bezeichner (Schlüssel) und in der zweiten Spalte der dazugehörige Wert zu diesem Bezeichner. Über den Namen kann man den Wert erfragen. Beispiele: • Wörterbuch (Name, Bedeutung) • Umgebungsvariable in Betriebssystem-Shells (Name, Wert) • Klausurergebnisse (Matr.Nr., Ergebnis) An konkreten Klassen gibt es: • • • • HashMap, HashTable: Nutzten Hash-Verfahren zur Verwaltung der Name-Wert-Paare WeakHashMap: HashMap mit der Eigenschaft, dass der Garbage Collector Einträge entfernen kann, wenn sie außerhalb der Tabelle nicht genutzt werden TreeMap: Nutzt einen Baum, um die Name-Wert-Paare sortiert abzuspeichern Properties: Einfache Ein-/Ausgabe von Name-Wert-Paaren Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 352 Beispiel import java.util.*; class Student { // Beispielklasse String name; int matrNr; // Schlüssel Student(int nr, String n) {matrNr = nr; name = n; } public String toString() { return name; } } public class HashMapTest { public static void main(String[] args) { HashMap h = new HashMap(); Student p1, p2 , p3; // Schlüssel-Wert-Paare h.put(new Integer(4711) h.put(new Integer(4712) h.put(new Integer(4713) // Container erzeugen einfügen. Der Schlüssel muss , p1=new Student(4711,"Bryan , p2=new Student(4712,"Bruce , p3=new Student(4713,"Frank ein Objekt sein! Adams") ); Springsteen") ); Sinatra") ); // Student nach Matrikelnummer suchen Student p = (Student) h.get(new Integer(4712)); System.out.println(p); } } Rudolf Berrendorf FH Bonn-Rhein-Sieg Programmiersprache Java 353