Datenstrukturen in Java (Teil 2)

Werbung
Java
Programmierung mit
Datenstrukturen
> Datenstrukturen
in Java (Teil 2)
Mark Egloff 2006
1
Java
Programmierung mit
Lernziel Heute Abend
>
Sie lernen verschieden Datenstrukturen und Ihre Bedeutung
kennen z.B. „Arrays, Listen, Bäume, Maps“
>
Sie kennen die Unterschiede und wissen wann welche
Datenstruktur vorteilhaft eingesetzt werden sollte
>
Sie können eigene Datenstrukturen erstellen, diese sortieren
und entsprechend bearbeiten
Mark Egloff 2006
2
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Übersicht Datenstrukturen

>
Arrays
Mehrdimensionale Felder um Werte oder Objekte in einer festen Reihenfolge aufzunehmen. Die maximale Grösse ist festgelegt
>
Liste 
Die Liste ist eine Datenstruktur zur dynamischen Speicherung von beliebig
vielen Objekten. Objekte werden dabei einer Reihe nach abgelegt
>
Maps (Hashtabellen) 
„Maps“ sind Indexstrukturen (oder Assoziativspeicher), die die Elemente
anhand eines Indexes oder Schlüssels verwalten
>
Bäume ( nächsten Abend…)
Mehrere Elemente können auf andere Elmente verweisen. So entstehen
Verknüpfungen und es können „Bäume“ realisiert werden
Mark Egloff 2006
3
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Collections - Dynamische Datenstrukturen (1/2)
>
Bis jetzt haben wir Arrays kennen gelernt, die eine fixe Grösse haben.
Nun möchten wir uns mehr mit dynamischen Datenstrukturen befassen.
>
Dynamische Datenstrukturen passen ihre Größe der Anzahl der Daten an,
die sie aufnehmen. Dynamische Strukturen haben aber den Nachteil,
dass zur Laufzeit Speicher angefordert und verwaltet werden muss, wenn
Daten eingefügt werden.
>
Dieses Problem wurde mittlerweile von der Informatik erkannt, und der
Trend geht wieder hin zu festen, nicht dynamischen Datenstrukturen
 vorwiegend Arrays, natürlich nur dort, wo dies auch möglich ist.
>
Eine der grössten Neuerungen, die die Java-2-Plattform eingeführt hat, ist
die so genannte „Collection-API“. Ein Container als Objekt, welches
wiederum Objekte aufnimmt und die Verwaltung der Elemente übernimmt.
Mark Egloff 2006
4
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Collections - Dynamische Datenstrukturen (2/2)
>
In Java findet man alle Arten von dynamischen Datenstrukturen im
Package „java.util“. Dort ist das „Collection-API“ untergebracht.
>
Als zentrale Basis des API‘s dienen die Interfaces
„java.util.Collection“ und „java.util.Map“
>
Es existiert eine Hilfsklasse „java.util.Collections“ – ähnlich wie
bei den Arrays, die noch zusätzliche Unterstützungen anbietet
ablegen
holen
Objekte
Collection
Mark Egloff 2006
5
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Das Basis- Interface „java.util.Collection“ (1/3)
>
„Collection“ bildet die generelle Basis, die
fast alle Datenstrukturen implementiert (bis auf
die Assoziativspeicher: Arrays und Maps)
>
Listen sowie Set‘s basieren auf diesem
einfachem Interface. Durch die Schnittstelle
„Collection“ erhalten alle Klassen einen
gemeinsamen, äusseren Rahmen
>
Dadurch lassen sich Implementationen und
ihre Algorithmen einfach austauschen um die
jeweiligen Anforderungen abzudecken
>
Das Interface bietet Grund-Operationen für z.B.
für Elemente hinzufügen, löschen, selektieren
und finden
Mark Egloff 2006
6
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Das Basis- Interface „java.util.Collection“ (2/4)
<<interface>>
Collection
<<interface>>
Set
<<interface>>
List
<<interface>>
SortedSet
HashSet
LinkedHashSet
ArrayList
TreeSet
Mark Egloff 2006
LinkedList
Vector
Stack
7
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Das Basis- Interface „java.util.Collection“ (3/4)
z.B. Nutzung des Interfaces „Collection“ mit versch. Implementationen
import java.util.*;
...
Collection col = new LinkedList();
col.add("Head");
col.add("first");
col.add("Java");
for(Iterator it = col.iterator(); it.hasNext(); )
System.out.print( it.next() + " ");
Ausgabe:
Head first Java
 dieselbe Reihenfolge wie eingefügt
