Algorithmen und Datenstrukturen Wintersemester 2013/14 23. Vorlesung Interfaces und Generics Krzysztof Fleszar Lehrstuhl für Informatik I 1 Übersicht InsertionSort • für Punkte Einschub: Liste für Objekte beliebiger Klassen • für Objekte beliebiger Klassen Einschub: Liste für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann • für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann 2 Übersicht InsertionSort • für Punkte (Wiederholung vom 19.12.2013) Einschub: Liste für Objekte beliebiger Klassen • für Objekte beliebiger Klassen Einschub: Liste für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann • für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann 3 InsertionSort für Punkte Ein Punkt in der Ebene: UML-Diagramm: public class Punkt { public double x; public double y; } Punkt +x:double +y:double Voraussetzung fürs Sortieren: Definition einer Ordnung y pi < pj genau dann, wenn p3 pi.x < pj.x oder p1 p2 1 0 ( pi.x = pj.x und pi.y < pj.y) p4 = lexikographische Ordnung 0 1 x 4 InsertionSort für Punkte Ein Punkt in der Ebene: UML-Diagramm: public class Punkt { Punkt public double x; +x:double public double y; +y:double public Punkt(double myX, double myY) { +Punkt(double, double) x = myX; +compareTo(Punkt):int y = myY; } /* gibt Wert < 0 fuer (this < p), Wert > 0 fuer (this > p) und 0 fuer (this = p) zurueck */ public int compareTo(Punkt p) { if (this.x < p.x) return -1; if (this.x == p.x) { if (this.y < p.y) return -1; if (this.y == p.y) return 0; } return 1; } 5 } InsertionSort für Punkte public class Sortierverfahren { public static void insertionSort(int[] a) { for (int j = 1; j < a.length; j++) { int key = a[j]; int i = j - 1; while (i >= 0 && a[i] > key) { a[i + 1] = a[i]; i--; } a[i + 1] = key; } } } 6 InsertionSort für Punkte public class Sortierverfahren { public static void insertionSort(Punkt[] a) { for (int j = 1; j < a.length; j++) { Punkt key = a[j]; int i = j - 1; while (i >= 0 && a[i].compareTo(key) > 0) { a[i + 1] = a[i]; i--; } a[i + 1] = key; } } } 7 InsertionSort für Punkte public class Sortierverfahren { public static void main(String[] args) { Punkt[] a = new Punkt[4]; a[0] = new Punkt(1, 2); a[1] = new Punkt(1, 1); a[2] = new Punkt(3, 1); a[3] = new Punkt(4, 3); insertionSort(a); for (int i = 0; i < a.length; i++) System.out.println(a[i].x + " " + a[i].y); } public static void insertionSort(Punkt[] a) { //... } } 8 InsertionSort für Punkte Problem: eigene Sortiermethode für jede Klasse public static void insertionSort(Punkt[] a) { //... } 9 Übersicht InsertionSort Einschub • für Punkte (Wiederholung vom 19.12.2013) Einschub: Liste für Objekte beliebiger Klassen • für Objekte beliebiger Klassen • für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann 10 Liste für Punkte x head nil y prev key next nil public class PunktListenElement { public Punkt key; public PunktListenElement prev; public PunktListenElement next; public PunktListenElement(Punkt k, PunktListenElement p) { key = k; next = p; prev = null; } 11 } Liste für Punkte public class PunktListe { public PunktListenElement head; public PunktListenElement insert(Punkt k) { PunktListenElement x = new PunktListenElement(k, head); if (head != null) { head.prev = x; } head = x; return x; } } public class PunktListenElement { public Punkt key; public PunktListenElement prev; public PunktListenElement next; public PunktListenElement(Punkt k, PunktListenElement p) { key = k; next = p; prev = null; } 12 } Liste für Punkte public class PunktListenTest { public static void main(String[] args) { PunktListe l = new PunktListe(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); for (PunktListenElement p = l.head; p != null; p = p.next) { System.out.println(p.key.x + " " + p.key.y); } } } Problem: eigene Liste für jede Klasse notwendig Lösung: erstelle Liste für Objekte der Klasse java.lang.Object 13 Liste für Objekte java.lang.Object Punkt • Jede Java-Klasse ist Unterklasse der Klasse java.lang.Object • Eine Liste, die Objekte vom Typ java.lang.Object aufnehmen kann, kann also jedes Objekt aufnehmen. 14 Liste für Objekte public class PunktListe { public PunktListenElement head; public PunktListenElement insert(Punkt k) { PunktListenElement x = new PunktListenElement(k, head); if (head != null) { head.prev = x; } head = x; return x; } } public class PunktListenElement { public Punkt key; public PunktListenElement prev; public PunktListenElement next; public PunktListenElement(Punkt k, PunktListenElement p) { key = k; next = p; prev = null; } 15 } Liste für Objekte public class Liste { public ListenElement head; public ListenElement insert(Object k) { ListenElement x = new ListenElement(k, head); if (head != null) { head.prev = x; } head = x; return x; } } public class ListenElement { public Object key; public ListenElement prev; public ListenElement next; public ListenElement(Object k, ListenElement p) { key = k; next = p; prev = null; } } 16 Liste für Objekte public class ListenTest { public static void main(String[] args) { Liste l = new Liste(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); for (ListenElement p = l.head; p != null; p = p.next) { System.out.println(p.key.x + " " + p.key.y); } } Compiler: "p.key.x cannot be resolved or is not a field" } 17 Liste für Objekte public class ListenTest { public static void main(String[] args) { Liste l = new Liste(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); for (ListenElement p = l.head; p != null; p = p.next) { Punkt myPunkt = (Punkt) p.key; //explizite Typkonvertierung System.out.println(myPunkt.x + " " + myPunkt.y); } } } Ausgabe: 1.0 0.0 2.0 2.0 0.0 1.0 18 Liste für Objekte public class ListenTest { public static void main(String[] args) { Liste l = new Liste(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); l.insert(new Double(3.2)); l.insert(new Integer(4)); Wir können nun auch Objekte anderer Klassen in die Liste einfügen } } 19 Liste für Objekte public class ListenTest { public static void main(String[] args) { Liste l = new Liste(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); l.insert(new Double(3.2)); l.insert(new Integer(4)); for (ListenElement p = l.head; p != null; p = p.next) { Punkt myPunkt = (Punkt) p.key; //explizite Typkonvertierung System.out.println(myPunkt.x + " " + myPunkt.y); } Ausgabe: Exception in thread "main" } } java.lang.ClassCastException: java.lang.Integer cannot be cast to Punkt at ListenTest.main(ListenTest.java:12) 20 Liste für Objekte public class ListenTest { public static void main(String[] args) { Liste l = new Liste(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); l.insert(new Double(3.2)); l.insert(new Integer(4)); for (ListenElement p = l.head; p != null; p = p.next) { if (p.key instanceof Punkt) { Punkt myPunkt = (Punkt) p.key; System.out.println(myPunkt.x + " " + myPunkt.y); } } } } instanceof überprüft, ob Objekt zu Klasse gehört 21 Liste für Objekte public class ListenTest { public static void main(String[] args) { Liste l = new Liste(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); l.insert(new Double(3.2)); l.insert(new Integer(4)); for (ListenElement p = l.head; p != null; p = p.next) { if (p.key instanceof Punkt) { Punkt myPunkt = (Punkt) p.key; System.out.println(myPunkt.x + " " + myPunkt.y); } } } } Ausgabe: 1.0 0.0 2.0 2.0 ...es werden nur die 0.0 1.0 Punkte ausgegeben 22 Liste für Objekte public class ListenTest { public static void main(String[] args) { Liste l = new Liste(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); l.insert(new Double(3.2)); l.insert(new Integer(4)); for (ListenElement p = l.head; p != null; p = p.next) { //gib Ergebnis von p.key.toString() aus: System.out.println(p.key); } } } Ausgabe: 4 3.2 Punkt@c3c749 Punkt@150bd4d Punkt@1bc4459 23 Liste für Objekte java.lang.Object +toString():String java.lang.Double java.lang.Integer +toString():String +toString():String Punkt for (ListenElement p = l.head; p != null; p = p.next) { //gib Ergebnis von p.key.toString() aus: System.out.println(p.key); } Ausgabe: 4 3.2 Punkt@c3c749 Punkt@150bd4d Punkt@1bc4459 toString (Klasse Integer) toString (Klasse Double) toString (Klasse Object) 24 Liste für Objekte java.lang.Object +toString():String java.lang.Double java.lang.Integer Punkt +toString():String +toString():String +toString():String public class Punkt { public double x; public double y; public String toString() { return "(" + x + ", " + y + ")"; } //... } Methode toString der Klasse Object wird überschrieben 25 Liste für Objekte public class ListenTest { public static void main(String[] args) { Liste l = new Liste(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); l.insert(new Double(3.2)); l.insert(new Integer(4)); for (ListenElement p = l.head; p != null; p = p.next) { //gib Ergebnis von p.key.toString() aus: System.out.println(p.key); } java.lang.Object } } Ausgabe: 4 3.2 (1.0, 0.0) (2.0, 2.0) (0.0, 1.0) +toString():String Punkt 26 +toString():String Übersicht InsertionSort • für Punkte Einschub: Liste für Objekte beliebiger Klassen • für Objekte beliebiger Klassen • für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann 27 InsertionSort für Objekte public class Sortierverfahren { public static void insertionSort(Punkt[] a) { for (int j = 1; j < a.length; j++) { Punkt key = a[j]; int i = j - 1; while (i >= 0 && a[i].compareTo(key) > 0) { a[i + 1] = a[i]; i--; } a[i + 1] = key; } } } 28 InsertionSort für Objekte public class Sortierverfahren { public static void insertionSort(Object[] a) { for (int j = 1; j < a.length; j++) { Object key = a[j]; int i = j - 1; while (i >= 0 && a[i].compareTo(key) > 0) { a[i + 1] = a[i]; i--; Compiler: "The method } a[i + 1] = key; compareTo(Object) is undefined for } the type Object" } } 29 InsertionSort für Objekte public class Sortierverfahren { public static void insertionSort(Comparable[] a) { for (int j = 1; j < a.length; j++) { Comparable key = a[j]; int i = j - 1; while (i >= 0 && a[i].compareTo(key) > 0) { a[i + 1] = a[i]; i--; } a[i + 1] = key; To Do: } Definiere Klasse Comparable, } so dass sichergestellt ist, dass } Objekte von Unterklassen vergleichbar sind 30 InsertionSort für Objekte public abstract class Comparable { public abstract int compareTo(Object o); } Es fällt uns schwer, eine allgemeine Definition zu finden. Wir sollten daher verbieten, Instanzen unserer Klasse Comparable zu erzeugen. Deshalb: abstract 31 InsertionSort für Objekte public abstract class Comparable { public abstract int compareTo(Object o); } Die Klasse unserer Vergleichsobjekte hat evtl. bereits eine Oberklasse. Comparable Tier Elefant Mehrfachvererbung ist verboten! 32 InsertionSort für Objekte public interface Comparable { public int compareTo(Object o); } Die Klasse unserer Vergleichsobjekte hat evtl. bereits eine Oberklasse. Deshalb: interface <<Interface>> Comparable Tier Elefant 33 InsertionSort für Objekte Interfaces ähneln abstrakten Klassen, die ausschließlich abstrakte Methoden besitzen (keine Attribute und keine implementierten Methoden). Unterschied: Eine Klasse kann mehrere Interfaces implementieren, aber nur eine Klasse (direkt) erweitern. <<Interface>> Comparable Tier Elefant 34 InsertionSort für Objekte public interface Comparable { public int compareTo(Object o); } Interface Comparable war bis Java-Version 1.4 so im Paket java.lang definiert. 35 InsertionSort für Objekte public class Punkt { public double x; public double y; public Punkt(double myX, double myY) { x = myX; y = myY; } /* gibt Wert < 0 fuer (this < p), Wert > 0 fuer (this > p) und 0 fuer (this = p) zurueck */ public int compareTo(Punkt p) { if (this.x < p.x) return -1; if (this.x == p.x) { if (this.y < p.y) return -1; if (this.y == p.y) return 0; } return 1; } } 36 InsertionSort für Objekte public class Punkt implements Comparable { public double x; public double y; Compiler: "The type Punkt must public Punkt(double myX, double myY) { implement the inherited abstract x = myX; method Comparable.compareTo(Object)" y = myY; } /* gibt Wert < 0 fuer (this < p), Wert > 0 fuer (this > p) und 0 fuer (this = p) zurueck */ public int compareTo(Punkt p) { if (this.x < p.x) return -1; if (this.x == p.x) { if (this.y < p.y) return -1; if (this.y == p.y) return 0; } return 1; } } 37 InsertionSort für Objekte public class Punkt implements Comparable { public double x; public double y; public Punkt(double myX, double myY) { x = myX; y = myY; } /* gibt Wert < 0 fuer (this < p), Wert > 0 fuer (this > p) und 0 fuer (this = p) zurueck */ public int compareTo(Object o) { Punkt p = (Punkt) o; if (this.x < p.x) return -1; if (this.x == p.x) { if (this.y < p.y) return -1; if (this.y == p.y) return 0; } return 1; } } 38 InsertionSort für Objekte public class Sortierverfahren { public static void main(String[] args) { Punkt[] a = new Punkt[4]; Hier wird Feld mit a[0] = new Punkt(1, 2); Punkt-Objekten übergeben a[1] = new Punkt(1, 1); a[2] = new Punkt(3, 1); Hier wird Feld mit a[3] = new Punkt(4, 3); Comparable-Objekten insertionSort(a); entgegengenommen for (int i = 0; i < a.length; i++) System.out.println(a[i].x + " " + a[i].y); } public static void insertionSort(Comparable[] a) { //... } } 39 InsertionSort für Objekte public class Sortierverfahren { public static void main(String[] args) { Punkt[] a = new Punkt[4]; a[0] = new Punkt(1, 2); a[1] = new Punkt(1, 1); a[2] = new Punkt(3, 1); a[3] = new Punkt(4, 3); insertionSort(a); Ausgabe: 1.0 1.0 for (int i = 0; i < a.length; i++) 2.0 System.out.println(a[i].x + 1.0 " " + a[i].y); } 3.0 1.0 public static void insertionSort(Comparable[] a) { //... 4.0 3.0 } } 40 InsertionSort für Objekte GeoFigur +m:Punkt +GeoFigur(Punkt) +getFlaeche():double +compareTo(GeoFigur):int Quadrat Kreis -a:double -r:double +Quadrat(Punkt, double) +getFlaeche():double +setA(double) +getA():double +Kreis(Punkt, double) +getFlaeche():double +setR(double) 41 +getR():double InsertionSort für Objekte <<Interface>> Comparable +compareTo(Object):int GeoFigur +m:Punkt +GeoFigur(Punkt) +getFlaeche():double +compareTo(Object):int Quadrat Kreis -a:double -r:double +Quadrat(Punkt, double) +getFlaeche():double +setA(double) +getA():double +Kreis(Punkt, double) +getFlaeche():double +setR(double) 42 +getR():double InsertionSort für Objekte Klasse GeoFigur in Java: public abstract class GeoFigur { public Punkt m; public GeoFigur(Punkt myM) { m = myM; } public abstract double getFlaeche(); public int compareTo(GeoFigur key) { if (this.getFlaeche() > key.getFlaeche()) return 1; if (this.getFlaeche() < key.getFlaeche()) return -1; return 0; } } 43 InsertionSort für Objekte Klasse GeoFigur in Java: public abstract class GeoFigur implements Comparable { public Punkt m; public GeoFigur(Punkt myM) { m = myM; } public abstract double getFlaeche(); public int compareTo(Object o) { GeoFigur key = (GeoFigur) o; if (this.getFlaeche() > key.getFlaeche()) return 1; if (this.getFlaeche() < key.getFlaeche()) return -1; return 0; } } 44 InsertionSort für Objekte Sortieren: public class Sortierverfahren { public static void main(String[] args) { GeoFigur[] a = new GeoFigur[4]; a[0] = new Quadrat(new Punkt(0.0, 0.0), 2.0); a[1] = new Quadrat(new Punkt(1.0, 2.0), 4.0); a[2] = new Kreis(new Punkt(2.0, 0.0), 2.0); a[3] = new Kreis(new Punkt(0.0, 1.0), 4.0); insertionSort(a); for (int i = 0; i < a.length; i++) System.out.println(a[i].getClass().toString() + " " + a[i].getFlaeche()); } public static void insertionSort(Comparable[] a) { //... } } 45 InsertionSort für Objekte Sortieren: public class Sortierverfahren { public static void main(String[] args) { GeoFigur[] a = new GeoFigur[4]; a[0] = new Quadrat(new Punkt(0.0, 0.0), 2.0); a[1] = new Quadrat(new Punkt(1.0, 2.0), 4.0); a[2] = new Kreis(new Punkt(2.0, 0.0), 2.0); a[3] = new Kreis(new Punkt(0.0, 1.0), 4.0); insertionSort(a); Ausgabe: for (int i = 0; i < a.length; i++) System.out.println(a[i].getClass().toString() + " " + a[i].getFlaeche()); class Quadrat 4.0 class Kreis 12.566370614359172 } public static void insertionSort(Comparable[] a) { class //... Quadrat 16.0 } class Kreis 50.26548245743669 } 46 InsertionSort für Objekte Sortieren: public class Sortierverfahren { public static void main(String[] args) { Compiler: Type mismatch: cannot convert from Punkt to GeoFigur GeoFigur[] a = new GeoFigur[4]; a[0] = new Punkt(0.0, 0.0); a[1] = new Quadrat(new Punkt(1.0, 2.0), 4.0); a[2] = new Kreis(new Punkt(2.0, 0.0), 2.0); a[3] = new Kreis(new Punkt(0.0, 1.0), 4.0); insertionSort(a); for (int i = 0; i < a.length; i++) System.out.println(a[i].getClass().toString() + " " + a[i].getFlaeche()); } public static void insertionSort(Comparable[] a) { //... } } 47 InsertionSort für Objekte Sortieren: public class Sortierverfahren { public static void main(String[] args) { Comparable[] a = new Comparable[4]; a[0] = new Punkt(0.0, 0.0); a[1] = new Quadrat(new Punkt(1.0, 2.0), 4.0); a[2] = new Kreis(new Punkt(2.0, 0.0), 2.0); a[3] = new Kreis(new Punkt(0.0, 1.0), 4.0); insertionSort(a); for (int i = 0; i < a.length; i++) System.out.println(a[i]); } public static void insertionSort(Comparable[] a) { //... } } 48 InsertionSort für Objekte Sortieren: public class Sortierverfahren { public static void main(String[] args) { Comparable[] a = new Comparable[4]; a[0] = new Punkt(0.0, 0.0); a[1] = new Quadrat(new Punkt(1.0, 2.0), 4.0); a[2] = new Kreis(new Punkt(2.0, 0.0), 2.0); a[3] = new Kreis(new Punkt(0.0, 1.0), 4.0); insertionSort(a); Ausgabe: for (int i = 0; i < a.length; i++) System.out.println(a[i]); Exception in thread "main" java.lang.ClassCastException: } Quadrat cannot be cast to Punkt public static void insertionSort(Comparable[] a) { at Punkt.compareTo(Punkt.java:12) //... at Sortierverfahren.insertionSort(Sortierverfahren.java:21) } at } Sortierverfahren.main(Sortierverfahren.java:9) 49 InsertionSort für Objekte public class Punkt implements Comparable { public double x; public double y; public Punkt(double myX, double myY) { x = myX; y = myY; } /* gibt Wert < 0 fuer (this < p), Wert > 0 fuer (this > p) und 0 fuer (this = p) zurueck */ public int compareTo(Object o) { Punkt p = (Punkt) o; if (this.x < p.x) return -1; Ausgabe: if (this.x == p.x) { if (this.y < p.y) return -1; if (this.y == p.y) return 0; Exception in thread "main" java.lang.ClassCastException: } Quadrat cannot be cast to Punkt return 1; at Punkt.compareTo(Punkt.java:12) at} Sortierverfahren.insertionSort(Sortierverfahren.java:21) }at Sortierverfahren.main(Sortierverfahren.java:9) 50 InsertionSort für Objekte public class Punkt implements Comparable { public double x; public double y; public Punkt(double myX, double myY) { x = myX; y = myY; } public int compareTo(Object o) { if (o instanceof Punkt) { Punkt p = (Punkt) o; if (this.x < p.x) return -1; if (this.x == p.x) { if (this.y < p.y) return -1; if (this.y == p.y) return 0; } return 1; } else { //? } } } 51 InsertionSort für Objekte public class Punkt implements Comparable { public double x; public double y; public Punkt(double myX, double myY) { x = myX; y = myY; } public int compareTo(Object o) { if (o instanceof Punkt) { Punkt p = (Punkt) o; if (this.x < p.x) return -1; if (this.x == p.x) { if (this.y < p.y) return -1; if (this.y == p.y) return 0; } return 1; } else { //? } } } Es wäre schön, wenn wir wüssten, mit was für Objekten wir zu rechnen haben. 52 Übersicht InsertionSort Einschub • für Punkte (Wiederholung vom 19.12.2013) • für Objekte beliebiger Klassen Einschub: Liste für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann • für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann 53 Liste für Objekte public class ListenTest { public static void main(String[] args) { Liste l = new Liste(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); l.insert(new Double(3.2)); l.insert(new Integer(4)); Wir möchten es verbieten! for (ListenElement p = l.head; p != null; p = p.next) { //gib Ergebnis von p.key.toString() aus: System.out.println(p.key); } } } Wie kann man der Liste „sagen“, dass nur Objekte einer bestimmten Klasse erlaubt sind? 54 Liste für Objekte public class Liste { public ListenElement head; public ListenElement insert(Object k) { ListenElement x = new ListenElement(k, head); if (head != null) { head.prev = x; } head = x; return x; } } public class ListenElement { public Object key; public ListenElement prev; public ListenElement next; public ListenElement(Object k, ListenElement p) { key = k; next = p; prev = null; } } 55 Liste für Objekte Seit Java Version 5 können generische Datentypen definiert werden. Platzhalter für den Namen einer Klasse public class ListItem<T> { public Object key; public ListenElement prev; public ListenElement next; public ListenElement(Object k, ListenElement p) { key = k; next = p; prev = null; } } 56 Liste für Objekte ListItem<T> kann nur Objekte vom Typ T speichern. public class ListItem<T> { public T key; public ListItem<T> prev; public ListItem<T> next; public ListItem (T k, ListItem<T> p) { key = k; next = p; prev = null; } } 57 Liste für Objekte public class List<T> { public ListItem<T> head; public ListItem<T> insert(T k) { ListItem<T> x = new ListItem<T>(k, head); if (head != null) { head.prev = x; } head = x; return x; } } public class ListItem<T> { public T key; public ListItem<T> prev; public ListItem<T> next; public ListItem (T k, ListItem<T> p) { key = k; next = p; prev = null; } } List<T> erlaubt nur Objekte vom Typ T! 58 Liste für Objekte public class ListenTest { public static void main(String[] args) { List<Punkt> l = new List<Punkt>(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); public class List<T> { … } Platzhalter wird durch Klassennamen ersetzt for (ListItem<Punkt> p = l.head; p != null; p = p.next) { System.out.println(p.key.x + " " + p.key.y); } } } 59 Liste für Objekte public class ListenTest { public static void main(String[] args) { List<Punkt> l = new List<Punkt>(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); for (ListItem<Punkt> p = l.head; p != null; p = p.next) { System.out.println(p.key.x + " " + p.key.y); } } } Ausgabe: 1.0 0.0 2.0 2.0 0.0 1.0 60 Liste für Objekte public class ListenTest { public static void main(String[] args) { List<Punkt> l = new List<Punkt>(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); l.insert(new Double(2.0)); for (ListItem<Punkt> p = l.head; p != null; p = p.next) { System.out.println(p.key.x + " " + p.key.y); } } } Compiler: "The method insert(Punkt) in the type List<Punkt> is not applicable for the arguments (Double)" 61 Liste für Objekte public class ListenTest { public static void main(String[] args) { List<Object> l = new List<Object>(); l.insert(new Punkt(0.0, 1.0)); l.insert(new Punkt(2.0, 2.0)); l.insert(new Punkt(1.0, 0.0)); l.insert(new Double(2.0)); for (ListItem<Object> p = l.head; p != null; p = p.next) { System.out.println(p.key); } } } Ausgabe: 2.0 (1.0, 0.0) (2.0, 2.0) (0.0, 1.0) 62 Übersicht InsertionSort • für Punkte • für Objekte beliebiger Klassen Einschub: Liste für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann • für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann 63 InsertionSort für Objekte public class Punkt implements Comparable { public double x; public double y; public Punkt(double myX, double myY) { x = myX; y = myY; } public int compareTo(Object o) { if (o instanceof Punkt) { Punkt p = (Punkt) o; if (this.x < p.x) return -1; if (this.x == p.x) { if (this.y < p.y) return -1; if (this.y == p.y) return 0; } return 1; } else { //? } } } Es wäre schön, wenn wir wüssten, mit was für Objekten wir zu rechnen haben. 64 InsertionSort für Objekte public interface Comparable<T> { public int compareTo(T o); } 65 InsertionSort für Objekte public interface Comparable<T> { public int compareTo(T o); } public class Punkt implements Comparable { //... public int compareTo(Object o) { Punkt p = (Punkt) o; if (this.x < p.x) return -1; if (this.x == p.x) { if (this.y < p.y) return -1; if (this.y == p.y) return 0; } return 1; } } 66 InsertionSort für Objekte public interface Comparable<T> { public int compareTo(T o); } public class Punkt implements Comparable<Punkt> { //... public int compareTo(Punkt p) { } } if (this.x < p.x) return -1; if (this.x == p.x) { if (this.y < p.y) return -1; if (this.y == p.y) return 0; } return 1; Punkte können nur mit Punkten verglichen werden! 67 InsertionSort für Objekte public class Sortierverfahren { public static void main(String[] args) { Punkt[] a = new Punkt[4]; a[0] = new Punkt(1, 2); a[1] = new Punkt(1, 1); a[2] = new Punkt(3, 1); a[3] = new Punkt(4, 3); insertionSort(a); for (int i = 0; i < a.length; i++) System.out.println(a[i].x + " " + a[i].y); } public static void insertionSort(Comparable[] a) { //... } } 68 InsertionSort für Objekte public class Sortierverfahren { public static void main(String[] args) { Punkt[] a = new Punkt[4]; a[0] = new Punkt(1, 2); a[1] = new Punkt(1, 1); a[2] = new Punkt(3, 1); a[3] = new Punkt(4, 3); insertionSort(a); for (int i = 0; i < a.length; i++) System.out.println(a[i].x + " " + a[i].y); } public static <T> void insertionSort (T[] a) { //... } } 69 InsertionSort für Objekte generische Methode: Nimmt Feld mit Objekten vom Typ T entgegen. Platzhalter public static <T> void insertionSort (T[] a) { //... } } 70 InsertionSort für Objekte generische Methode: Wie sicherstellen, dass T das Interface Comparable<T> implementiert? Platzhalter public static <T> void insertionSort (T[] a) { //... } } 71 InsertionSort für Objekte generische Methode: Gib entsprechende Bedingung an! public static <T extends Comparable<T>> void insertionSort (T[] a) { //... } } 72 InsertionSort für Objekte generische Methode: public class Punkt implements Comparable<Punkt> { //... Achtung: Schlüsselwort ist „extends“ und nicht „implements“! public static <T extends Comparable<T>> void insertionSort (T[] a) { //... } } 73 InsertionSort für Objekte public class Sortierverfahren { public static <T extends Comparable<T>> void insertionSort(T[] a) { for (int j = 1; j < a.length; j++) { T key = a[j]; int i = j - 1; while (i >= 0 && a[i].compareTo(key) > 0) { a[i + 1] = a[i]; i--; } a[i + 1] = key; } } } 74 InsertionSort für Objekte public class Sortierverfahren { public static void main(String[] args) { Punkt[] a = new Punkt[4]; a[0] = new Punkt(1, 2); a[1] = new Punkt(1, 1); a[2] = new Punkt(3, 1); a[3] = new Punkt(4, 3); insertionSort(a); for (int i = 0; i < a.length; i++) System.out.println(a[i].x + " " + a[i].y); } public static <T extends Comparable<T>> void insertionSort (T[] a) { //... } 75 Schluss Generische Datentypen/Methoden erlauben es, Datenstrukturen/Algorithmen so zu implementieren, dass sie für verschiedene Datentypen angewandt werden können. 76 Übersicht InsertionSort • für Punkte • für Objekte beliebiger Klassen • für Objekte von Klassen, die ein(e) Nutzer(in) festlegen kann Beispiel: Mehrere Interfaces 77 Mehrfachvererbung Tier +masse:double +volumen:double masse in kg, volumen in m3 Landtier Wassertier +getGewichtskraft():double +getAuftrieb():double Frosch Quelle: Wikipedia In Java ist Mehrfachvererbung verboten! ?? Quelle: Wikipedia Quelle: Wikipedia 78 Mehrere Interfaces Tier +masse:double +volumen:double <<Interface>> Landtier +getGewichtskraft():double Frosch <<Interface>> Wassertier ! +getAuftrieb():double +getGewichtskraft():double Quelle: Wikipedia +getAuftrieb():double Quelle: Wikipedia public class Frosch extends Tier implements Landtier, Wassertier { //... 79 Mehrere Interfaces und Generics public class Frosch<T,K,V> extends Tier<T> implements Landtier<T,V>, Wassertier<K> { //... oO Quelle: Wikipedia 80