Generische Datentypen • • • • • Programmierung (fortgeschrittene Konzepte) Generische Programmierung in Java Wolf-Ulrich Raffel ([email protected]) 19.10.2005 Generische Programmierung in Java 1 Zur Erinnerung: Generische Programmierung in Java 19.10.2005 3 19.10.2005 Generische Programmierung in Java 4 Die Schnittstelle Iterator • Alte Version (vereinfacht): • Alte Version: public class Vector implements Collection{ public void add (Object o) {...} public Iterator iterator() {...} } public interface Iterator{ boolean hasNext (); Object next(); } • Neue Version (vereinfacht): • Neue Version: public class Vector<T> implements Collection<T>{ public void add (T o) {...} public Iterator<T> iterator() {...} Generische Programmierung in Java 2 Vector meineGeomObjekte = new Vector<GeomObjekt>(); meinGeomObjekte.add(new Quadrat(3.0)); meinGeomObjekte.add(new Fahrrad()); //falsch! ... Iterator<GeomObjekt> iter = meineGeomObjekte.iterator(); while (iter.hasNext()) { GeomObjekt o = iter.next(); println(o.flaecheninhalt()); } Die Klasse Vector 19.10.2005 Generische Programmierung in Java Mit Generischen Datentypen: Vector meineGeomObjekte = new Vector(); meinGeomObjekte.add(new Quadrat(3.0)); meinGeomObjekte.add(new Fahrrad()); //sinnlos, aber erlaubt ... Iterator iter = meineGeomObjekte.iterator(); while (iter.hasNext()) { Object o = iter.next(); if (o instanceof GeomObjekt) { //zur Sicherheit println(((GeomObjekt)o).flaecheninhalt()); } } 19.10.2005 „Generics“ Verfügbar ab Java (1.)5.0. Vorher separate Sprache: „Generic Java“ Vermeidet unnötige Typecasts Ermöglicht Collections mit anderen Typen als Objects 5 public interface Iterator<T>{ boolean hasNext (); T next(); } 19.10.2005 Generische Programmierung in Java 6 1 Eigene Generics definieren Unterklassen bei Generics • Ein Quadrat ist ein Rechteck, aber: • Java API enthält viele generische Klassen (Vector, Iterator,...) • Man kann selbst Generics definieren • Generischer Code wird nicht für jede Instanz kopiert (anders als in C++) • Namenskonvention für Typparameter: einzelne Grossbuchstaben 19.10.2005 Generische Programmierung in Java Vector<Quadrat> quadrate = new Vector<Quadrat>(); Vector<Rechteck> rechtecke = quadrate; //falsch • Sieht erlaubt aus, scheitert aber deswegen: rechtecke.add(new Rechteck(2.5,1.5)); Quadrat q = quadrate.get(0); • Problem ist bereits von Feldern bekannt: Quadrat[] quadrate = new Quadrat[10]; Rechteck[] rechtecke = quadrate; rechtecke[0] = new Rechteck(2.5,1.5); //erzeugt ArrayStoreException 7 19.10.2005 Wildcards • Statt Object kann man ein Wildcard verwenden static void printAll (Vector<?> v) { Iterator<?> iter = v.iterator(); while (iter.hasNext()) { Object o = (iter.next()); //geht! System.out.println(o); } } static void printAll (Vector<Object> v) { Iterator<Object> iter = v.iterator(); while (iter.hasNext()) { Object o = (iter.next()); System.out.println(o); } } • Wildcard matcht alle Klassen • Vector<?> ist Oberklasse aller Vector-Klassen • Zuweisung an Object möglich, da Object Mutterklasse • Funktioniert leider nur für Vector<Object>, aber z.B. nicht für Vector<String> Generische Programmierung in Java 9 Beschränkte Wildcards Generische Programmierung in Java 10 • 2.Versuch: Mit Wildcards static double flaechensumme (Vector<?> v) { Iterator<?> iter = v.iterator(); double summe = 0.0; while (iter.hasNext()) { GeomObjekt o = (iter.next()); //falsch! summe+=o.flaecheninhalt(); } return summe; } static double flaechensumme (Vector<GeomObjekt> v) { Iterator<GeomObjekt> iter = v.iterator(); double summe = 0.0; while (iter.hasNext()) { GeomObjekt o = (iter.next()); summe+=o.flaecheninhalt(); } return summe; } • Geht nicht, Zuweisung nur an Object möglich • Geht leider nur z.B. nicht für Vector<Quadrat> Generische Programmierung in Java 19.10.2005 Beschränkte Wildcards (2) • Angenommen, wir wollen die Flächeninhalte Geometrischer Objekte aufsummieren 19.10.2005 8 Wildcards (2) • Angenommen, wir wollen alle Elemente eines Vectors ausgeben 19.10.2005 Generische Programmierung in Java 11 19.10.2005 Generische Programmierung in Java 12 2 Beschränkte Wildcards (3) Schreiben bei Wildcards • Lösung: Beschränkte Wildcards • Schreiben in Vector mit durch „extends“ beschränktem Wildcard nicht möglich! static double flaechensumme (Vector<? extends GeomObjekt> v) { Iterator<? extends GeomObjekt> iter = v.iterator(); double summe = 0.0; while (iter.hasNext()) { GeomObjekt o = (iter.next()); summe+=o.flaecheninhalt(); } return summe; } static void fuegeEinheitsQuadratHinzu (Vector<? extends GeomObjekt> v) { v.add(new Quadrat(1.0)); //geht nicht! } • Aber es geht das folgende static void fuegeEinheitsQuadratHinzu (Vector<Quadrat> v) { v.add(new Quadrat(1.0)); } • Geht für jeden Subtyp vom GeomObjekt 19.10.2005 Generische Programmierung in Java 13 Schreiben bei Wildcards (2) 19.10.2005 Generische Programmierung in Java 14 Zusammenfassung Wildcards • Es geht auch jeder Supertyp von Quadrat: • Nur Objekte lesen => einfache Wildcards static void fuegeEinheitsQuadratHinzu (Vector<GeomObjekt> v) { v.add(new Quadrat(1.0)); } void printAll (Vector<?> v) • Nur geom.Objekte lesen => beschränkte Wildcards mit extends void read(Vector<? extends GeomObjekt> v) • Allgemein lässt sich formulieren • Nur geom.Objekte schreiben => beschränkte Wildcards mit super static void fuegeEinheitsQuadratHinzu (Vector<? super Quadrat> v) { v.add(new Quadrat(1.0)); } void write(Vector<? super GeomObjekt> v) • geom.Objekte lesen und schreiben => exakten Typ verwenden void readAndWrite(Vector<GeomObjekt> v) 19.10.2005 Generische Programmierung in Java 15 19.10.2005 Generische Methoden Generische Programmierung in Java 16 Generische Methoden (2) • Bisher nur generische Klassen und Schnittstellen • Auch Methoden können generisch sein • Bei Methodenaufruf braucht man Typparameter nicht angeben • Spezifischster Typ für Methode wird ausgewählt 19.10.2005 Generische Programmierung in Java 17 • Angenommen, wir wollen alle Elemente eines Feldes in einem Vector speichern static void arr2vec(Object[]a,Vector<?> v){ for (int i=0; i<a.length; i++) { v.add(a[i]); //geht nicht! } } • Mit generischen Methoden geht es: static <T> void arr2vec(T[]a,Vector<? super T> v){ for (int i=0; i<a.length; i++) { v.add(a[i]); } } 19.10.2005 Generische Programmierung in Java 18 3 Generische Methoden vs. Wildcards Generische Methoden vs. Wildcards (2) • Man kann formulieren: • Generische Methoden nur verwenden, wenn Typparameter mehrmals genutzt wird interface Collection<E> { <T> boolean containsAll(Collection<T> c); <T extends E> void addAll(Collection<T> c); } static <T> void tausch0(Vector<T> v1, Vector<T> v2){ v1.add(v2.get(0)); v2.add(v1.get(0)); } • Oder äquivalent (und eleganter) mit Wildcards: • Verwendung von Wildcards geht nicht interface Collection<E> { boolean containsAll(Collection<?> c); void addAll(Collection<? extends E> c); } 19.10.2005 Generische Programmierung in Java void tausch0(Vector<?> v1, Vector<?> v2){ v1.add(v2.get(0));//geht nicht v2.add(v1.get(0));//geht nicht } 19 Methodenauswahl Vector<Quadrat> quadratV = new Vector<Quadrat>(); Vector<Rechteck> rechteckV = new Vector<Rechteck>(); Quadrat[] quadratA = new Quadrat[10]; ... 20 • Ähnliches Problem beim Überladen von Methoden bekannt: void tueEtwas (GeomObjekt g1, GeomObjekt g2){...} //1 void tueEtwas (GeomObjekt g, Quadrat q){...} //2 void tueEtwas (Quadrat q, Rechteck r){...} //3 • Folgende Aufrufe werden durchgeführt: • und führen folgende Aufrufe durch tueEtwas tueEtwas tueEtwas tueEtwas arr2vec(quadratA,rechteckV);//T=Rechteck arr2vec(rechteckA,quadratV);//geht nicht arr2vec(quadratA,objectV);//T=Object arr2vec(quadratA,kreisV);//geht nicht Generische Programmierung in Java Generische Programmierung in Java Methodenauswahl bei Überladen • Angenommen wir haben folgendes 19.10.2005 19.10.2005 (rechteck1, quadrat1); (quadrat1, kreis1); (quadrat1, object1); (quadrat1, quadrat2); //2 spez. als 1) //nur 1 passt //nichts passt // 2 oder 3 ? • Compilezeitfehler, wenn keine Methode passt oder Auswahl mehrdeutig 21 19.10.2005 Generische Programmierung in Java 22 Abschlussbemerkungen • Mehrere Typparameter möglich public class MyClass <S,T> {...} • Konstruktordeklaration ohne Typparameter public class MyClass <S,T> { public MyClass() {...} //richtig public MyClass<S,T>() {...} //falsch } 19.10.2005 Generische Programmierung in Java 23 4