Mark Egloff 2006
8
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Das Basis- Interface „java.util.Collection“ (4/4)
z.B. Nutzung des Interfaces „Collection“ mit versch. Implementationen
import java.util.*;
...
Collection col = new TreeSet();
col.add("Head");
col.add("first");
col.add("Java");
Einfacher Austausch der
Implementation, Rest
bleibt gleich, jedoch
anderes Verhalten
for(Iterator it = col.iterator(); it.hasNext(); )
System.out.print( it.next() + " ");
Ausgabe:
Head Java first
 sortierte Reihenfolge
Mark Egloff 2006
9
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Auswahl der „richtigen“ Collection- Klasse
Zugriff ohne Schlüssel
keine Dupplikate
?
?
Zugriff über Schlüssel
Duplikate erlaubt
<< Set >>
<< Map >>
<< List >>
Opt. Zugriff
?
Sortiertes
Iterieren
Opt.
Zugriff
HashSet
?
Sortiertes
Iterieren
Opt.
Zugriff
TreeSet
singlethread
ArrayList
?
Einfügen
nur am Kopf
threadsafe
LinkedList
HashTable
?
?
single thread
HashMap
TreeMap
threadsafe
Vector
Stack
Mark Egloff 2006
10
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
> Listen in Java
Mark Egloff 2006
11
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen
>
Die Liste ist eine Datenstruktur zur dynamischen Speicherung von
beliebig vielen Objekten.
>
Dabei beinhaltet jedes Listenelement als Besonderheit einen Verweis
auf das nächste Element, wodurch die Gesamtheit der Objekte zu einer
Verkettung von Objekten wird. Listen sind somit stets linear.
Mark Egloff 2006
12
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Vorteile/Nachteile gegenüber Arrays
>
Vorteil: Listen können beliebige Anzahl von Objekten aufnehmen bzw.
verknüpfen. Sie müssen nicht auf eine bestimmte Grösse initialisiert
werden. Neue Objekte können einfach am Ende angehängt werden.
 Speicher wird effizienter genutzt, keine leere, vorreservierte Plätze
 Beliebige Grösse
>
Nachteil: Es ist nur möglich vom einen zum nächsten Objekt in der Liste
zu navigieren. Suchen nach Objekten ist aufwendig
Einfügen /Entfernen von Objekten mitten in der Liste benötigt
zusätzliche Logik um die Objekte wieder miteinander zu Verknüpfen.
 nur sequentieller Zugriff, macht es langsam
 zusätzlicher Verwaltungsaufwand
 Overhead um ein Objekt zu speichern, benötigt zusätzlicher Speicher
