11.11 Die abstrakten Basisklassen für Container
Das Designprinzip der Collection-Klassen folgt drei Stufen: Schnittstellen legen Gruppen von Operationen für die verschiedenen Behältertypen fest; abstrakte Basisklassen führen die Operationen der Schnittstellen auf eine minimale Zahl von als abstrakt definierten Grundoperationen zurück, etwa addAll() auf add() oder isEmpty() auf getSize(); konkrete Klassen für bestimmte Behältertypen beerben die entsprechende abstrakte Basisklasse und ergänzen die unbedingt erforderlichen Grundoperationen (und einige die Performance steigernde Abkürzungen gegenüber der allgemeinen Lösung in der Oberklasse).
Es gibt eine Reihe von abstrakten Basisklassen, die den Containern eine Basisfunktionalität geben. Unter diesen Klassen sind:
AbstractCollection
Implementiert die Methoden der Schnittstelle Collection ohne iterator() und size(). AbstractCollection ist Basisklasse von AbstractList und AbstractSet.
AbstractList
Erweitert AbstractCollection und implementiert die Schnittstelle List. Für eine konkrete Klasse müssen lediglich Methoden für get(int index) und size() implementiert werden. Soll die Liste auch Elemente aufnehmen, sollte sie auch set(int index, Object element) implementieren. Andernfalls bewirkt das Einfügen von Elementen nur eine Unsupported OperationException. Die direkten Unterklassen sind AbstractSequentialList, ArrayList und Vector.
AbstractSequentialList
AbstractSequentialList erweitert AbstractList (und damit auch AbstractCollection) und bildet die Grundlage für die Klasse LinkedList. Im Gegensatz zur konkreten Klasse ArrayList bereitet Abstract SequentialList die Klasse LinkedList darauf vor, die Elemente in einer Liste zu verwalten und nicht wie ArrayList in einem internen Array.
AbstractSet
Erweitert AbstractCollection und implementiert die Schnittstelle Set. AbstractSet dient als Basis für die beiden Klassen HashSet und TreeSet. Es überschreibt auch keine Methoden der Oberklasse AbstractCollection, sondern fügt nur equals(Object)- und hashCode()-Methoden hinzu.
AbstractMap
Implementiert die Schnittstelle Map. Um eine konkrete Unterklasse zu erstellen, muss put() sinnvoll implementiert werden; überschreiben wir put() nicht, erhalten wir die bekannte UnsupportedOperationException. Für get(Object) gibt es eine Implementierung.
Das Wissen um diese Basisimplementierung ist nützlich, wenn eigene Datenstrukturen implementiert werden.
11.11.1 Optionale Methoden
Rufen wir eine optionale Methode auf, die von der Unterklasse nicht implementiert wird, erhalten wir eine UnsupportedOperationException. Die vielen Optional-Anmerkungen erschrecken zunächst und lassen die Klassen beziehungsweise Schnittstellen irgendwie unzuverlässig oder nutzlos wirken. Die konkreten Standardimplementierungen der Collection-API bieten diese Operationen jedoch vollständig an, nur die Spezial-Wrapper für nur Lese-Container lassen sie weg. Das Konzept der optionalen Operationen ist umstritten, wenn Methoden zur Laufzeit eine Exception auslösen. Besser wären natürlich separate kleinere Schnittstellen, die nur die Leseoperationen enthalten und zur Übersetzungszeit überprüft werden können; doch dann würde es noch deutlich mehr Schnittstellen im Util-Paket geben.
|