public void

Werbung
Th. Letschert
OOP 2
5. Generizität I
© Th Letschert FH Gießen-Friedberg
Th. Letschert
OOP 2
Generizität I
- Vererbungs- und parametrische Generizität
- generische Kollektionen
Seite 2
Th. Letschert
OOP 2
Vererbungsund parametrische Generizität
Seite 3
Generizität
Generisch / Generizität
unspezifisch, allgemein / allgemein verwendbar
Polymorphismus und Generizität
generisch (lat.):
eine Gattung oder ein
Geschlecht (Familie)
betreffend.
Polymorphismus = Vielgestaltigkeit
die Vielgestaltigkeit macht allgemein verwendbar
Generizität ist das Ziel: Polymorphismus ist ein Mittel
Varianten der Generizität
Vererbungs-, Schnittstellen-Polymorphismus ~> VererbungsGenerizität
allgemeine Verwendbarkeit duch Typ- / Subtyp-Relation
1. Verebungs-Polymorphismus:
» Klasse / Subklasse ~> Typ / Subtyp
2. Schnittstellen-Polymorphismus:
» Interface / Implementierende Klasse ~> Typ / Subtyp
Parametrischer Polymorphismus ~> Parametrische Generizität
allgemeine Verwendbarkeit durch Typ-Parameter
Seite 4
Schnittstellen-/Vererbungs- vs. parametrische Generizität
Vererbungsgenerizät:
Komme mit allen Arten klar !
Parametrische Generizität:
Kann für alle Arten etwas erzeugen !
Produziere Zwinger
für alle Arten
Ich nehme alles,
was ein
Hund ist.
Bernhardiner
mit Heidi
class Zwinger {
};
void sperrEin(Hund h) {
....}
...
Zwinger z = new Zwinger();
class Zwinger<T> {
void sperrEin(T t) {
...}
...
};
Zwinger<Dogge> z = new Zwinger<Dogge>();
Seite 5
Th. Letschert
OOP 2
Vererbungs-Generizität
Seite 6
Vererbungs-Generizität
Einsatz Vererbungsgenerizät I :
Abstraktion von Details des Benutzten
PinscherZwinger
Pinscher
hinein(Pinscher): void
radau(): void
belle(): void
DoggenZwinger
hinein(Dogge): void
radau(): void
Vom Pinscher- / Doggen-Zwinger zum
Hunde-Zwinger: Für den Hundezwinger
ist nur die Hunde-Eigenschaft relevant:
ImportSchnittstelle Hund
Pinscher
Dogge
belle(): void
belle(): void
Dogge
belle(): void
HundeZwinger
hinein(Hund): void
radau(): void
Hund
Hund
belle(): void
Seite 7
HundeZwinger
hinein(Hund): void
radau(): void
Hund
Hund
Vererbungs-Generizität
Einsatz Vererbungsgenerizität I :
Abstraktion von Details des Benutzten
public interface Hund {
public void belle();
}
Pinscher
belle(): void
Hund
public class Pinscher implements Hund {
....
}
Hund
public class Dogge implements Hund {
....
}
Dogge
belle(): void
HundeZwinger
hinein(Hund): void
radau(): void
Hund
public class HundeZwinger
....
}
{
Import-Schnittstellen
werden nicht explizit im
Code dokumentiert
Seite 8
Vererbungs-Generizität
Einsatz Vererbungsgenerizät II :
Abstraktion von Implementierungsdetails
Vom Array- / Listen-Zwinger zum
Zwinger: Für den Benutzer des
Zwingers ist die Implementierung
irrelevant
Export-Schnittstelle Zwinger
ArrayZwinger
hinein(O): void
radau(): void
Zwinger
ArrayZwinger
hinein(O): void
radau(): void
Array
Implementierung mit Array
Array
Zwinger
ListZwinger
ListZwinger
hinein(O): void
radau(): void
hinein(O): void
radau(): void
List
List
Implementierung mit Liste
Seite 9
Vererbungs-Generizität
Einsatz Vererbungsgenerizät I / II :
1. Abstraktion von Details des Benutzten
2. Abstraktion von Implementierungsdetails
Zwinger
ArrayZwinger
hinein(Hund): void
radau(): void
Zwinger
ListZwinger
hinein(Hund): void
radau(): void
2.
Hund
Hund
1.
Seite 10
Kombination:
Abstraktion vom Benutzten:
Import-Schnittstelle
Abstraktion von der Implementierung:
Export-Schnittstelle
Th. Letschert
OOP 2
Parametrische Generizität
Seite 11
Parametrische Generizität
Einsatz parametrische Generizität :
komplette Abstraktion vom Benutzten
Erzeugung spezialisierter Varianten
Zwinger
In einen Zwinger kann man
alles sperren: Ein T-Zwinger hat
keinen Bezug zu irgendwelchen
Eigenschaften von T.
T
hinein(T): void
hinaus(): T
Ebene 1: Generic
<<bind>>T->Dogge
DoggenZwinger
hinein(Dogge): void
hinaus(): Dogge
<<snapshot>>
Ebene 2: Klasse
käfig:DoggenZwinger
Ebene 3: Objekt
Seite 12
Parametrische Generizität
Parametrische Generizität in Java
Zwinger
T
class Zwinger<T> {
private ArrayList<T> l
= new ArrayList<T>();
hinein(T): void
hinaus(): T
Ebene 1: Generic
<<bind>>T->Dogge
DoggenZwinger
}
hinein(Dogge): void
hinaus(): Dogge
public void hinein(T h) {
l.add(h);
}
public void hinaus(T h) {
l.remove(0);
}
Ebene 1/2: Generische Klasse
Ebene 2: Klasse
Zwinger<Dogge> kaefig
= new Zwinger<Dogge>();
käfig:DoggenZwinger <<snapshot>>
Ebene 3: Objekt
Ebene 3: Objekt
Seite 13
Th. Letschert
OOP 2
Kombination
Parametrische und Vererbungs-Generizität
Seite 14
Parametrische- und Vererbungs-Generizität
2 Dimensionen der Generizität
Vererbung : Typ ~ Subtyp
Parametrisch: Typ-Parameter
Vererbung / Schnittstellen-Generizität
Hund
Zwinger<Bernhardiner>
RettungsBernhardiner
Seite 15
Zwinger<Dozent>
parametrische Generizität
Zwinger<Katze>
Parametrische + Vererbungs-Generizität
Wir können nur Hunde-Zwinger
erzeugen. Zwinger benötigt
Fähigkeiten von Hund,
Beschänkung des Imports
Typ-Parameter mit Beschränkungen
Hund <<interface>>
belle(): void
Zwinger
class Zwinger<T extends Hund> {
private ArrayList<T> l
= new ArrayList<T>();
T:Hund
hinein(T): void
lassBellen(): void
}
<<bind>>T->Dogge
<<snapshot>>
public void hinein(T h) {
l.add(h);
}
public void lassBellen() {
for(Hund h : l)
l.belle();
}
Zwinger<Dogge> kaefig
= new Zwinger<Dogge>();
käfig:DoggenZwinger
Seite 16
Parametrische + Vererbungs-Generizität
Typ-Parameter mit Beschränkungen
Varianten in der Implementierung
Wir können nur Hunde-Zwinger
erzeugen. Wir können sie aber in
verschiedenen Varianten erzeugen!
Hund <<interface>>
belle(): void
T:Hund
Zwinger <<interface>>
hinein(T): void
lassBellen(): void
<<realize>>
Das Wesen der Hunde
Zwinger beliebiger Hunde beliebiger Implementierung
Zwinger beliebiger Hunde mit Listen-Implementierung
Doggen-Zwinger beliebiger Implementierung
T:Hund
ListZwinger
hinein(T): void
lassBellen(): void
Zwinger<Dogge> kaefig = new ListZwinger<Dogge>();
<<bind>>T->Dogge
<<snapshot>>
käfig:DoggenListZwinger
Seite 17
Parametrische + Vererbungs-Generizität
Wir können nur Hunde-Zwinger
erzeugen. Wir können sie aber in
verschiedenen Varianten erzeugen!
Typ-Parameter mit Beschränkungen
Varianten in der Implementierung
Hund <<interface>>
belle(): void
T:Hund
Zwinger <<interface>>
hinein(T): void
lassBellen(): void
interface Hund {
public void belle();
}
public interface Zwinger<T extends Hund> {
public void hinein(T h);
public T hinaus() throws
NoSuchElementException ;
public void lassBellen();
}
public class ListZwinger<T extends Hund>
implements Zwinger<T> {
<<realize>>
private List<T> l = new LinkedList<T>();
T:Hund
public T hinaus()
throws NoSuchElementException{ ... }
ListZwinger
hinein(T): void
lassBellen(): void
<<bind>>T->Dogge
<<snapshot>>
käfig:DoggenListZwinger
public void hinein(T h) { ... }
public void lassBellen() { ... }
}
Zwinger<Dogge> kaefig = new ListZwinger<Dogge>();
Seite 18
Th. Letschert
OOP 2
Beispiel:
Collections-Framework von Java
Seite 19
Java-Kollektionen / Collections-Framework
Package java.util
enthält:
Legacy collection classes
Standard-Implementierung diverser Kollektionen
z.B.: ArrayList, HashMap, ...
Collections Framework
Framework (Rahmen): Ein System von Klassen (Interfaces) mit Basisfunktionalität
Einsatz: Erweiterung durch Entwickler
Utility Classes
diverse Hilfsklassen
Seite 20
Collections-Framework
Collections Framework / Interfaces
Iterator
Iterable
ListIterator
Collection
List
Set
Iterator und ListIterator:
Durchlaufen / Durchlaufen
mit erweiterter Funktionalität
Queue
Map
SortedSet
SortedMap
RandomAccess
Kollektionen: Elemente
einfügen und mit Iterator
durchlaufen
Abbildungen: Elemente unter
einem Schlüssel einfügen
und Zugreifen
Wahlfreier Zugriff: Elemente
unter einem Index einfügen
und Zugreifen
Seite 21
Collections-Framework
List
<<interface>>
Collection
<<interface>>
Map
<<interface>>
Queue
<<interface>>
AbstractCollection
AbstractList
AbstractSet
AbstractMap
AbstractQueue
Abstract
SequentialList
LinkedList
HashSet
ArrayList
PriorityQueue
TreeSet
TreeMap
Vector
HashTable
„alte“ Klassen
HashMap
„alte“ Klassen
Stack
Properties
Seite 22
Th. Letschert
OOP 2
Beispiel:
Collections-Framework erweitern:
Ringpuffer einpassen
Seite 23
Ring-Puffer
Ring-Puffer:
Array ringförmig nutzen
buffer[SIZE]
front = 0;
rear = 0;
int count = 0;
SIZE = ...
Elemente
Schreibposition
Leseposition
Belegte Positionen
Puffergrösse
Entnehmen
Einfügen(x)
if (count > 0)
v = buf[rear];
rear = (rear + 1) % SIZE;
count--;
return v;
if (count < SIZE)
buf[front] = x;
count++;
front = (front + 1) % SIZE;
front
rear
Seite 24
Ring-Puffer
Ring-Puffer
Generizität:
Dimension
Größe
Typ der Elemente
Anforderungen an den Element-Typ: keine
Art
Parametrische Generizität, oder
Vererbungs-Generizität, oder
Parameter des Konstruktors
Schnittstelle / Implementierung
Ist Ring-Puffer
eine Schnittstelle oder
eine Implementierung?
Seite 25
Ring-Puffer im Collections-Framework
Collection
<<interface>>
List
<<interface>>
Map
<<interface>>
Queue
<<interface>>
AbstractCollection
AbstractList
AbstractSet
AbstractMap
Kollektion mit FIFOVerhalten
AbstractQueue
abstrakte
Basisklasse als
Implementierungshilfe
Abstract
SequentialList
LinkedList
HashSet
ArrayList
PriorityQueue
TreeSet
HashMap
RingBuffer
Vector
HashTable
„alte“ Klassen
„alte“ Klassen
Stack
Properties
Seite 26
TreeMap
Ring-Puffer im Collections-Framework
Iterable
<<interface>>
Queue
<<interface>>
E
E
AbstractQueue
RingBuffer
E
Ein Ring-Puffer
ist eine FIFO-Kolletion mit beschränkter Größe (Interface Queue)
Der Typ der Elemente
ist unbeschränkter generischer Parameter
Die Kapazität
kann – als Wert - nur als Parameter des Konstruktors auftreten
E
Seite 27
Abstract-Queue
java.util Class AbstractQueue<E>
A Queue implementation that extends this class must minimally define a method
Queue.offer(E) which does not permit insertion of null elements, along with methods
Queue.peek(),
Queue.poll(),
Collection.size(), and a
Collection.iterator() supporting Iterator.remove().
Typically, additional methods will be overridden as well. If these requirements cannot be
met, consider instead subclassing AbstractCollection.
Sinn von AbstractQueue:
size, offer, poll, peek, und iterator müssen implementiert werden,
der Rest basiert auf diesen Methoden und wird von AbstractQueue geliefert.
Seite 28
RingBuffer (1)
import java.util.AbstractQueue;
import java.util.Iterator;
public class RingBuffer<E> extends AbstractQueue<E> {
private
private
private
private
private
E
int
int
int
int
buffer[];
front = 0;
rear = 0;
count = 0;
SIZE;
//
//
//
//
//
Elemente
Schreibposition
Leseposition
Belegte Positionen
Puffergroesse
public RingBuffer( int capacity ) {
SIZE = capacity>0?capacity:0;
buffer = (E[]) new Object[SIZE];
}
Der Iterator fehlt noch
public Iterator<E> iterator() {
// TODO implementieren !
}
public int size() {
return count;
}
Seite 29
RingBuffer (2)
public boolean offer(E x) {
assert x != null;
if ( count == SIZE ) return false;
buffer[front] = x;
count++;
front = (front + 1) % SIZE;
return true;
}
public E peek() {
if (count == 0) return null;
return buffer[rear];
}
}
Ein Element anbieten:
Ergebnis ~ hat angenommen
Auf das nächste Element sehen, aber
es nicht entnehmen
public E poll() {
if (count == 0) return null;
Das nächste Element entnehmen falls
E v = buffer[rear];
möglich, sonst null .
rear = (rear + 1) % SIZE;
count--;
return v;
}
add wird von
RingBuffer<String> b = new RingBuffer<String>(3);
AbstractQueue
b.add("Charlotte");
geliefert.
b.add("Emil");
b.add("Hugo");
Exception in thread "main" java.lang.IllegalStateException: Queue full
b.add("Karla");
at java.util.AbstractQueue.add(AbstractQueue.java:64)
at ringbuffer.RingBuffer.main(RingBuffer.java:55)
add-Methode aus AbstractQueue
Seite 30
Iterator für RingBuffer (1)
public class RingBuffer<E> extends AbstractQueue<E> {
...
public Iterator<E> iterator() {
return new RingIterator();
}
}
private class RingIterator implements Iterator<E> {
...
}
...
Der Iterator wird als private innere Klasse definiert
Seite 31
ConcurrentModificationException
Wird eine Kollektion verändert während ein Iterator über sie läuft,
dann sollte sie eine ConcurrentModificationException werfen
Ringpuffer:
– Zahl der Modifikationen wird gezählt
– Diese Zahl darf sich während eines Iteratorlaufs nicht ändern
public class RingBuffer<E> extends AbstractQueue<E> {
...
private int modCount = 0;
...
public boolean offer(E x) {
...
modCount++;
...
}
Ring-Puffer zählt
Modifikationen
public E poll() {
...
modCount++;
...
}
}
Seite 32
Iterator für RingBuffer (2)
private class RingIterator implements Iterator<E> {
private int offset = 0;
private int modCountAtStart;
public RingIterator() {
modCountAtStart = modCount;
}
public boolean hasNext() {
if ( modCount != modCountAtStart )
throw new ConcurrentModificationException();
return count-offset > 0;
}
Modifikation während
eines Iteratorlaufs
wird entdeckt.
public E next() {
if (!hasNext()) throw new NoSuchElementException();
E v = buffer[(rear+offset)%SIZE];
public static void main(String[] args){
RingBuffer<String> b = new RingBuffer<String>(6);
offset++;
b.add("Karla");
return v;
for ( String s : b) {
System.out.println(s);
}
}
}
}
public void remove() {
throw new UnsupportedOperationException();
}
System.out.println( "GEHOLT: "+ b.remove() ) ;
Karla
GEHOLT: Karla
Exception in thread "main" java.util.ConcurrentModificationException
at ringbuffer.RingBuffer$RingIterator.hasNext(RingBuffer.java:69)
at ringbuffer.RingBuffer.main(RingBuffer.java:89)
Seite 33
Th. Letschert
OOP 2
Beispiel:
Binärbäume und das Collections-Framework
Seite 34
Binär-Bäume und das Collections-Framework
Fügen Sie geordnete Binär-Bäume in das Collections-Framework ein.
Geordnete Binär-Bäume: siehe Datei GBBaum.txt von Prof. Eichner (Algorithmen
und Datenstrukturen)
Generizität
welche Art von Generizität verwendet der Code ?
was ist die maximal mögliche Verallgemeinerung ?
Charakter (Schnittstelle / abstrakte Klasse / Klasse) ?
Einpassen entsprechend der Java-Konventionen !
Seite 35
Binär-Bäume und das Collections-Framework
Iterable
<<interface>>
E
Jede Kollektion ist iterierbar.
Set
<<interface>>
E
Jede Implementierung muss das
Interface Set implementieren.
Mengen haben beliebige Elemente.
AbstractSet
GbbSet
E
AbstractSet ist eine Hilfsklasse für die
Implementierung.
E:Comparable<E>
add(E e):boolean
remove(Object o):boolean
E
Processor
<<interface>>
process(E e)
GbbSet basiert auf geordneten binären
Bäumen und kann darum nur
vergleichbare Elemente verwalten.
Die Traversierung eines Baums kann mit
eine beliebige Aktion auf den Elementen
verbunden werden.
E:Comapable<E>
GBBaum
...
traverse(Processor<E> p)
Menge mit Binärbaum-Implementierung
Seite 36
Herunterladen