Mark Egloff 2006
13
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Beispiel einer einfachen Liste (1/2)
>
Der folgende einfache Code zeigt wie ein Listenelement abgebildet
werden könnte. Natürlich müssen Listen in Java nicht selber
implementiert werden
1
DATA
next
Listenelement 1
2
DATA
next
Listenelement 2
class ListenElement {
int index;
Object data;
ListenElement next
3
DATA
null
Listenelement 3
ListenElement
index
data
next
next
}
Mark Egloff 2006
14
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Beispiel einer einfachen Liste (2/2)
ListenElment l1 = new ListenElement(1, "Alpha");
ListenElment l2 = new ListenElement(2, "Beta");
ListenElment l3 = new ListenElement(3, "Gamma");
l1.next = l2;
l2.next = l3;
1
Alpha
next
Listenelement 1
2
Beta
next
Listenelement 2
Mark Egloff 2006
3 Gamma
null
Listenelement 3
15
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Übersicht verschiedener Implementationen
>
java.util.ArrayList
Liste auf der Basis eines Arrays. Der interne Array wird bei Bedarf
automatisch vergrössert. Ist nicht – threadsafe.
>
java.util.LinkedList
Bildet eine verknüpfte Liste (ohne Array). Ist nicht – threadsafe.
>
java.util.Vector
Liste auf der Basis eines Arrays. Der interne Array wird bei Bedarf
automatisch vergrössert. Ist threadsafe.
>
java.util.Stack
Basiert auf „Vector“, bildet eine „last-in-first-out“ (LIFO) Liste. Ist
threadsafe.
Mark Egloff 2006
16
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Übersicht verschiedener Implementationen
interface
Collection
AbstractList
Cloneable
java.io.Serializable
ArrayList
interface
List
AbstractSequentialList
Cloneable
java.io.Serializable
LinkedList
Mark Egloff 2006
AbstractList
Cloneable
java.io.Serializable
Vector
Stack
17
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Auszug aus dem Interface „java.util.List“
Collection
interf ace
List
+size:int
+contains:boolean
+iterator:Iterator
+toArray:Object[]
+toArray:Object[]
+add:boolean
+remove:boolean
+containsAll:boolean
+addAll:boolean
+addAll:boolean
+removeAll:boolean
+retainAll:boolean
+clear:void
+equals:boolean
+hashCode:int
+get:Object
+set:Object
+add:void
+remove:Object
+indexOf:int
+lastIndexOf:int
+listIterator:ListIterator
+listIterator:ListIterator
+subList:List
public interface List extends Collection
{
int
size();
boolean add(Object o);
void
add(int index, Object o);
boolean remove(Object o);
Object
remove(int index);
Object
get(int index);
boolean set(int index);
boolean removeAll(Collection c);
void
clear();
Iterator iterator();
...
}
Der spezieller Unterschied gegenüber
„Collection“ ist, dass man über einen Index auf
die Elemente zugreifen kann
Mark Egloff 2006
18
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Beispiel Vector
import java.util.*;
class Run
{
public static void main(String[] args)
{
List l = new Vector();
Instanzierung
Kreis k = new Kreis(2.5f);
l.add(k);
Hinzufügen
k = (Kreis) l.get(0);
k = (Kreis) l.get(1);
}
Lesen
// Laufzeitfehler
// IndexOutOfBoundsExcpetion
}
Mark Egloff 2006
19
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Beispiel Stack
import java.util.*;
class Run
{
public static void main(String[] args)
{
Stack s = new Stack();
s.push("Head");
s.push("first");
s.push("Java");
}
System.out.println( s.pop() );
//  Java
System.out.println( s.pop() );
//  first
}
Mark Egloff 2006
20
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Performance verschiedener Implementationen
Class
LinkedList
ArrayList
Vector
(threadsafe)
Elemente
Add
Iterate
Remove
1‘000
0.070 ms
3.06 ms
0.07 ms
100‘000
64.7 ms
432.0 ms
8.2 ms
1‘000
0.062 ms
5.24 ms
0.71 ms
100‘000
22.5 ms
532.3 ms
6314.4 ms
1‘000
0.067 ms
5.49 ms
0.71 ms
100‘000
47.1 ms
560.3 ms
6314.6 ms
 Nach 10 Durchläufen mit JRE 1.5, 2GHz Pentium M, 1GB RAM
Die Wahl der richtigen Listen - Implementation ist entscheidend für die
Performance
Gewisse Listen lassen ein Fine-Tuning zu, um das Resizing-Verhalten zu
optimieren (initialCapacity, capacityIncrement)
Mark Egloff 2006
21
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Performance verschiedener Implementationen
http://javolution.org/doc/benchmark.html
Mark Egloff 2006
22
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Listen – Performance verschiedener Implementationen
http://javolution.org/doc/benchmark.html
Mark Egloff 2006
23
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
> Set‘s in Java
Mark Egloff 2006
24
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Set‘s
>
Sets oder auch „Mengen“ genannt sind eine spezielle Form von Listen,
welche das gleiche Element nur einmal aufnehmen. Diese Art von
Strukturen eignen sich bestens um eindeutige Werte aufzunehmen
>
Set‘s sind im allgemeinen langsamer als Listen, da sie zusätzlich eine
Logik besitzen um die Eindeutigkeit sicherzustellen. Man unterscheidet
zwischen geordneten (sortierten) sowie ungeordneten Set‘s
>
In Java bildet die Basis das Interface „java.util.Set“ bzw.
„java.util.SortedSet“
ablegen
Objekt
equals()
equals()
equals()
equals()
holen
equals()
Mark Egloff 2006
25
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Set‘s – Übersicht verschiedener Implementationen
>
java.util.HashSet
Schnelle Implementierung durch Hashing-Verfahren (HashMap). Ist nichtthreadsafe
>
java.util.TreeSet
Mittels Binärbäume realisiert, die eine Sortierung ermöglichen. Ist nichtthreadsafe
>
java.util.LinkedHashSet
Schnelle Mengenimplementierung unter Beibehaltung der
Einfügereihenfolge. Ist nicht- threadsafe
>
java.util.EnumSet (seit Java 1.5).
Eine spezielle Menge ausschließlich für Enum-Objekte. Ist nicht- threadsafe
>
java.util.concurrent.CopyOnWriteArraySet (seit Java 1.5)
Schnelle Datenstruktur eignet sich für viele lesende Zugriffe Ist threadsafe
Mark Egloff 2006
26
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Set‘s – Übersicht verschiedener Implementationen
interf ace
java.util.Collection
Collection
interf ace
java.util.Set
Cloneable
java.io.Serializable
j av a.util.TreeSet
interf ace
java.util.SortedSet
Cloneable
java.io.Serializable
j av a.util.HashSet
Mark Egloff 2006
AbstractCollection
java.util.AbstractSet
27
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Set‘s – Auszug aus dem Interface „java.util.Set“
Collection
interf ace
java.util.Set
+size:int
+contains:boolean
+iterator:Iterator
+toArray:Object[]
+toArray:Object[]
+add:boolean
+remove:boolean
+containsAll:boolean
+addAll:boolean
+retainAll:boolean
+removeAll:boolean
+clear:void
+equals:boolean
+hashCode:int
public interface Set extends Collection
{
int
size();
boolean add(Object o);
boolean remove(Object o);
boolean removeAll(Collection c);
void
clear();
Iterator iterator(); //  Enumeration
...
}
Mark Egloff 2006
28
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Set‘s – Beispiel mit HashSet
import java.util.*;
public class Run {
public static void main(String args[]) {
Set set = new HashSet();
set.add("Bernadine");
set.add("Elizabeth");
set.add("Gene");
set.add("Elizabeth");
Instanzierung
Hinzufügen
(Elizabeth 2x)
System.out.println( set )
}
}
Ausgabe:
[Gene, Bernadine, Elizabeth]
 unsortierte, zufällige Reihenfolge
