> Datenstrukturen in Java (Teil 2)

Java Programmierung mit Datenstrukturen > Datenstrukturen in Java (Teil 2) Mark Egloff 2006 1 Java Programmierung mit Lernziel Heute Abend > ...
Author: Nora Kolbe
4 downloads 2 Views 1MB Size
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) Collection

Set

List

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

>

>

> 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“

> Collection

creates

iterator() …

> 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 „“ jeweils nach dem Klassennamen der Collection

>

Der Syntax ähnelt dem Prinzip der „Templates“ in C++.

z.B. Typisierte Collection ab Java 1.5 Collection col = new ArrayList(); 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 col = new ArrayList(); 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 „“ vereinfacht sich die Iteration

HashMap map = new HashMap(); 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 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