Foliensatz 17

Werbung
CS1005
Objektorientierte Programmierung
Bachelor of Science (Informatik)
Th Letschert
Datentypen und Datenstrukturen
Selbst definierte Datenstrukturen
Innere Klassen
Seite 1
© Th Letschert
Typen:
1. Kasper
2. Prinzessin
3. Großmutter
Datentypen und Datenstrukturen
Datenstrukturen: realisieren die Typen,
sie agieren hinter den Kulissen
Seite 2
Th Letschert
Datentyp / Datenstruktur
Typ / Datentyp / abstrakter Datentyp
Sicht von außen / Sicht des Anwenders
(Daten-) Typ ist charakterisiert durch sein Verhalten
(oft) durch Interface (Schnittstelle) beschreibbar
kann immer durch Spezifikation beschrieben werden
Datenstruktur
innere Sicht / Sicht des Implementierers
Struktur / Aufbau / Organisation von Daten
Ich bin ein
Stack !
5
2
push
pop
top
Seite 3
Datentyp / Datenstruktur
Datentyp / Datenstruktur / Interface
public interface Stack {
int top();
void push(int x);
void pop();
}
public class ArrayStack implements Stack
{
private int a[];
private int count;
}
public void push(int x) {
....
}
public void pop() {
....
}
Seite 4
Datentyp / Datenstruktur
Datenstrukturen und Kollektionstypen
Datentyp-Sicht der Liste:
Kollektionstypen:
Kollektion mit einem bestimmten
Datentypen die Kollektionen
Verhalten (definierte Reihenfolge)
(beliebiger) Elemente verwalten
Beispiele: Liste, Menge, Abbildung,
Stack, Warteschlangen, ...
gibt mir Dein
erstes Element
Kollektionstypen erfordern die
Datentyp Liste
Organisation ihrer Elemente in
Datenstrukturen
Weitere Beispiele Datenstruktur
Datenstruktur-Sicht der Liste:
linear über Verweise verkette
Speicherbereiche
Feld
Liste
Baum
...
umfasst
Knoten und
Verweise
Seite 5
Datenstruktur Liste
Th Letschert
Datentyp / Datenstruktur
Collection Framework:
Datenstrukturen
hinter der Fassade von Datentypen
Datentyp Liste
Datenstruktur Liste
LinkedList
Datentyp Liste
Datenstruktur Feld
Die Begriffe Datenstruktur und Datentyp werden (leider)
nicht immer klar getrennt. Bei der Datenstruktur steht die
Speicherorganisation im Vordergrund, beim Datentyp die
Schnittstelle.
Aber: Die Schnittstelle legt eine bestimmte
Speicherorganisation nahe und die Speicherorganisation
ermöglicht eine bestimmte Schnittstelle.
Seite 6
ArrayList
Th Letschert
Datenstruktur Baum
Seite 7
Th Letschert
Datenstruktur Baum
Bäume: zykelfreie Graphen
– Knoten
– Kanten (eventuell gerichtet
zu den „Kindern“ / Nachfolgern)
baumartige Datenstrukturen:
– Knoten: Speicherbereiche
– Kanten: Verweise
Einsatz baumartiger Datenstrukturen
– Implementierung von „schwach
sortierten“ Datentypen
– Darstellung hierarchischer Information
(z.B. Syntaxbäume)
– etc.
Bäume:
zykelfreie verbundene Graphen
+
1
Seite 8
7
4
Syntaxbaum
zu (1-4)+7
Th Letschert
Datenstruktur Baum
Binäre Bäume
– Knoten haben maximal 2 Nachfolger
binäre Suchbäume
– Knoten enthalten Informationen
– Informationen kommen nicht doppelt vor
– linke Nachfolger enthalten kleine Info
– rechte Nachfolger enthalten größere Info
Einsatz binärer Suchbäume
– schwache Sortierung für Datenstrukturen
in denen gesucht werden muss; z.B.
Verzeichnisse oder Menge (schon drin?)
– Suche im Suchbaum schneller als in
unsortierter Liste
– Einfügen schneller als in einer sortierten
Liste
Seite 9
6
3
1
9
5
12
binärer Suchbaum
Suche nach 5:
- 5 < 6 => links
- 5 > 3 => rechts
- 5 = 5 => gefunden
Th Letschert
Datenstruktur Baum im Collections Framework
Bäume im Collections- Framework
– java.util.TreeSet<E>
Set
<<interface>>
SortedSet <<interface>>
Mengen-Implementierung die einen Baum
als Datenstruktur verwendet und die
Ordnung der Elemente (compareTo) bei
der Speicherung berücksichtigt.
Vorteil gegenüber HashSet: Elemente
können sortiert durchlaufen werden.
Nachteil gegenüber HashSet: Operationen
sind etwas langsamer
AbstractSet
TreeSet
HashSet
Map
– java.util.TreeMap<K,V>
Abbildungs-Implementierung die einen
Baum als Datenstruktur verwendet und
die Ordnung der Schlüssel (compareTo)
bei der Speicherung berücksichtigt.
Vorteil gegenüber HashMap: Schlüssel
können sortiert durchlaufen werden.
Nachteil gegenüber HashMap: Operationen
sind langsamer
Seite 10
<<interface>>
SortedMap <<interface>>
AbstractMap
TreeMap
HashMap
Th Letschert
Datenstruktur Baum im Collections Framework
Beispiel: Vorkommen von Worten in Dateien
Wortvorkommen:
Wort ~>
( DateiName ~>
{ (Zeile, Spalte) | Wort kommt in Zeile an Spalte vor } )
static TreeMap< String,
TreeMap<String,
TreeSet<LineColumn>>>
wordOccurrance = new TreeMap<String,
TreeMap<String,
TreeSet<LineColumn>>>();
Der Typ der Variablen wird mit Klassen definiert (statt mit Interfaces, wie die allgemeine
Regel empfiehlt), da der Algorithmus die besonderen Fähigkeiten der Baum-Implementierungen benötigt.
Seite 11
Th Letschert
Datenstruktur Baum im Collections Framework
File f = null;
List<File> fileList = new ArrayList<File>();
Wortvorkommen feststellen
while (true) {
f = chooseFile("Text-Datei waehlen");
if (f == null) { break; }
fileList.add(f);
}
for (File file : fileList) {
String fileName = file.getCanonicalPath();
Scanner scan = new Scanner(file);
int lineNr = 0;
while (scan.hasNextLine()) {
String inputLine = scan.nextLine();
lineNr++;
String[] words = inputLine.split("\\s");
int fromIndex = 0;
for (String word : words) {
if (!word.matches("([a-zA-Z])([a-zA-Z0-9-_]|&[a|o|u|A|O|U]uml;)*")) { continue; }
TreeMap<String, TreeSet<LineColumn>> wordOcc = wordOccurrance.get(word);
if (wordOcc == null) {
wordOcc = new TreeMap<String, TreeSet<LineColumn>>();
wordOccurrance.put(word, wordOcc);
}
TreeSet<LineColumn> filePos = wordOcc.get(fileName);
if (filePos == null) {
filePos = new TreeSet<LineColumn>();
wordOcc.put(fileName, filePos);
}
int cloumnPos = inputLine.indexOf(word, fromIndex);
filePos.add(new LineColumn(lineNr, cloumnPos));
fromIndex = cloumnPos;
}
}
}
Seite 12
Th Letschert
Datenstruktur Baum im Collections Framework
Wortvorkommen ausgeben
for (String word : wordOccurrance.keySet()) {
System.out.println("Word: " + word);
TreeMap<String, TreeSet<LineColumn>> fileOcc = wordOccurrance.get(word);
for (String fn : fileOcc.keySet()) {
System.out.println("File: " + fn);
for (LineColumn lc : fileOcc.get(fn)) {
System.out.print(" " + lc + ",");
}
System.out.println();
}
}
Seite 13
Th Letschert
Datenstruktur Baum im Collections Framework
final class LineColumn implements Comparable<LineColumn> {
private int line;
private int column;
Wortvorkommen speichern
public LineColumn(int line, int column) {
this.line = line;
this.column = column;
}
public boolean equals(LineColumn lc) {
return line == lc.line && column == lc.column;
}
@Override
public boolean equals(Object o) {
if (o instanceof LineColumn) {
return equals((LineColumn) o);
} else { return false; }
}
@Override
public String toString() { return "Line: " + line + " Column: " + column; }
@Override
public int hashCode() { return line * column + line + column; }
}
@Override
public int compareTo(LineColumn o) {
return this.line != o.line ? this.line - o.line : this.column - o.column;
}
Seite 14
Th Letschert
Selbst definierte
Datenstrukturen
Seite 15
Th Letschert
Datentyp Menge implementiert als Baum
Interface Menge
– definiert Funktionalität
Implementierung als Suchbaum:
BaumMenge
Menge
<<interface>>
enthaelt(int): boolean
einfuege(int): void
– realisiert die Funktionalität mit einem
Suchbaum
<<realize>>
BaumMenge
0..2
Knoten
0..1
wert: int
Eine Instanz von BaumMenge
enthält maximal einen Knoten
(der anker genannt wird)
Jeder Knoten enthält
maximal zwei andere Knoten.
anker
enthaelt(int): boolean
einfuege(int): void
Binärbaum-Implementierung
einer Menge von int-Werten
Seite 16
Th Letschert
Datentyp Menge implementiert als Baum
public interface Menge {
public void
einfuege(int x);
public boolean enthaelt(int x);
}
Interface Menge
Implementierung BaumMenge
public class BaumMenge implements Menge {
public boolean enthaelt(int x) {
return enthaeltR(x, anker);
}
public void einfuege(int x) {
if ( anker == null )
anker = new Knoten(x,null,null);
else einfuegeR(x, anker);
}
private Knoten anker = null;
private static class Knoten {
int
wert;
Knoten
links;
Knoten
rechts;
Knoten(int e, Knoten links, Knoten rechts){
wert = e;
this.links = links;
this.rechts = rechts;
}
}
}
Seite 17
Methoden:
Rekursion über die
Baumstruktur.
statische innere Klasse:
Lokale
Klassendefinition
(statisch: weil ohne Bezug
zu einem Objekt.)
Knoten ist eine rein interne
Hilfsklasse
Th Letschert
Datentyp Menge implementiert als Baum
Interface Menge Implementierung BaumMenge
private void einfuegeR(int x, Knoten k) {
if ( x == k.wert )
return; // schon drin
else
if (x < k.wert ) {
if ( k.links == null )
k.links = new Knoten(x,null,null);
else
einfuegeR(x, k.links);
} else {
if (x > k.wert )
if ( k.rechts == null )
k.rechts = new Knoten(x,null,null);
else
einfuegeR(x, k.rechts);
}
}
}
Methoden:
Rekursion über die
Baumstruktur.
Seite 18
Th Letschert
Iterierbare Menge
java.lang
interface Iterable<T>
Iterierbare Klassen haben eine Methode
iterator, die einen Iterator über einen
Element-Typ T liefert.
interface Iterable<T> ist
Bestandteil der Klassenbibliothek
Iterator<T> iterator();
public interface Menge
extends Iterable<Integer> {
public void
einfuege(int x);
public boolean enthaelt(int x);
}
Jede Implementierung
von Menge ist eine
iterierbare Klasse mit
der Methode iterator,
die einen Iterator über
Integer liefert.
6
3
1
9
5
iterator
1, 3, 5, 6, 9, 12
12
Seite 19
Der Iterator könnte z.B. einen InfixDurchlauf der Knoten liefern.
Infix:
erst links, dann Mitte, dann rechts
Th Letschert
Iterierbare Menge / Programmrahmen
public class BaumMenge implements Menge {
......
public Iterator<Integer> iterator() {
return new BaumIterator();
}
class BaumIterator implements Iterator<Integer> {
public boolean hasNext() {
?????
}
public Integer next() {
?????
}
}
}
public void remove() {
throw new
UnsupportedOperationException();
}
Seite 20
nicht statische innere
Klasse: Lokale
Klassendefinition
mit Bezug zu einem
Objekt.
(Ein Iterator muss sich
auf den Baum beziehen,
den er durchlaufen soll.)
remove wollen wir nicht
implementieren!
Th Letschert
Iterierbare Menge
public class BaumMenge implements Menge {
....
private Knoten anker = null;
....
public Iterator<Integer> iterator() { return new BaumIterator(); }
class BaumIterator implements Iterator<Integer> {
LinkedList<Knoten> l;
BaumIterator() {
l = new LinkedList<Knoten>();
infix(anker);
}
private void infix(Knoten k) {
if ( k == null ) return;
infix(k.links);
l.add(k);
infix(k.rechts);
}
public boolean hasNext() {
return ! l.isEmpty();
}
public Integer next() {
Knoten k = l.getFirst();
l.removeFirst();
return k.wert;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Der Iterator
speichert intern eine
Liste der Knoten.
in nicht-statischen Klassen
ist ein Bezug auf das
umfassende Objekt
möglich. Hier ist das
umfassende Objekt eine
Instanz von BaumMenge
und der Bezug geht zur
Objekt-Variable anker
dieser Instanz.
remove wird nicht
unterstützt.
}
Seite 21
Th Letschert
Iterierbare Menge durchlaufen
BaumMenge b = new BaumMenge();
for (Integer i : b)
System.out.println(i);
Iterator<Integer> iter = b.iterator();
while ( iter.hasNext() ) {
System.out.println(iter.next());
}
ausführliche Form
Kurzform
Seite 22
Th Letschert
1
Innere Klassen
Seite 23
Th Letschert
Statische innere Klasse / geschachtelte Klasse
Statische innere Klassen unterscheiden sich nur in der Sichtbarkeit
/ Programmorganisation von anderen „normalen“Klassen
class A
In Methoden der
statischen inneren
Klasse können (nur)
statische Komponenten
der äußeren Klasse
verwendet werden
A.x
bezieht sich auf eine
Komponente der
äußeren Klasse
kurz x wenn x eindeutig ist
{
static T x;
static class I {
T x = A.x;
...
}
...
}
Seite 24
Th Letschert
Nicht-statische innere Klasse
Nicht-statische innere Klasse (kurz: innere Klasse):
jedes Exemplar hat einen (impliziten) Bezug zum erzeugenden Objekt
class BaumIterator implements Iterator<Integer> {
LinkedList<Knoten> l;
private BaumIterator() {
l = new LinkedList<Knoten>();
infix(BaumMenge.this.anker); // oder kurz:
infix(anker);
}
... etc. ...
}
kein static !
BaumMenge.this: Zeiger auf den Erzeuger
anker
ist eindeutig, darum hier
anker ~ BaumMenge.this.anker
Seite 25
Th Letschert
Nicht-statische innere Klasse
In Methoden der inneren
Klasse:
this
zeigt auf ein
Objekt der inneren Klasse
( auf „mich selbst“)
A.this
zeigt auf ein Objekt der
äußeren Klasse (auf
„meinen Erzeuger“)
nicht
statische
innere
Klasse
Exemplar ...
... I()
der new
äußeren ...new I()
Klasse A ...
A-Objekt
class A {
....
class I {
...
}
....
Exemplar
der
inneren
Klasse I
...
...
this
...this
...
A.this
...A.this
...
}
Struktur der
Klassendefinitionen
I-Objekt
Seite 26
Th Letschert
Statische / Nicht-statische innere Klasse
public class BaumMenge implements Menge {
// ...
public Iterator<Integer> iterator() {
return new BaumIterator(this);
}
private static class BaumIterator
implements Iterator<Integer> {
Normalerweise kann ein
Bezug zum erzeugenden
Objekt auch explizit gesetzt
werden!
LinkedList<Knoten> l;
private BaumIterator(BaumMenge m) {
l = new LinkedList<Knoten>();
infix(m.anker);
}
}
}
// ...
Seite 27
Th Letschert
Anonyme innere Klasse
Anonyme Klasse:
interface INF {
public TR m(TP x);
...
}
Klasse mit Definition und
Instanzierung in einem
Anonyme Klassen sind
immer innere Klassen
Instanzierungen sind
immer innerhalb einer
Methode und damit in
einer anderen Klasse
anonyme Klasse:
Instanzierungs-Stelle =
Definitionsstelle
class C {
...
void f() {
INF y = new
...
};
}
=
class C {
class Y implements INF {
public TR m(TP x) {...}
...
}
Anonyme Klassen sind
immer nicht statische
innere Klassen
Entwurfsentscheidung
Java
INF () {
public TR m(TP x){
...}
...
};
void f() {
INF y = new Y();
}
}
Seite 28
Th Letschert
Nicht-statische innere Klasse in Methoden
(Nicht statische) Klassen können innerhalb von Methoden definiert
werden
sie können anonym sein, müssen aber nicht
können nur auf Variablen der umfassenden Methode zugreifen, wenn
diese final sind.
Wichtigste (bekannteste) Anwendung: GUIs / ActionListener
Seite 29
Th Letschert
Nicht-statische innere Klasse in Methoden
public class Outer {
public interface Int2Int {
int f(int x);
}
private int x;
public Outer(int x) { this.x = x; }
public Int2Int genF (final int y) {
return new Int2Int() {
public int f(int a) {
return a+x+y;
}
};
}
Methoden-Variable
public static void main( String[] args){
Int2Int ff = (new Outer(1)).genF(2);
}
System.out.println(ff.f(3));
Ausgabe 6
}
Seite 30
Th Letschert
Nicht-statische innere Klasse in Methoden
public interface Int2Int {
int f(int x);
}
public final class Outer {
private int x;
public Outer(int x) { this.x = x; }
public Int2Int genF(final int y) {
}
}
class Inner implements Int2Int {
public int f(int a) {
return a + x + y;
}
}
return new Inner();
public static void main(String[] args) {
Int2Int ff = (new Outer(1)).genF(2);
System.out.println(ff.f(3));
}
Das Gleiche mit einer benannten inneren Klasse
Seite 31
Th Letschert
Anonyme innere Klasse
Anonyme innere Klassen
public class Outer {
– haben keine eigene
Konstruktordefinition
– können
Objektvariablen
definieren
private int x;
public Outer(int x) { this.x = x; }
public Int2Int genF (final int y) {
return new Int2Int() {
private int b;
public int f(int a) {
int temp = b;
b = a;
return x+y+temp;
}
};
}
Ausgabe ?
}
public static void main( String[] args){
Int2Int ff = (new Outer(1)).genF(2);
System.out.println(ff.f(3));
System.out.println(ff.f(3));
}
Seite 32
Th Letschert
Innere Klasse: Übersicht
innere Klasse: Klasse die innerhalb einer anderen definiert wird
statische innere / geschachtelte Klasse (static inner class / nested class)
Innere / geschachtelte Klasse ist ohne Bezug auf ein Objekt
Die Definition der inneren Klasse kann nur statische Komponenten der äußeren
Klasse nutzen
Statische innere Klassen haben einen Bezug zum statischen Anteil des
definierenden Kontexts (der Klasse in der sie definiert sind: ÄussereKlasse.....)
(nicht statische) innere Klasse (inner class)
Innere Klasse mit Bezug zu einem Objekt der äußeren Klasse (seinem Erzeuger)
Die Definition der inneren Klasse kann statische und nicht statische Komponenten
der äußeren Klasse nutzen.
Innere Klassen dürfen (im Gegensatz zu statischen inneren Klassen) keine
statischen Komponenten definieren.
(Statisch heißt ohne Bezug zu einem Objekt, Objekt-Bezug widerspricht dem
Konzept einer nicht-statischen Klasse)
Innere Klassen haben eine Bezug zum definierenden Kontext (dem Objekt das sie
erzeugt: ÄussereKlasse.this.... )
Seite 33
Th Letschert
Datenstrukturen / Java-Sprachelemente
Datenstrukturen
bestehen meist aus Knoten die über Referenzen miteinander verknüpft sind
werden (nicht nur) zur Realisation eines Kollektions-Typs verwendet
Kollektionen bieten Iteration über ihre Elemente
Iteratoren benötigen einen Bezug zu ihrem Erzeuger: der Kollektion über die
sie iterieren sollen.
Java-Sprachelemente
Kollektionen implementieren Iterable
Iteratoren implementieren Iterator
Knoten werden als innere Klassen definiert
Iteratoren werden als innere Klassen definiert
Kollektions-Typen implementieren die Iterable-Schnittstelle
Varianten Klassendefinition in Klasse:
 statisch
 nicht statisch
 nicht statisch, anonym
Seite 34
Th Letschert
Herunterladen