Mark Egloff 2006
29
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Set‘s – Beispiel mit TreeSet
import java.util.*;
public class Run {
public static void main(String args[]) {
Set set = new TreeSet();
set.add("Bernadine");
set.add("Elizabeth");
set.add("Gene");
set.add("Elizabeth");
Instanzierung
Hinzufügen
(Elizabeth 2x)
System.out.println( set )
}
}
Ausgabe:
[Bernadine, Elizabeth, Gene]
 sortierte Reihenfolge
Mark Egloff 2006
30
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Set‘s – Funktionsweise von HashSet & TreeSet
>
java.util.HashSet
HashSet verwendet intern die „java.util.HashMap“. Es wird beim
Einfügen vom jeweiligen Objekt ein eindeutiger Wert
(Identifikationsnummer, Hash) berechnet. Hierzu wird vom Objekt die
Methode „hashCode()“ aufgerufen (vererbt von „java.lang.Object“).
Diese muss für eigene Objekte überschrieben werden.
>
java.util.TreeSet
Verwendet intern für die Sortierung das Interface
„java.lang.Comparable“. Das jeweilige Objekt muss dieses Interface
unterstützen, ansonsten wird eine „ClassCastException“ ausgelöst.
Bei Objekten eigener Klassen muss dieses Interface implementiert
werden.
Mark Egloff 2006
31
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
> Iteratoren in Java
Mark Egloff 2006
32
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Iteration - Mit einem Iterator durch die Daten wandern
>
Um über generische und dynamische Datenstrukturen zu wandern wurde
in der Informatik ein spezielles Design geschaffen das „Iterator“-Pattern.
>
Der „Iterator“ (oder „Cursor“) ist dabei ein Zeiger, mit dem über die
Elemente einer Liste bzw. durch die Elemente iteriert werden kann.
>
Er verweist nur auf das aktuelle Objekt in einer Collection und kann mit
entsprechenden Operationen auf das nächste Objekt verschoben werden
Iterator
next()
next()
Collection
next()
next()
Objekt
Mark Egloff 2006
33
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Iteration - Mit einem Iterator durch die Daten wandern
>
Das „Iterator“-Pattern erlaubt uns über eine beliebige Datenstruktur zu
iterieren ohne die genaue Implementation zu kennen
>
Unsere Applikation bedient sich dabei nur einem zentralen Interface
„Iterator“
<< Interface>>
Collection
creates
iterator()
…
<< Interface>>
Iterator
hasNext()
next()
use
MyApp
main()
creates
ArrayList
…
ArrayListIterator
has
…
Mark Egloff 2006
Iterator Pattern
34
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Iteration - Mit einem Iterator durch die Daten wandern
>
Für Iteratoren definiert die Java-Bibliothek zwei unterschiedliche
Schnittstellen. Das hat historische Gründe.
>
Die Schnittstelle „java.util.Enumeration“ gibt es seit den ersten
Java-Tagen; die Schnittstelle „java.util.Iterator“ gibt es seit Java
1.2 (seit der Collection-API). Der Typ „Iterator“ sollte in der Regel
verwendet werden.
>
Beide Schnittstellen funktionieren nach dem demselben Prinzip. Sie
besitzen eine Funktion, die jeweils das nächste Element erfragt z.B.
„next()“ und eine Funktion, die ermittelt, ob es überhaupt ein nächstes
Element gibt z.B. „hasNext()“. So wandert der Iterator Element für
Element ab.
Mark Egloff 2006
35
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Iteration – Auszug aus den Iterator Interfaces:
interf ace
java.util.Enume ration
+hasMoreElement s:boolean
+nextElement:Object
interf ace
java.util.Iterator
+hasNext:boolean
+next:Object
+remove:void
public interface Enumeration
{
boolean hasMoreElements();
Object
nextElement();
}
public interface Iterator
{
boolean hasNext();
Object
next();
void
remove();
}
Der spezieller Unterschied ist hier, dass „Iterator“ noch die Möglichkeit
bietet während der Iteration ein Element aus der Liste zu entfernen
Mark Egloff 2006
36
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Iteration - Mit einem Iterator durch die Daten wandern
z.B. Iteration mittels dem Interface „java.util.Iterator“
import java.util.*;
...
Collection col = new LinkedList();
col.add("Head"); col.add(...); ...;
// Iteration
Iterator it = col.iterator();
while( it.hasNext() ) {
String s = (String) it.next();
}
// Casting von Object auf String
Da „next()“ ein „java.lang.Object“ zurückliefert muss entsprechend gecastet werden. Achtung wegen „ClassCastException“
Mark Egloff 2006

