7. Kapitel COLLECTIONS Techniken der Programmentwicklung Prof. Dr. Wolfgang Schramm Übersicht 1 1. Programmstrukturierung mit Paketen (packages) 2. Vererbung 3. Abstrakte Klassen und Interfaces 4. Ausnahmebehandlungg 5. Datenströme: die Java IO‐Bibliothek 6. Multithreading 7. Collections 8 Innere Klassen 8. Innere Klassen 9. Generics 10 Reflection 10. Lernziele des Kapitels 2 Kennenlernen des Java Collection API. Die wichtigsten Collections und ihre Eigenschaften näher kennenlernen. Collections einsetzen können. Iteratoren kennen‐ und einsetzen lernen. i l Inhalt 3 Einführung, Motivation Collection Definition Eigenschaften Die Collection‐Historie Die „ganz alten“ Collections (seit Java 1) Vector HashTable Das Collection Framework (ab Java 5) Eigenschaften Entwurfsprinzipien Aufbau Auswahl einiger wichtiger Collections Map Set List Iteratoren Collection ‐ Begriff 4 Collections/ Container = Datenstrukturen, die dazu dienen, Mengen von Daten aufzunehmen und zu verarbeiten. Die Daten werden gekapselt abgelegt, und der Zugriff ist nur mit Hilfe vorgegebener Methoden möglich. Haben wir als ADTs schon in ADS kennengelernt. Typische Collections: Stacks, Queues, Hashtabellen, Listen und Trees. Äquivalenz Collections für Datenstrukturen = Schleifenkonstrukte für Anweisungen. Schleifen: die Wiederholbarkeit und Wiederverwendbarkeit von Code Collections: Zusammenfassung und repetitive Bearbeitung von einzelnen Datenelementen. Verwendung von Collections: oft im Zusammenhang mit Schleifen, z.B. wenn das Programm von seiner Struktur her nicht Einzel‐, sondern Mengendaten verarbeitet. Hauptrolle von Collections: Elementardaten zu speichern und einen der Bearbeitung angemessenen Zugriff darauf zu ermöglichen. Collections können ganz neue Sichten auf die Daten definieren. Eine Hashtable beispielsweise stellt Daten paarweise zusammen und ermöglicht so die Definition einer beispielsweise stellt Daten paarweise zusammen und ermöglicht so die Definition einer Referenzbeziehung, die ohne ihre Hilfe nur schwer herzustellen wäre. Collections in einfachen Programmiersprachen: meist nur in Form von Arrays. In Java und anderen objektorientierten Sprachen: ganze Reihe unterschiedlicher Collections In Java und anderen objektorientierten Sprachen: ganze Reihe unterschiedlicher Collections (als ADTs) mit einem viel breiter gefächerten Aufgabenspektrum. Motivation: mehr Flexibilität durch geschickte Organisation der ADTs Organisation der ADTs 5 Ziel: Die gespeicherten Daten sollen unabhängig von der Implementierung (der konkreten Datenstruktur) immer mit derselben Technik abgefragt werden können Datenstruktur) immer mit derselben Technik abgefragt werden können. Um welche Datenstrukturen handelt es sich meistens: Arrays, Bäume etc. Welche Operationen werden gebraucht? Suche: Frage nach der Zugehörigkeit eines Werts zum Datenbestand, also: »Gehört das Wort dazu?«. (Wortproblem) Aufzählung der Daten in irgendeiner Weise. Wie können die Operationen realisiert werden? Arrays: Zugriff auf die Elemente über den Index. Aber: nicht immer ein Array der Datenspeicher und die objektorientierte Programmierung verbietet, Aber: nicht immer ein Array der Datenspeicher und die objektorientierte Programmierung verbietet, hinter die Kulisse zu sehen allgemeinerer Weg des Zugriffs über sog. Iteratoren. Dafür gibt es 2 unterschiedliche Interfaces: Enumeration. Enumeration Iterator. Operationen auf Collections 6 Basisoperationen zum Erfragen der Elementanzahl und zum Hinzufügen, Löschen, Selektieren und Finden von Elementen. f h l k l Mengenoperationen, um etwa andere Collections einzufügen. i fü Feldoperationen bei Collection, um die Sammlung in ein Array zu konvertieren und bei Map Operationen, um Array zu konvertieren, und bei Map Operationen um alternative Sichten auf Schlüssel oder Werte zu bekommen. Die Klasse Vector 7 Die Klasse Vector implementiert ein dynamisches Array, das Objekte speichern kann. b k h k Die Größe des Vektors wird automatisch an die benötigte G öß Größe angepasst, d.h. die Größe ist zur Laufzeit veränderbar. t d h di G öß i t L f it ä d b Elemente können an beliebiger Stelle eingefügt werden. Der Zugriff auf die Elemente: sowohl sequentiell als auch wahlfrei Der Zugriff auf die Elemente: sowohl sequentiell als auch wahlfrei. Die Zugriffe auf vorhandene Elemente und das Durchlaufen des Vector sind schnelle Operationen. Einfügungen und Löschungen , welche die interne Kapazität des Arrays über‐ bzw. unterschreiten, sind relativ langsam, weil Teile des Arrays p umkopiert werden müssen. Die Zugriffsoperationen sind sicher. Methoden der Klasse Vector (Auswahl) 8 public Vector() // voreingestellte Kapazität von 10 Elementen public Vector(int initialCapacity) public Vector(int initialCapacity, int capacityIncrement) public Vector(Collection c) j java.util.Vector til V t public final boolean isEmpty() public final int size() public void addElement(Object obj) public void insertElementAt(Obj obj, int index) throws ArrayIndexOutOfBoundsException public Object firstElement() throws NoSuchElementException public Object lastElement() throws NoSuchElementException public Object elementAt(int index) throws public Enumeration elements() ArrayIndexOutOfBoundsException Iterieren über Vector 9 public boolean hasMoreElements() public Object p j nextElement() throws () NoSuchElementException p public Enumeration elements() // aus java.util.Vector p () // j java.util.Enumeration Achtung: Uralttechnik! public class MyVector { public static void main(String[] args) { Vector v = new Vector(); Besser: Iterator verwenden. v.addElement("eins"); v addElement("drei"); v.addElement( drei ); v.insertElementAt("zwei",1); for (Enumeration el = v.elements(); el.hasMoreElements(); ) System.out.println((String)el.nextElement()); } } Methoden der Klasse Stack 10 class Stack extends Vector public public public public p public Object push(Object item) Object pop() Object peek() boolean empty() p y() int search(Object o) java.util.Stack Die Klasse Hashtable – Konkretisierung der Klasse Dictionary 11 Konkretisierung der abstrakten Klasse Dictionary. Dictionary speichert immer zusammengehörige Paare von Schlüsseln und Daten speichert immer zusammengehörige Paare von Schlüsseln und Daten (assoziativer Speicher). Der Schlüssel wird als Name des zugehörigen Wertes angesehen. Üb d S hlü l k Über den Schlüssel kann später der Wert wieder gefunden werden. ä d W i d f d d Über den Schlüsselbegriff wird ein effizienter Zugriff auf den Wert ermöglicht. Ein Dictionary kann auf unterschiedliche Weise implementiert werden. Die Implementierung Hashtable benutzt das Verfahren der Schlüsseltransformation, also die Verwendung einer Transformationsfunktion (Hash‐Funktion), zur Abbildung von Schlüsseln auf Indexpositionen eines Arrays. Weitere Konkretisierungen der Klasse Dictionary, etwa auf der Basis binärer Bäume, gibt es in Java derzeit nicht. Methoden der Klasse Hashtable (Auswahl) 12 public Hashtable() java.util.Hashtable public Hashtable (int initialCapacity) public void clear() public boolean contains (Object value) public boolean containsKey (Object key) public boolean containsValue (Object value) public Enumeration elements () public Object get (Object key) public Object put (Object key, Object value) Iterieren über Hashtable 13 public class MyHash { p public static void main(String[] args) { Hashtable h = new Hashtable(); //Pflege der Aliase h.put("Fritz","[email protected]"); h.put("Alex","[email protected]"); al@bla lrbla.com h put("Sven" h.put( Sven ,"s s.klaus@hs klaus@hs-mannheim mannheim.de de"); ); Alex --> [email protected] h.put("Claudia","[email protected]"); Claudia --> [email protected] Sven --> [email protected] //Ausgabe Fritz i --> [email protected] f ll @ i d Enumeration e = h.keys(); while (e.hasMoreElements()) { String alias = (String)e.nextElement(); System.out.println(alias + " --> " + h.get(alias)); } } } Entwurfsziele für das Collection API (von Java 5) 15 Das API soll vernüftig klein sein – bezüglich seines Umfangs und seines Konzepts aber mächtig. und seines Konzepts – aber mächtig Die neue Funktionalität soll die alte erweitern, nicht ersetzen, d.h. für den Programmierer soll sich nicht viel ändern. d.h. für den Programmierer soll sich nicht viel ändern. Wenige Kern‐Interfaces, die (noch) keine Feinheiten z.B. (variable Größe, Änderbarkeit) festlegen. Um die Anzahl der Methoden in den Kern‐Interfaces gering zu halten, enthält ein Interface eine Methode nur, wenn Die Operation eine elementare ist, d.h. Elementaroperationen mittels l dh l l derer andere vernünftig beschrieben werden können. Nur aus zwingenden Performancegründen sollten diese Operationen von einer Implementierung überschrieben werden. Alle wichtigen Repräsentationen von Collections sollen interoperabel sein interoperabel sein. Entwurfsprinzipien des Collection Framworks 16 Schnittstellen legen Gruppen von Operationen für die verschiedenen Behältertypen fest Behältertypen fest. Abstrakte Basisklassen führen die Operationen der Schnittstellen auf eine Abstrakte Basisklassen führen die Operationen der Schnittstellen auf eine minimale Zahl von als abstrakt deklarierten Grundoperationen zurück. Beispiele: etwa addAll() auf add() oder isEmpty() auf getSize(). Konkrete Klassen für bestimmte Behältertypen beerben die entsprechende abstrakte Basisklasse und ergänzen die unbedingt erforderlichen Grundoperationen (und einige die Performance steigernde Abkü Abkürzungen gegenüber der allgemeinen Lösung in der Oberklasse). Sie üb d ll i Lö i d Ob kl ) Si sind in der Nutzung unsere direkten Ansprechpartner. Beispiele: List Schnittstelle für Sequenzen (Listen), Map Schnittstelle für Assoziativspeicher, die Schlüssel‐Werte‐Paare verbinden. Beispiele: Für eine Liste entweder die Klasse ArrayList oder die Klasse Vector und als Assoziativspeicher die Klasse TreeMap. l A i ti i h di Kl T M Algorithmen, wie die Suche nach einem Element, gehören zum Teil zur Schnittstelle der Datenstrukturen. Zusätzlich gibt es mit der Klasse C ll i Collections eine Utility‐Klasse mit weiteren Algorithmen. i U ili Kl i i Al i h Collection‐Framework (seit Java 5) 17 Sammlung von mehr als 40 Klassen und 14 Interfaces im Paket java.util, die das Collections‐Framework des JDK bilden. Im wesentlichen die fünf Collection‐Grundformen: Collection Sammlung von Objekten ohne besondere Ordnung, Duplikate sind zulässig Duplikate sind zulässig. List ist eine beliebig große Liste von Elementen beliebigen Typs, auf die sowohl wahlfrei als auch sequentiell zugegriffen werden kann. Set ist eine (doublettenlose) ungeordnete Menge von Elementen, auf die mit typischen Mengenoperationen zugegriffen werden kann. Queue Warteschlange mit speziellen Methoden, die auch mit leeren Q g p , oder überfüllten Warteschlangen ohne Ausnahmen umgehen können. Map ist eine Abbildung von Elementen eines Typs auf Elemente eines anderen Typs, also eine Menge zusammengehöriger Paare von anderen Typs, also eine Menge zusammengehöriger Paare von Objekten. Es werden verschiedene Implementierungsvarianten bereitgestellt – in Form von Interfaces und einiger abstrakter Basisklassen – mit denen die Implementierung Interfaces und einiger abstrakter Basisklassen mit denen die Implementierung eigener Collections vereinfacht werden kann. Collection‐Framework 18 Es gibt jeweils eine oder mehrere konkrete Implementierungen zu d 5 (4) ( l I t f den 5 (4) (als Interface festgelegten) Grundformen. f t l t ) G df Sie unterscheiden sich in den verwendeten Datenstrukturen und Algorithmen und damit in ihrer Eignung für verschiedene Algorithmen und damit in ihrer Eignung für verschiedene Verwendungsarten. Es gibt eine abstrakte, sog. Rumpfimplementierung des Interfaces, g g p p g mit dessen Hilfe das Erstellen eigener Collections erleichtert wird. Schema der Namensgebung der Interfaces und Klassen: Das Interface hat immer den allgemein verwendeten Namen der zu implementierenden Collection (List, Set, Queue, Map). Jede Implementierungsvariante stellt vor den Namen dann eine Jede Implementierungsvariante stellt vor den Namen dann eine spezifische Bezeichnung. Sie gibt einen Hinweis auf die Art der verwendeten Datenstrukturen und Algorithmen. Beispiel: Für das Interface List gibt es die Implementierungsvarianten B i i l Fü d I t f Li t ibt di I l ti i t LinkedList und ArrayList sowie die abstrakte Implementierung AbstractList. Die wichtigsten Interfaces des Collection Framework 19 Iterable Collection Set SortedSet NavigableSet g Iterator List Queue Deque BlockingQueue BlockingDeque Collections des Typ Map 20 I I = Interface K = Klassen Iterator Collection Map I SortedMap Ab t tM AbstractMap K K K HashMap LinkedHash Map IdentityHash Map PrinterState Reasons WeakHash Map TreeMap HashMap ‐ Beispiel 21 import java.util.*; public class MyHashMap { public static void main(String[] args) { HashMap h = new HashMap(); //Pflege der Aliase h.put("Fritz","[email protected]"); h.put("Alex","[email protected]"); h put("Sven" h.put( Sven ,"s [email protected] klaus@hs-mannheim de"); ); h.put("Claudia","[email protected]"); //Ausgabe for (Object o: h.entrySet()) h entrySet()) { //System.out.println (o); Map.Entry entry = (Map.Entry)o; System.out.println( (St i ) t (String)entry.getKey() tK () + " --> " + (String)entry.getValue()); } } } Quelle: [Krüger] Sven --> s [email protected] klaus@hs-mannheim de Alex --> [email protected] Fritz --> [email protected] Claudia --> [email protected] Basisinterface Collection 22 Um nicht für jede denkbare Collection‐Klasse ein eigenes Interface definieren zu müssen wurde ein Basisinterface Collection geschaffen aus dem die meisten müssen, wurde ein Basisinterface Collection geschaffen, aus dem die meisten Interfaces abgeleitet wurden. Es fasst die wesentlichen Eigenschaften einer großen Menge unterschiedlicher Collections zusammen: int size() java.util.Collection boolean isEmpty() boolean contains(Object o) Iterator iterator() Object[] toArray() Object[] toArray(Object[] a) boolean add(Object o) boolean remove(Object o) boolean containsAll(Collection c) boolean addAll(Collection ( c) ) boolean removeAll(Collection c) boolean retainAll(Collection c) void clear() boolean equals(Object o) int hashCode() Ändert sich die Zusammensetzung der Collection true Interface Collection 23 Collection +size (): int + isEmpty (): boolean + contains (o: Object): boolean + iterator (): Iterator + toArray (): Object[] + toArray (a: Object[]): Object[] + add (o: Object): boolean + remove (o: Object): boolean + containsAll (c: Collection): boolean + addAll (c: Collection): boolean + removeAll (c: Collection): boolean + retainAll (c: Collection): boolean + clear (): void + equals (o: Object): boolean + hashCode (): int Interface Collection 24 Bis auf die Assoziativspeicher implementieren die Datenstrukturen die Schnittstelle Collection und erhalten damit einen gemeinsamen äußeren Schnittstelle Collection und erhalten damit einen gemeinsamen, äußeren Rahmen. Basis‐Operationen für hinzufügen, löschen, selektieren und finden von Elementen. Die Collection‐Schnittstelle wird von mehreren Schnittstellen erweitert. Abgeleitete Schnittstellen schreiben Verhalten vor, ob etwa der Container Werte doppelt beinhalten darf oder die Werte sortiert hält; List, Set und SortedSet sind pp ; , die wichtigsten. AbstractCollection implementiert Basisfunktionalität und belässt nur noch zwei abstrakte Funktionen. abstrakte Funktionen. Interface Collection: Beispiel 25 import java.util.*; class ErsteSammlung { public static void main( String args[] ) { Collection c = new LinkedList(); for ( int i = 0; i < 10; i++ ) c.add( "" + i ); for ( Iterator it = c.iterator(); c iterator(); it.hasNext();) it hasNext();) System.out.println( it.next() ); } } Ändern der Implementierung: Collection c = new LinkedList(); Collection c = new ArrayList(); Collection: Interface List 26 Eine Collection vom Typ List ist eine geordnete Menge von Objekten. ZZugriff auf Elemente entweder sequentiell oder über ihren Index (ihre Position in iff f El d i ll d üb ih I d (ih P i i i der Liste) zugegriffen werden kann. Wie bei Arrays hat das erste Element den Index 0 und das letzte den Index size() ‐ 1. Einfügen/Löschen von Elementen: an einer beliebigen Stelle der Liste. Die weiter hinten stehenden Elemente werden dann entsprechend nach rechts bzw. links p verschoben. Des weiteren gibt es Methoden, um Elemente in der Liste zu suchen. Das Interface List ist direkt aus dem Interface Collection D I t f Li t i t di kt d I t f C ll ti abgeleitet und erbt somit b l it t d bt it dessen Methoden. Zusätzlich gibt es einige neue Methoden, die zum wahlfreien Zugriff auf die Elemente benötigt werden. Einfügen von Elementen: add und addAll. Interface List – Methoden (Auswahl) 27 void add(int index, Object element) boolean add(Object o) boolean addAll(Collection c) boolean addAll(int index, Collection c) Object remove(int index) boolean remove(Object o) boolean removeAll(Collection c) boolean retainAll(Collection c) Ändert sich die Zusammensetzung der Liste true Collections des Typ List 28 I Collection I Li t List K Abstract Collection K I = Interface K = Klassen Abstract List K ArrayList Iterator Abstract Sequential List Vector LinkedList Stack K Beispiel – List(en) 29 import java.util.*; public class MyList { static void fillList(List list) { for (int i = 0; i < 10; ++i) { list.add("" + i); } list.remove(3); list.remove("5"); } static void printList(List list) { for ( (int i = 0; ; i < list.size(); (); ++i) ) { System.out.println((String)list.get(i)); } } System.out.println("---"); } Quelle: [Krüger] public static void main(String[] args) { //Erzeugen g der LinkedList LinkedList list1 = new LinkedList(); fillList(list1); printList(list1); //Erzeugen der ArrayList ArrayList list2 = new ArrayList(); fillList(list2); printList(list2); //Test von removeAll list2.remove("0"); list1.removeAll(list2); printList(list1); } 0 1 2 4 6 7 8 9 --- 0 1 2 4 6 7 8 9 --- 0 --- Schnittstelle Iterator 30 Iteration bei herkömmlichen Datenstruktur‐Klassen (und bis JDK 1.2): Enumeration (hasMoreElements(), nextElement()). Mit dem neuen Collection‐Framework (seit JDK 1.2): Iterator (hasNext(), next (), remove()). Ein Iterator kann die aufgezählte Datenstruktur grundsätzlich verändern (remove), eine Enumeration nicht. Bei allen Collections, die das Interface Collection implementieren, kann ein Iterator zum Durchlaufen aller Elemente mit der Methode iterator beschafft werden. Iterator + hasNext(): boolean + next(): Object + remove(): void Iterator ‐ Beispiel 31 import java.util.*; 2 public class MyIterator { public static void main(String[] args) { // Füllen der Liste ArrayList list = new ArrayList(); for (int i = 1; i <= 20; ++i) { list.add("" + i); } // Löschen von Elementen über Iterator Iterator it = list.iterator(); while (it.hasNext()) { String g s = (String) g it.next(); if (s.startsWith("1"))it.remove(); } //Ausgeben der verbleibenden Elemente it = list.iterator(); (); while (it.hasNext()) System.out.println((String) it.next()); } } Quelle: [Krüger] 3 4 5 6 7 8 9 20 Erweiterte for‐Schleife 32 Iterieren mit einem Iterator mit der for‐Schleife: for (Iterator it = ausdruck.iterator(); it.hasNext(); ){ formalerparameter = it.next(); anweisung; } Iterieren mit der äquivalenten, erweiterten for‐Schleife: f for (f (formalerparameter l t : ausdruck d k ) anweisung; i formalerparameter = aus Datentyp und Variablenname bestehende Parameterdeklaration der Art Integer i oder Object o ausdruck = Instanz oder ein Ausdruck des Typs java.lang.Iterable oder ein Array. Erweiterte for‐Schleife ‐ Beispiel 33 import java.util.*; public static void printVector2(Vector v) { for (Object j o : v) System.out.println(o); } public class ForLoop { } public static void printVector1(Vector v) { for (Iterator it = v.iterator();it.hasNext();){ Object o = it.next(); System.out.println(o); } } public static void main(String[] p g args) g { Vector v = new Vector(10); for (int i = 0; i < 10; i++) v.add (i, i*i); printVector1(v); printVector2(v); } Quelle: [Krüger] 0 0 1 1 4 4 9 9 16 16 25 25 36 36 49 49 64 64 81 81 Erweiterte for‐Schleife – Arrays 34 public static void printArray1(int[] args) { for (int i = 0; i < args.length; ++i) System.out.println(args[i]); } public static void printArray2(int[] args) { for (int a : args) System.out.println(a); } Wozu die erweiterte for‐Scheife Wozu die erweiterte for Scheife nicht nicht genommen werden kann: genommen werden kann: Das Durchlaufen der Collection von hinten nach vorn. Das simultane Durchlaufen mehrerer Collections. Das Löschen oder Ändern einzelner Elemente während des Durchlaufs. Collections des Typ Set 35 Collection I I Set I K Iterator SortedSet I = Interface K = Klassen Abstract Collection K AbstractSet K HashSet TreeSet K JobState Reasons LinkedHash Set SortedSet ‐ Konstruktoren 36 Ein parameterloser Konstruktor erzeugt eine leere Menge, deren (zukünftige) Elemente bezüglich ihrer natürlichen Ordnung sortiert werden Elemente bezüglich ihrer natürlichen Ordnung sortiert werden. Ein Konstruktor mit einem Argument des Typs Comparator erzeugt eine leere Menge, deren (zukünftige) Elemente bezüglich der durch den Comparator vorgegebenen Ordnung sortiert werden vorgegebenen Ordnung sortiert werden. Ein Konstruktor mit einem Argument vom Typ Collection erzeugt eine Menge, die alle eindeutigen Elemente der als Argument übergebenen Collection in ihrer natürlichen Ordnung enthält. l h d h l Ein Konstruktor mit einem Argument des Typs SortedSet erzeugt eine Menge mit denselben Elementen und derselben Sortierung wie die als Argument übergebene Menge. SortedSet ‐ Beispiel 37 import java.util.*; //Konstruieren des Sets TreeSet s = new TreeSet(new ReverseStringComparator()); public class MyTSortedSet { public static void main(String[] args) { //Konstruieren des Sets TreeSet s = new TreeSet(); s.add("Kiwi"); s.add("Kirsche"); s.add("Ananas"); s.add("Zitrone"); s.add("Grapefruit"); s.add("Banane"); //Sortierte Ausgabe Iterator it = s.iterator(); while (it.hasNext()) System.out.println((String)it.next()); } } Ananas s.add("Kiwi"); s.add("Kirsche"); s.add("Ananas"); s.add("Zitrone"); s.add("Grapefruit"); s.add("Banane"); //Sortierte Ausgabe for (Object o: s) System.out.println(o); . . . . . class ReverseStringComparator implements Comparator { public int compare(Object o1, Object o2) { return ((String)o2).compareTo((String)o1); } } Zitrone Banane Kiwi Grapefruit Kirsche Ki Kirsche h G Grapefruit f it Kiwi Zitrone Quelle: [Krüger] Banane Ananas Die Klasse Collections 38 Die Klasse Collections enthält eine große Anzahl Algorithmen (i.d.F. (i d F statischer Methoden) zur Manipulation Verarbeitung von Collections. Methoden zum Durchsuchen, Sortieren, Kopieren Synchronisieren von Collections sowie solche zur Extraktion Elementen mit bestimmten Eigenschaften. von und und von static void sort (List list) static void sort (List list, Comparator c) Fehlt der Comparator, wird die Liste in ihrer natürlichen Ordnung sortiert. i Dazu müssen ü alle ll Elemente l d Comparable‐Interface das C bl I f implementieren und ohne Typfehler paarweise miteinander vergleichbar sein. Gemäß JDK‐Dokumentation verwendet diese Methode ein modifiziertes Mergesort, das auch im Worst‐Case eine Laufzeit von O(n*log(n)) O(n log(n)) hat (auch bei der Klasse LinkedList) und damit auch für große Listen geeignet sein sollte. Collections: Problem Typsicherheit 1/2 39 Großes Problem mit Collections (bis Java 5): sie sind prinzipiell offen für jjeden Typ. yp Man speichert Objekte vom allgemeinsten Typ Object. Beim Lesen der Collection werden diese allgemeinen Objekte auch wieder zurück geliefert. geliefert Wenn man in einer Collection Apfel‐Objekte speichert, will man dort keine Birnen‐Objekte speichern – doch mit einen allgemeinen Typ Object kann a das nicht c verhindert e de werden. e de Beispiel: Apfel jona = new Apfel(); ArrayList apfelSpeicher = new ArrayList(); apfelSpeicher.add( jona ); fügt ein Element in die Liste ein, ein es hätte aber auch apfelSpeicher.add(new apfelSpeicher add(new Birne()) oder apfelSpeicher.add("ätsch") sein können. Der Fehler fällt beim Einfügen nicht auf, doch beim Wiederholen der yp p g folgt g die (g (gefürchtete)) Daten und anschließender Typanpassung ClassCastException. Collections: Problem Typsicherheit 2/2 40 Abhilfe seit Java 5 : Die Collection‐API macht massiven Gebrauch der Generics. Erst dadurch wird bessere Typsicherheit gewährleistet, denn nur ganz spezielle Objekte kommen in die Datenstruktur. Datenstruktur Mit den Generics lässt sich bei der Konstruktion einer Collection‐ Datenstruktur angeben, welche Objekte in die Liste aufgenommen werden dürfen. Konkrete Container‐Klassen (kleine Auswahl) 41 Listen ArrayList LinkedList Mengen HashSet TreeSet Assoziativspeicher HashMap TreeMap Schlange LinkedList Implementiert Listen-Funktionalität wie ein Vector. Sie erweitert dabei die Klasse AbstractList. ArrayList implementiert die Schnittstelle List. LinkedList ist eine doppelt verkettete Liste, also eine Liste von Einträgen mit einer Referenz auf den jeweiligen Nachfolger und Vorgänger Das ist nützlich beim Einfügen und Löschen von Vorgänger. Elementen an beliebigen Stellen innerhalb der Liste. Diese Klasse erweitert AbstractSequentialList. Eine Implementierung der Schnittstelle Set durch ein schnelles Hash Verfahren Hash-Verfahren Implementierung von Set durch einen Baum, der alle Elemente sortiert hält Implementiert einen assoziativen Speicher durch ein HashVerfahren. Sie erweitert die Klasse AbstractMap und ist damit auch eine Map. Exemplare dieser Klasse halten ihre Elemente in einem Binärbaum sortiert. TreeMap erweitert AbstractMap und implementiert SortedMap. Die verkettete Liste implementiert auch Queue. ArrayBlockingQueue Eine blockierende Warteschlage Warteschlage. PriorityQueue Prioritätswarteschlange.