Objektorientierte Programmierung Java API PDF
Document Details

Uploaded by TriumphalUnderstanding8738
Philipps-Universität Marburg
Christoph Bockisch
Tags
Summary
Diese Präsentation von Prof. Christoph Bockisch an der Universität Marburg behandelt objektorientierte Programmierung. Es werden Java Generics, Klassen, Schnittstellen und wichtige Konzepte wie Comparable und Iterator erläutert, sowie Methoden zur Listenverwaltung.
Full Transcript
Objektorientierte Programmierung 609 12.4 Generische Klassen und Schnittstellen der Java API Das Paket java.util bietet unter anderem Algorithmen, Klassen und Schnittstellen zur (effizienten) Verwaltung von Mengen beliebiger Datenobjekte. Listen Suchbäume...
Objektorientierte Programmierung 609 12.4 Generische Klassen und Schnittstellen der Java API Das Paket java.util bietet unter anderem Algorithmen, Klassen und Schnittstellen zur (effizienten) Verwaltung von Mengen beliebiger Datenobjekte. Listen Suchbäume Sortierverfahren Wichtige generische Schnittstellen Comparable Vergleich von zwei Objekten Iterator Durchlauf durch eine Datenstruktur unabhängig von der konkreten Implementierung Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 610 Interface List Das Interface ist eine zentrale Schnittstelle in java.util. Das Interface hat noch weitere Ober-Interfaces, wie z. B. Iterable. Dieses Interface werden wir gleich betrachten. Das Interface List wird von vielen Klassen implementiert, wie z. B. ArrayList LinkedList SortedList Wichtige Methoden im Interface List boolean add(E e) E get(int index) List subList(int fromIndex, int toIndex) Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 611 Tip zum Umgang mit Interfaces Insbesondere bei Datenstrukturen: Benutzen Sie als Typ von Variablen/Parametern nach Möglichkeit Interfaces. Diese haben meist verschiedene Implementierungen mit unterschiedlichen “nicht-funktionalen" Eigenschaftfen Algorithmen sollten meist unabhängige von “nicht- funktionalen" Eigenschaftfen sein. Zum Beispiel: public void sort(List l) { public void sort(ArrayList l) { … … } } List hat viele verschiedene Implementierungen, z.B.: ArrayList – schnell bei Zugriff über Index LinkedList – schnell beim Anfügen an den Anfang Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 612 Interface Comparable Für geordnete Daten verwendet man das Interface Comparable, das folgende Methode für Objekte o vom Typ T vorschreibt. int compareTo(T o); Das Ergebnis von compareTo ist vom Typ int. Es gilt folgende Konvention: Wenn a.compareTo(b) negativ ist, interpretiert man dies als a < b. Wenn a.compareTo(b) 0 ist, interpretiert man dies als a == b. Wenn a.compareTo(b) positiv ist, interpretiert man dies als a > b. Beispiel class Point2D implements Comparable {... public int compareTo(Point2D o) { int xc = Double.compare(getX(), o.getX()); if (xc < 0) return -1; else return (xc == 0)? Double.compare(y,o.y) : 1; } Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge } Objektorientierte Programmierung 613 Interface Iterator Ein Behälter ist ein generischer Datentyp zur Verwaltung von Mengen beliebiger Objekte. Listen sind nur ein Beispiel für einen Behälter. Ein Iterator liefert die Elemente eines Behälters (oder eines Teils) in einer spezifischen Reihenfolge („Aufzählung der gewünschten Elemente“). Die Methode hasNext() liefert true, wenn bei der aktuellen Aufzählung der Elemente des Behälters noch weitere Elemente anstehen. Die Methode next() produziert das nächste Element der Aufzählung. Die Methode remove() entfernt das Element aus dem Behälter, das zuletzt mit next abgeliefert wurde. Diese Methode ist optional – d.h. kann auch weggelassen werden und führt dann ggf. zu einer Ausnahme. public interface Iterator { public boolean hasNext(); public E next(); public void remove(); } Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 614 Beispiel: Ein Iterator für Listen import java.util.Iterator; Default-Methode im Interface Iterator public class MyListIterator implements Iterator { implementiert und wirft dort eine private ListElement cursor; UnsupportedOperationException. protected MyListIterator(ListElement head) { this.cursor = head; } public boolean hasNext() { return cursor != null; } public E next() { E result = cursor.data; cursor = cursor.next; return result; } } Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 615 Interface Iterable Analog zu einem Array kann auch eine Liste mit der for-each-Schleife durchlaufen werden. Voraussetzung hierfür ist, dass die Liste noch die generische Schnittstelle Iterable implementiert. public interface Iterable { public Iterator iterator(); } Die Schnittstelle List erweitert die Schnittstelle Iterable public interface List extends Iterable{... } und die Klasse LinkedList implementiert die Methode. public class LinkedList implements List{... public Iterator iterator() { return new MyListIterator(head); } } Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 616 Anwendung der for-each Schleife Da unsere Klasse LinkedList die Schnittstelle Iterable implementiert, kann der Durchlauf durch die Listen mit einer for-each-Schleife erfolgen. public static void main(String[] args) { List list = new LinkedList(); list.add(new Point2D (.2,.3)); list.add(new Point2D (.3,.4)); list.add(new Point2D (.4,.5)); list.add(new Point2D (.5,.6)); // Ausgabe aller Punkte mit der for-each Schleife for (Point2D p: list) System.out.println("Punkt: " + p); } Die for-each-Schleife kann für alle Klassen, die Iterable implementieren, genauso wie bei Arrays benutzt werden. Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 617 12.5 Java Generics im Detail Bisher haben wir am Beispiel von Listen die wichtigsten Konzepte generischer Klassen erklärt. In diesem Abschnitt sollen weitere Details von Java Generics behandelt werden. Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 618 Syntax Java Generics unterstützt die Parametrisierung mit Typen bei Klassen Schnittstellen Methoden Anzahl der Parameter beliebig, aber typischerweise ist die Anzahl kleiner 3. Syntax Angabe der Parameterliste in eckigen Klammerpaar „< … >“ Bei Klassen und Schnittstellen nach dem entsprechenden Namen. Parameter werden durch Kommata getrennt. Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 619 Beschränkungen Keine primitive Typen als Argument für einen Typparameter. Keine Aufrufe von Konstruktoren des Typparameters T T x = new T(); funktioniert nicht! Kein Aufruf von statischen Methoden des Typparameters T double avg = T.myStaticMethod(); funktioniert nicht! Keine Verwendung des Typparameters T in der Definition von statischen Methoden oder statischen Felddeklarationen Keine Allokation eines Arrays von Typparameter T T[ ] arr = new T; funktioniert nicht! Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 620 Beschränkungen Keine primitive Typen als Argument für einen Typparameter. Keine Aufrufe von List li;Konstruktoren des Typparameters T T x = new T(); funktioniert nicht! //das Folgende funktioniert aber: Kein Aufruf von statischen Methoden des Typparameters T List =...; double avg = T.myStaticMethod(); li.add(1); funktioniert nicht! // dabei wird der int 1 in ein // automatisch Keine Verwendung desinTypparameters ein Integer-Objekt T in der Definition von statischen // umgewandelt Methoden. oder statischen Felddeklarationen Keine Allokation eines Arrays von Typparameter T T[ ] arr = new T; funktioniert nicht! Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 621 Generische Methoden Objektmethoden dürfen Typparameter der Klasse verwenden Außerdem erlaubt Java, sowohl statischen Methoden als auch Objektmethoden eigene Typparameter zu deklarieren. Die Liste der generischen Typen wird vor dem Rückgabetyp der Methode angegeben. Beispiel // class Main public static void swap(T[] arr) { T tmp = arr; arr = arr[arr.length-1]; arr[arr.length-1] = tmp; } Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 622 Automatische Typ-Bestimmung Oft kann der Java-Compiler den Typ für Typparameter selbst bestimmen Bei Erzeugung einer Instanz: //explizite Typangabe: List li = new LinkedList(); //Automatische Typbestimmung List li = new LinkedList(); Beim Aufruf einer Methode: (gegeben: Integer[] arr = null;) //explizite Typangabe: Main.swap(arr); //Automatische Typbestimmung Main.swap(arr); Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 623 Einschränkung des Typparameters Bei den bisherigen generischen Typen erlauben wir beliebige Typen bei der Instanziierung. public static void main(String[] args) { // Liste mit Punkten List listp = new LinkedList(); // Liste mit Konten List listk = new LinkedList(); // Liste mit Integern List listi = new LinkedList(); // Liste mit Objekten List listo = new LinkedList(); } Dies ist nicht immer erwünscht, da in bestimmten Fällen von Typen gewisse Eigenschaften gefordert werden. Z. B. sollte eine sortierte Liste nur mit Typen instanziiert werden, die die Schnittstelle Comparable unterstützen. Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 624 extends-Klausel Bei einer generischen Klasse kann diese Eigenschaft für einen Typparameter durch Angabe des Schlüsselworts extends und einer Klasse oder Schnittstelle gefordert werden. Beispiel Es soll eine generische Klasse erstellt werden, um beliebige Zahlen zu addieren. Anmerkung: Die Klasse Number aus der Java API ist die Oberklasse von all diesen Klassen wie z. B. der Klasse Integer oder Double Lösung class Accumulator { … // Über T kann jetzt auf die Methoden der Klasse // Number zugriffen werden. } Accumulator ai = new Accumulator(); // funktioniert Accumulator ai = new Accumulator(); // funktioniert nicht. Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 625 extends-Klausel mit Schnittstellen Um eine Ordnung in der Liste sicherzustellen, sollte der generische Typ die Schnittstelle Comparable unterstützen. Zusätzlich müssten wir in unserer Listenimplementierung die Methode boolean add(T elem) noch so ändern, dass die Objekte entsprechend der Ordnung in der Liste liegen. Die Einschränkung, dass eine Typparameter von einer Schnittstelle erben muss, wird ebenfalls über die extends-Klausel angegeben. Beispiel Sortierte Liste Elemente müssen die generische Schnittstelle Comparable implementieren Der Typparameter T von SortedList darf als Typargument für die Schnittstelle/Klasse verwendet werden, die T implementieren/erweitern soll. class SortedList {... } Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 626 12.6 Wildcards – Motivation (1) Bei den bisherigen Möglichkeiten in Generics gibt es noch ein paar Probleme. Die Klasse Object ist Oberklasse von Point2D. Jedoch ist LinkedList keine Oberklasse von LinkedList ! Object List Point2D List Damit ist dieser Programmschnipsel nicht korrekt. List points = new LinkedList();// funktioniert List objects = new LinkedList();// nicht erlaubt Es gibt also keine Polymorphie zwischen den beiden Listen-Klassen. Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 627 Warum ist es nicht erlaubt? Betrachten wir folgende Situation Eine Methode zum Einfügen eines neuen Konto-Objekts in eine Liste vom Typ LinkedList. void addSomethingToList (LinkedList llo) { // Wir fügen jetzt etwas zu llo hinzu, wie z. B. ein Konto: llo.add(new Konto()); } Aufruf der Methode mit einem Parameter vom Typ LinkedList Das sollte aber verhindert werden, da Konto keine Unterklasse von Point2D ist. public static void main(String[] args) { // Liste mit Punkten Wird von Java LinkedList points = new LinkedList(); verboten. points.add(new Point2D(0.2,0.3)); Sonst würde diese addSomethingToList(points); Zuweisung Point2D point = points.get(points.size() – 1); fehlschlagen, weil } das letzte Element nun ein Konto ist. Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 628 Warum sollte es erlaubt sein? Es soll eine Methode bereitgestellt werden, um eine beliebige Liste auszugeben. void printList (LinkedList lif) { for (Object e: lif) System.out.println(e); } Der Aufruf der Methode printList für die Liste points ist leider nicht erlaubt! public static void main(String[] args) { // Liste mit Punkten Wird von Java verboten, LinkedList points = new LinkedList(); obwohl die printList- points.add(new Point2D(.2,.3)); Methode die points List printList(points); gar nicht verändert. } In diesem Fall wäre das Verbot nicht notwendig. Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 629 Wildcard-Typ Durch Verwendung eines Wildcard-Typs wird dieses Problem behoben. void printList (LinkedList lif) { for (Object e: lif) System.out.println(e); } Der Aufruf der Methode für die Liste points funktioniert jetzt! public static void main(String[] args) { // Liste mit Punkten LinkedList points = new LinkedList(); points.add(new Point2D(.2,.3)); printlist(points); // alles in Ordnung! } Einschränkungen, bei Verwendung des Wildcard-Typs als Typargument In der Methode printList dürfen wir nicht die Methode add aufrufen, da diese Methode den Typparameter in der Parameterliste verwendet (boolean add(T t) {…}) Grund hierfür ist, dass der Typparameter der generischen LinkedList unbekannt ist. Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 630 Beziehung zwischen Klassen Durch LinkedList wird ein Obertyp für alle LinkedList-Klassen zur Verfügung gestellt. Object LinkedList Point2D LinkedList Jedoch gelten folgende zwei Einschränkungen: 1. Liefern Methoden den Typparameter der LinkedList als Ergebnis, können wir nur davon ausgehen, dass das Ergebnis zur Klasse Object gehört. 2. Es darf kein Aufruf einer Methode von LinkedList erfolgen, in der die Parameterliste den Typparameter verwendet. Die erste kann durch nach oben beschränkte Wildcards gelockert werden. Die zweite durch nach unten beschränkte Wildcards aufgehoben werden. Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 631 Motivation für oben beschränkte Wildcards Betrachten wir folgende Klassenhierarchie GeoWithExtent Rectangle Circle Die Schnittstelle GeoWithExtent besitzt eine Methode area() zur Flächenberechnung. Die Klassen Circle und Rectangle sind zwei Klassen, die die Schnittstelle implementieren. Wir betrachten im Folgenden drei verschiedene Listen. List geos = new LinkedList(); List rects = new LinkedList(); List circles = new LinkedList(); Können wir eine generische Methode bereitstellen, um für alle drei Listen die Summe der Flächeninhalte der Objekte zu berechnen? Prof. Christoph Bockisch ([email protected]) | Programmiersprachen und –werkzeuge Objektorientierte Programmierung 632 Obere Schranke für Wildcards Benutzen wir den normalen Wildcard LinkedList steht uns die Methode double area() nicht zur Verfügung. Deshalb gibt es nach oben beschränkte Wildcards, bei der wir nach ? das Schlüsselwort extends und ein Typ als obere Schranke hinzufügen können. In unserem Beispiel: static double areaOverAll(LinkedList