37
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Iteration - Mit einem Iterator durch die Daten wandern
>
Seit Java 1.5 gibt es eine kürzere Version der „for“-Schleife um über
eine Collection oder Array zu iterieren
// herkömmliche Iteration
for (Iterator it = col.iterator(); it.hasNext(); ) {
String s = (String) it.next();
}
// seit Java 1.5
for (Object o : col ) {
String s = (String) o;
}
Achtung wegen „ClassCastException“. Die Collection
„col“ kann ja alles mögliche an Objekten beinhalten
Mark Egloff 2006

38
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Iteration – Collection während der Iteration bearbeiten
Während einer Iteration ist es untersagt die Collection zu verändern
z.B. Elemente hinzuzufügen oder zu entfernen. Wer es trotzdem tut
erhält eine „ConcurrentModificationException“.

for (Iterator it = col.iterator(); it.hasNext(); ) {
String s = (String) it.next();
if ( ... ) col.remove( s )) ...;
 Laufzeitfehler!
}

>
Das Interface „Iterator“ bietet eine Methode „remove()“ an um
während der Iteration gleich das aktuelle Elemente zu entfernen
for (Iterator it = col.iterator(); it.hasNext(); ) {
String s = (String) it.next();
if ( ... ) it.remove() ) ...;
 richtig !!
}

Mark Egloff 2006
39
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Generische Datentypen in der Collection-API (1/5)
>
Ein grosses Problem bei der Handhabung von Collections ist, dass sie
prinzipiell offen für jeden Typ sind, da sie Objekte vom allgemeinsten Typ
„java.lang.Object“ beim Speichern entgegennehmen und diesen
auch als Rückgabe liefern.
Problem: Objekte gehen als
Ihre Datentypen (Fussball,
Fisch, Gitarre, Auto) rein und
kommen aber als generisches
Objekt wieder raus
 Casting ist notwendig !
Mark Egloff 2006
40
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Generische Datentypen in der Collection-API (2/5)
>
Falsches Casting bzw. das Auftreten von „ClassCastException“ zur
Laufzeit ist daher keine Seltenheit.
z.B. falsches Casting bei einer Collection mit gemixten Datentypen
Collection col = new ArrayList();
col.add( "Text…" );
col.add( new Integer(123) ); // mixed types
for (Iterator it = col.iterator(); it.hasNext(); ) {
String s = (String) it.next();
}
Mark Egloff 2006
//  Laufzeitfehler
beim 2. Element
41
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Generische Datentypen in der Collection-API (3/5)
>
Um diese Handhabung zu vereinfachen und um
„ClassCastExceptions“ zu vermeiden, wurde seit Java 1.5 eine
Möglichkeit geschaffen um den genauen Typ anzugeben
Kompromisslösung mittels
„Generics“: Es wird eine
Collection für einen Typ (z.B.
Fisch) geschaffen . Alle
gehen als Fische rein und
kommen auch wieder als
Fische raus
Mark Egloff 2006
42
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Generische Datentypen in der Collection-API (4/5)
>
Bei der Instanzierung muss die Klasse der Elemente angegeben werden.
Diese Typangabe erfolgt mit „<ClassName>“ jeweils nach dem
Klassennamen der Collection
>
Der Syntax ähnelt dem Prinzip der „Templates“ in C++.
z.B. Typisierte Collection ab Java 1.5
Collection<String> col = new ArrayList<String>();
col.add( "Text…" );
col.add( new Integer(123) ); //  Compilerfehler, nur String erlaubt
Mark Egloff 2006
43
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Generische Datentypen in der Collection-API (5/5)
>
Bei diesen typisierten Collections muss dann später nicht mehr gecastet
werden.
z.B. Typisierte Collection ab Java 1.5
List<String> col = new ArrayList<String>();
col.add( "Head" );
col.add( "first" );
col.add( "Java" );
// kein Casting mehr notwendig:
String first = col.get(1);
for (String s : col ) {
System.out.println(s);
}
// „get()“ gibt nun direkt String zurück
// direkter String-Iterator
Mark Egloff 2006
44
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
> Maps in Java
Mark Egloff 2006
45
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Maps
>
Eine Map ist ein Assoziativspeicher, der Objekte unter Verwendung einer
Zuordnung (Index) verwaltet.
>
Eine Map sind wie Postfächer anzusehen. Sie speichern die Objekte
anhand eines zusätzlichen Schlüssels (Key) ab, welcher als Index dient.
Dieser Schlüssel ist natürlich wiederum ein Objekt.
Key
Key
ablegen
holen
Daten
Daten
Map
Mark Egloff 2006
46
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Map‘s in Java
>
In Java bildet das Interface „java.util.Map“ die Basis für alle Maps. Sie
ist nicht kompatibel zum Interface „java.util.Collection“
>
Die Java Collection-API bietet wie bei den Set‘s entsprechend eine
sortierte und unsortierte implementationen an.
Übersicht verschiedener Implementationen
>
java.util.HashMap
Schnelle Implementierung durch Hashing-Verfahren. Ist nicht- threadsafe
>
java.util.Hashtable
Schnelle Implementierung durch Hashing-Verfahren. Ist threadsafe
>
java.util.TreeMap
Besitzt ein langsamerer Zugriff, doch dafür sind alle Schlüssel sortiert. Sie
sortiert die Schlüssel in einen Binärbaum ein. Ist nicht- threadsafe
Mark Egloff 2006
47
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Map‘s – Übersicht verschiedener Implementationen
interf ace
Map
Dictionary
Cloneable
java.io.Serializable
Hashtable
AbstractMap
Map
Cloneable
java.io.Serializable
HashMap
AbstractMap
AbstractMap
SortedMap
Cloneable
java.io.Serializable
TreeMap
empty :boolean
Mark Egloff 2006
48
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Map‘s – Auszug aus dem Interface „java.util.Map“
interf ace
Map
+size:int
+containsKey:boolean
+containsValue:boolean
+get:Object
+put:Object
+remove:Object
+putAll:void
+clear:void
+keySet:Set
+values:Collection
+entrySet:Set
+equals:boolean
+hashCode:int
public interface Map
{
int
size();
boolean containsKey(Object key);
boolean containsValue(Object value);
Object
put(Object key, Object value);
Object
get(Object key);
Object
remove(Object key);
void
clear();
...
}
Mark Egloff 2006
49
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Map‘s – Beispiel mit HashMap, Standard Schlüssel (1/2)
public class Kunde
{
public int
kndNnummer;
public String vorName;
public String nachName;
public Kunde( int
kndNummer,
String vorName,
String nachName)
{
this.kndNummer = kndNummer;
this.vorName
= vorName;
this.nachName = nachName;
}
}
Mark Egloff 2006
50
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Map‘s – Beispiel mit HashMap, Standard Schlüssel (2/2)
import java.util.*;
public class Run {
public static void main(String args[]) {
Map map = new HashMap();
map.put( new Integer(112),
new Kunde(112, "Hans", "Müller"));
map.put( new Integer(113),
new Kunde(113, "Max", "Moritz"));
Kunde k1 = (Kunde) map.get( new Integer(112) );
Kunde k2 = (Kunde) map.get( new Integer(113) );
}
}
Als Schlüssel muss ein Objekt bzw. Klasse verwendet werden, welche eine
Implementation der „hashCode()“ Methode besitzt
Mark Egloff 2006
51
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Map‘s – Beispiel mit HashMap , Ieration (1/2)
z.B. Iteration durch eine Map, durch alle Schlüssel und alle Elemente
// herkömmliche Iteration
Iterator it = map.keySet().iterator();
while( it.hasNext() ) {
Object key
= it.next();
Kunde k
= ( Kunde ) map.get( key );
System.out.println( k );
// unsortierte Ausgabe
}
// ab Java 1.5 mit erweiterter for- Schleife
for ( Object key : map.keySet() ) {
Kunde k
= ( Kunde ) map.get( key );
System.out.println( k );
// unsortierte Ausgabe
}
Mark Egloff 2006
52
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Map‘s – Beispiel mit HashMap, Iteration (2/2)
z.B. Iteration durch eine Map, durch alle Schlüssel und alle Elemente
// ab Java 1.5 mit der Benützung von „<Generics>“ vereinfacht sich die Iteration
HashMap<Integer,Kunde> map = new HashMap<Integer,Kunde>();
map.put( new Integer(112),
new Kunde(112, "Hans", "Müller"));
...
for ( Integer key : map.keySet() ) { // kein Casting notwendig
Kunde k = map.get( key );
System.out.println( k );
}
Der Einsatz von <Generics> ist nur möglich falls die Typen für die Schlüssel
sowie für die Datenelemente immer gleich sind
Mark Egloff 2006
53
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Map‘s – Beispiel mit TreeMap (1/2)
import java.util.*;
public class Run {
public static void main(String args[]) {
Map map = new TreeMap();
Einfacher
Austausch der
Implementation.
map.put( new Integer(112),
new Kunde(112, "Hans", "Müller"));
map.put( new Integer(113),
new Kunde(113, "Max", "Moritz"));
Kunde k1 = (Kunde) map.get( new Integer(112) );
Kunde k2 = (Kunde) map.get( new Integer(113) );
}
}
Als Schlüssel muss ein Objekt bzw. Klasse verwendet werden, welche das
Interface „java.lang.Comparable“ implementiert
Mark Egloff 2006
54
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Map‘s – Beispiel mit TreeMap (2/2)
z.B. Iteration durch eine Map, durch alle Schlüssel und alle Elemente
// herkömmliche Iteration
Iterator it = map.keySet().iterator();
while( it.hasNext() ) {
Object key
= it.next();
Kunde k
= ( Kunde ) map.get( key );
System.out.println( k );
// sortierte Ausgabe
}
Da „map“ hier eine SortedMap ist, erfolgt die Iteration durch die Schlüssel
sortiert
Mark Egloff 2006
55
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Map‘s – Funktionsweise von HashMap & TreeMap
>
java.util.HashMap
Es wird beim Einfügen vom jeweiligen Key-Objekt ein eindeutiger Wert
(Identifikationsnummer, Hash) berechnet. Hierzu wird vom Key die
Methode „hashCode()“ aufgerufen (vererbt von „java.lang.Object“).
Diese muss für eigene Key-Klassen überschrieben werden.
>
java.util.TreeMap
Verwendet intern für die Sortierung das Interface
„java.lang.Comparable“. Das jeweilige Key-Objekt muss dieses
Interface unterstützen, ansonsten wird eine „ClassCastException“
ausgelöst. Bei eigenen Keys muss dieses Interface implementiert werden.
Mark Egloff 2006
56
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
> Hilfsklasse „Collections“
Mark Egloff 2006
57
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Hilfsklasse „java.util.Collections“
>
Ähnlich wie bei den Arrays (java.util.Arrays) existiert auch für die
Collections und Maps eine Hilfsklasse mit nützlichen statischen
Funktionen: „java.util.Collections“
>
Die Klasse bietet bekannte Dinge wie binäre Suche, Ermittlung des
min/max Elementes, Sortierung sowie Generierung von Zufallsreihenfolgen an. Eine wesentliche weitere Funktionalität sind die „Factory“
- Methoden um „threadsafe“ oder „immutable“ Collections zu erzeugen.
z.B. Erzeugung einer „threadsafe“ - Liste mittels „Collections“
Collection c = new ArrayList(); // ArrayList ist nicht threadsafe
...
Collection sc = Collections.synchronizedCollection(c);
sc.add( "Text…" );
Mark Egloff 2006
58
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
> Handhabungen von
Collections
Mark Egloff 2006
59
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Collections sind Objekte
>
Collections sind normale Objekte, es gelten somit die gleichen bzw.
ähnliche Gesetze, wie wir schon kennen gelernt haben.
>
Alle Implementationen von „java.util.Collection“ sowie
„java.util.Map“ stammen automatisch von „java.lang.Object“ ab.
>
All diese Container besitzen somit eine „equals()“ sowie eine „clone()“
Methode. Doch wie wir schon bei den Arrays gesehen haben, müssen wir
die Details hierzu anschauen
z.B. Vergleich von 2 Collections
Collection c1 = new ArrayList();...
Collection c2 = new ArrayList();...
...
if ( c1.equals(c2) )  geht das ?? Was passiert hier genau?
Mark Egloff 2006
60
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Vergleichen von Collections (1/2)
>
Beide Interfaces „java.util.Collection“ sowie „java.util.Map“
bieten die Methode „equals()“ an.
>
Die Implementation dieser Methode befindet sich bei der jeweiligen
Implementations-Klasse des Interfaces (z.B. „java.util.ArrayList“) .
Deshalb lohnt es sich jeweils ein Blick in die JavaDoc der jeweiligen
Klasse zu werfen
>
Die Klassen im Java API verhalten sich nach den folgenden Regeln. Eine
Collection ist gleich wenn …
1. sie von derselben Klassen-Familie sind z.B. (List != Set)
2. sie die gleiche Anzahl an Elementen in gleicher Reihenfolge aufweisen
3. Im Falle von „Map“ die Elemente gleich indexiert sind
4. die jeweiligen Element mit „a1.equals(b1)== true“ ergeben
Mark Egloff 2006
61
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Vergleichen von Collections (2/2)
z.B. Anwendung der „equals()“ Methode bei „gleichen“ Klasse
Collection c1 = new ArrayList();
Collection c2 = new LinkedList();
...
if (c1.equals(c2)) ...
// funktioniert richtig

Bei Elementen eigener Klassen muss die „equals()“ Methode
implementiert sein
z.B. Anwendung der „equals()“ Methode bei „unterschiedlicher“ Klasse
Collection c1 = new ArrayList();
Collection c2 = new HashSet();
...
if (c1.equals(c2)) ...
// immer „false“  ja nie machen !

Mark Egloff 2006

62
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Elemente in Collections prüfen mit „contains()“
>
Die Collection Klassen bieten eine Methode an, die überprüft ob sich ein
gleiches Element schon in der Collection befindet: „contains()“
>
Bei „Map“ existieren entsprechend 2 „containsXXX()“ Methoden.
Einmal für die Schlüssel  „containsKey()“
und einmal für die Elemente selber  „containsValue()“
>
Diese Methode ruft intern von jedem Element die „equals()“ Methode
auf. Bei Elementen eigener Klassen muss deshalb die „equals()“
Methode implementiert sein
z.B. Anwendung der „contains()“ Methode
Collection c = new ArrayList();
...
if (c.contains( "DATA" )) ...
Mark Egloff 2006
63
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Klonen von Collections
>
Um eine Collection zu klonen müssen wir die „clone()“ Methode von der
jeweiligen Implementations-Klasse aufrufen. Die Interfaces
„Collection“ oder „Map“ kennen das „clone()“ selber nicht.
>
Die „clone()“ Methode selber kopiert nur den Container (die Hülle). Die
Elemente selber werden nicht kopiert (Shallow Copy oder Flache Kopie).
Es verhält sich somit gleich wie bei den Arrays.
>
Ein „deep“- Copy existiert nicht in Java, man müsste selber eine
entsprechende Hilfs-Methode schreiben
z.B. Anwendung der „clone()“ Methode
ArrayList al = new ArrayList();
...
Collection c = (Collection) al.clone();
Mark Egloff 2006
64
Java
Programmierung mit
Datenstrukturen in Java (Teil 2)
Collections und Arrays
>
Manchmal muss man zwischen Arrays und Collections wechseln. Hierzu
werden von den Klassen entsprechende Methoden angeboten
>
Das Interface „java.util.Collection“ bietet die Methode
„toArray()“ an um die Collection in ein Array zu überführen
>
„java.util.Arrays“ bietet eine Hilfsmethode um einen Array in eine
Liste zu wandeln  „Arrays.asList()“
z.B. Collection in Array wandeln und wieder zurück
Collection c = new ArrayList();
c.add( "Java" );
...
String[] sArray = (String[]) c.toArray( new String[]{} );
c = Arrays.asList(sArray);
Mark Egloff 2006
65
Herunterladen