Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Telecooperation/RBG Technische Universität Darmstadt Copyrighted material; for TUD student use only Grundlagen der Informatik I Thema 18: Typkonvertierungen.

Ähnliche Präsentationen


Präsentation zum Thema: "Telecooperation/RBG Technische Universität Darmstadt Copyrighted material; for TUD student use only Grundlagen der Informatik I Thema 18: Typkonvertierungen."—  Präsentation transkript:

1 Telecooperation/RBG Technische Universität Darmstadt Copyrighted material; for TUD student use only Grundlagen der Informatik I Thema 18: Typkonvertierungen und Generizität Prof. Dr. Max Mühlhäuser Dr. Guido Rößling

2 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Typkonvertierung Mit statischer Typisierung gibt es viele Kontexte, in denen Werte eines bestimmten Typs erwartet werden. –In a = expression erwarten wir, dass expression den gleichen Typ wie a hat –In a + b erwarten wir, dass a und b entweder beide ganze Zahlen, Fließkommazahlen oder Zeichenketten sind. –In f(a,b) erwarten wir, dass die Typen der Argumente sich mit denen der formalen Parameter decken. 2

3 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Arten der Typkonvertierung in Java Identitätskonvertierung – von einem Typ auf denselben Typ –Es ist z.B. ok, eine redundante Konvertierung einzufügen Verbreiterung primitiver Typen –z.B. byte nach int (ohne Informationsverlust) –z.B. int nach double (möglicher Informationsverlust) Verengung primitiver Typen –z.B. int nach byte (höhere Bits wegwerfen) –z.B. float nach int 3

4 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Arten der Typkonvertierung in Java Verbreiterung von Referenztypen (Verallgemeinerung) –Gegeben Referenztypen A, B, dann kann A zu B verbreitert werden genau dann wenn A ein Subtyp von B ist. –Diese Konvertierung geschieht immer während der Kompilierung und kann keine Laufzeitfehler auslösen. Verengung von Referenztypen (Konkretisierung) –Gegeben Referenztypen A, B, dann kann A verengt werden zu B genau dann wenn B ein Subtyp von A ist. –Diese Konvertierung muss zur Laufzeit überprüft werden und löst möglicherweise einen Laufzeitfehler aus. 4

5 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Arten der Typkonvertierung in Java String Konvertierung –Jeder Typ kann zu String konvertiert werden –Implizit wird die toString() -Methode (aus java.lang.Object ) benutzt –Das haben Sie z.B. bei System.out.println(myObject) schon genutzt Boxing und Unboxing –Von byte zu Byte, int zu Integer etc. und umgekehrt Ungeprüfte Konvertierung –Konvertierungen die zu einem Fehler führen können, ergeben Warnung zur Kompilierzeit –z.B. Konvertierung eines raw type zu einem parametrisierten Typ 5

6 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Konvertierungskontexte Zuweisungskonvertierung: v = expr –Konvertiere den Typ von expr zum Typ von v. –Nur für Konvertierungen ohne mögliche Laufzeitfehler Methodenaufrufkonvertierung: expr.M(expr) –konvertiert die Typen der Argumente. –Nur für Konvertierungen ohne mögliche Laufzeitfehler Cast-Konvertierung: (T)expr –Konvertiert den Typ von expr zu T –Kann auch die Verengungskonvertierung benutzen! Numerische Konvertierung –Konvertiert die Operanden eines numerischen Operators in einen gemeinsamen Typen, so dass die Operation ausgeführt werden kann erlaubt Identitäts-, Verbreiterungs- und Unboxing Konvertierung

7 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Typ-Verengung Verbreiterung verliert statische Typinformation // p bezieht sich auf Circle, Verbreiterung OK GraphicObject p = new Circle(5, 12, 4); Circle c1 = p; // compile-Fehler kann nicht verengen Die Information kann zur Laufzeit mit Tests und Casts wieder zurückgeholt werden kann if (p instanceof Circle) { // Laufzeittest c1 = (Circle) p; // Explizite Verengung } // zur Laufzeit OK 7

8 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Nochmals Collections… Eine Collection sollte zu mehr als einem Typ passen –Eine Implementierung langt für verschiedene Zwecke –Das allgemeine Verhalten der Collection hängt nicht vom Elementtyp ab Zusätzlich wollen wir einen spezifischen Elementtyp garantiert haben –Angenommen, wir nutzen eine Collection nur für Person Instanzen –Dann wollen wir auch Person Objekte ohne Verendung von Object erhalten können! 8

9 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Nochmals Collections… List myIntList = new LinkedList(); // 1 myIntList.add(new Integer(0)); // 2 Integer x = (Integer)myIntList.get(0); // 3 Der Cast in Zeile ist nervig aber erforderlich –Java garantiert nur, dass das Ergebnis zum Typ Object passt –Es kann also vom Typ Integer sein – oder eben auch nicht! Daher kriegen wir einen Typfehler ohne den Cast Zudem wurde der Cast nicht mit instanceof abgesichert Wir könnten uns auch irren und etwas anderes erhalten List myIntList = new LinkedList(); // 1 myIntList.add("Hello World"); // 2 Integer x = (Integer)myIntList.get(0); // 3 –Nun erhalten wir eine ClassCastException zur Laufzeit! 9

10 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Angabe der Absichten mit Generics Wir müssen Java mehr über unsere Absichten sagen –Diese Liste will nur Elemente haben, die zu Integer passen Dafür müssen wir…: –Die Deklaration der Liste anpassen: List –Das Anlegen der Liste anpassen: new LinkedList Vorteile: –Wir können auf den Cast in Zeile 3 verzichten –Typen, die nicht zu Integer passen, können nicht eingefügt oder abgefragt werden List myIntList = new LinkedList (); // 1 myIntList.add(new Integer(0)); // 2 Integer x = myIntList.get(0); // 3 myIntList.add("Hello World"); // compile-Fehler 10

11 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Was hat sich geändert? myIntList ist nun eine List –Nicht eine Liste, sondern eine Liste von Integer-Objekten –Wir müssen Ergebnisse also nicht mehr nach Integer casten Wir können keine anderen Typen mehr speichern Darum kümmern sich der Java Compiler (und Eclipse) 11 myIntList.add("Hello World"); The method add(Integer) in the type List is not applicable for the arguments (String)

12 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Und was bringt uns das? Auf den ersten Blick vielleicht nicht viel –Die Deklaration und Erzeugung der Liste sind länger –Wir können nur auf den Cast verzichten Es gibt aber einen großen Unterschied! –Nun kann der Compiler die Typkorrektheit überprüfen –Die Deklaration von myIntList gibt den Typ an –Der Compiler stellt sicher, dass alle Zugriffe zum Typ passen Was ist hier anders als bei einem Cast? –Mit einem Cast sagt der Programmierer der Typ sollte hier zum Cast zu Typ X passen Das sollte immer mit instanceof abgesichert werden! –Generische Deklaration sagt das passt immer zu Typ X 12

13 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Nochmals Listen List und Iterator werden in java.util wie folgt definiert: 13 public interface List { void add(E x); Iterator iterator(); } public interface Iterator { E next(); boolean hasNext(); void remove(); } Das kennen wir im Wesentlichen schon (siehe T15) Außer dem und E Damit wird ein formaler Typparameter deklariert E kann dann in der Klasse als Typ genutzt werden

14 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 List und IntegerList Wir nutzen List, aber es gibt nur List ? E ist ein formaler Typparameter –Ähnlich zu den formalen Parametern in Methodensignaturen E wird in allen Aufrufen durch Integer ersetzt Intuitiv kann man sich das so vorstellen: 14 public interface IntegerList { void add(Integer x); IntegerIterator iterator(); } Das kann das Verständnis erleichtern Aber es ist auch irreführend Es gibt nur eine List Klasse, nicht eine pro Typ

15 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Generics und Subtypen Warum ist der folgende Code nicht korrekt? Zeile 1 ist sicherlich korrekt –LinkedList ist ein Untertyp von List –Die formalen Parameter (beide String) passen Passt List in Zeile 2 zu List ? –List ist auf beiden Seiten die gleiche Basisklasse –String ist ein Erbe von Object –Die intuitive Antwort ist also ja 15 List ls = new LinkedList (); // 1 List lo = ls; // 2 lo.add(new Object()); // 3 String s = ls.get(0); // 4 Dieser Code wird vom Übersetzer so nicht akzeptiert!

16 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Generics und Subtypen Zunächst schauen wir uns den weiteren Code an: 16 List ls = new LinkedList (); // 1 List lo = ls; // 2 lo.add(new Object()); // 3 String s = ls.get(0); // 4 Zeile 2 legt ein Alias der Object und String List an Wir können ein Object in List einfügen (Zeile 3) Aber wir fügen es gleichzeitig auch in ls ein! ls ist deklariert als List … Aber ls würde nun auch andere Objekttypen enthalten Der Compiler erkennt das nicht, wenn Zeile 2 korrekt ist Daher wird der Compiler Line 2 zurückweisen type mismatch: cannot convert from List to List Dieser Code wird vom Übersetzer so nicht akzeptiert!

17 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Generics, Subtypen und unsere Intuition Sei Y eine Unterklasse von (Klasse oder Interface) X G sei eine generische Typdeklaration (z.B. List ) G ist kein Subtyp von G Warum fällt uns das so schwer zu glauben? Wir unterstellen, dass sich die Collection nicht ändert –Das ist natürlich oft eine falsche Annahme! Angenommen, das Studierendensekretariat gibt eine Liste der Studenten an das Einwohnermeldeamt –Ein Student ist eine Person –Übergabe von List für List wirkt OK –Aber nur, wenn eine Kopie übergeben wird, keine Referenz! –Das Einwohnermeldeamt fügt eine Person (aber nicht Student) ein Die gemeinsame (!) Studentenliste ist nun korrumpiert 17

18 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Generics, Subtypen und Intuition 18 Collection Set Collection Set Kovariante Subtypen Punktweise Subtypen, sicher nicht sicher

19 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Behandlung von Subtypen: Wildcards Wir wollen alle Elemente einer Collection ausgeben Ohne Generics funktioniert das in etwa wie folgt: Jetzt passen wir das eben schnell an Generics an: Aber diese Methode akzeptiert nur Collection –Sie akzeptiert keine List, sondern nur List –Zur Erinnerung: List ist kein Subtyp von List 19 void printCollection(Collection c) { for (Object element: c) System.out.println(element); } void printCollection(Collection c) { for (Object element: c) System.out.println(element); }

20 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Behandlung von Subtypen: Wildcards Was müssen wir nun tun? –Wir brauchen einen gemeinsamen Obertyp für alle Collection-Arten –Das ist die Collection von unbekannten Elementtypen –In Java-Notation: Collection (hier: List ) Nun können wir den Code anpassen: Die Elemente der Liste werden wie Object behandelt –Da java.lang.Object die Superklasse aller Typen ist –Daher passt jeder Typ – auch der unbekannte Typ ? - zu Object 20 void printCollection(Collection c) { for (Object element: c) System.out.println(element); }

21 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 The unbekannte Typ Der Unbekannte Typ wirkt sehr hilfreich –Wir können endlich auf die Elemente zugreifen! –Falls nötig, können wir sie auf einen konkreten Typ casten Natürlich nur wenn der Cast gültig ist! Wie steht es mit dem folgenden Code? c hat den unbekannten Elementtyp ? Der einzufügende Typ muss zu ? passen –Der Compiler kennt den tatsächlichen Typ von ? nicht –Daher ist unklar, ob Object dazu passt –Man darf kein Object einfügen in eine List ! –Es kann nur der Wert null eingefügt werden 21 Collection c = new ArrayList (); c.add(new Object()); Dieser Code wird vom Übersetzer so nicht akzeptiert!

22 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Eine generische Zeichenanwendung Wir betrachten folgendes Modell für ein Zeichentool: 22 abstract class Shape { abstract void draw(Canvas c); } class Circle extends Shape { private int x, y, radius; void draw(Canvas c) { //... } } class Rectangle extends Shape { private int x, y, width, height; void draw(Canvas c) { //... } } class Canvas { void draw(Shape s) { s.draw(this); } }

23 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Eine generische Zeichenanwendung Jede Form erweitert Shape und kann sich zeichnen Wir werden meist mehr als eine Form zeichnen! Also speichern wir die Elemente in einer List Wir passen den Code von Canvas entsprechend an: Das funktioniert gut für jede List Und wenn wir eine List zeichnen wollen? –Circle ist ein Subtyp von Shape –Aber List ist kein Subtyp von List –Der Aufruf drawAll(List ) führt zu einem Compile-Fehler 23 void drawAll(List shapes) { for (Shape s: shapes) { s.draw(this); }

24 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Eine generische Zeichenanwendung drawAll passt an sich zu allen Shape-Subtypen drawAll sollte mit List, List, List, funktionieren…! Der Einsatz von ? bringt uns nicht weiter –Der unbekannte Typ ? hat keine Methode draw(Canvas) –Der Cast nach Shape ist möglich aber gefährlich Wir müssen die Wildcard beschränken (bound) –Sie sollte alle Listen von Subtypen von Shape akzeptieren In Java-Notation: 24 void drawAll(List shapes) { for (Shape s: shapes) { s.draw(this); }

25 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Beschränkte Wildcards Es gibt einen kleinen aber wichtigen Unterschied –List akzeptiert nur genau List –List akzeptiert Listen von allen Subtypen von Shape, inklusive Shape selbst List … ? extends X bedeutet: –Wir kennen den exakten Type nicht ( ?) –Aber wir wissen, dass der Typ zu X konform sein muss –X ist die obere Schranke der Wildcard 25

26 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Beschränkte Wildcards Warum stimmt am folgenden Code nicht? Wir können kein Rechteck in List einfügen –Wir kennen den exakten Typ der Elemente in shapes nicht –Wir wissen zwar, dass es ein Subtyp von Shape ist –Aber der Typ passt nicht unbedingt zu Rectangle Der Aufruf könnte lauten addRectangle(List ); Bei unbekanntem Typ können wir nur null einfügen –Einerseits schlecht… –Dafür gibt es keine Typprobleme zur Laufzeit! –Java geht hier den (typ-)sicheren Weg. 26 void addRectangle(List shapes) { shapes.add(0, new Rectangle()); } Dieser Code wird vom Übersetzer so nicht akzeptiert!

27 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Schreiben von generischen Methoden Wie kopiert man alle Arrayelemente in eine Collection? Wir können nicht Collection als Parameter nutzen Aber Collection wird auch nicht funktionieren! –Der Typ ist unbekannt, also passt jeder konkrete Typ potentiell nicht 27 static void copyToCollection(Object[] array, Collection c) { for (Object o: array) { c.add(o); } Dieser Code wird vom Übersetzer so nicht akzeptiert!

28 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Schreiben von generischen Methoden Dazu schreiben wir eine generische Methode: Das besagt, dass dies eine generische Methode ist –T wird vor dem Rückgabewert eingeführt T dient als formaler Parametertyp Der Java Compiler nutzt das für Zugangskontrolle –Der Typ des Feldes und der Collection müssen konform sein –Es gilt der allgemeinste konforme Typ Meist langt die Nutzung von Wildcards –Wildcards werden bevorzugt – klarer und knapper 28 static void copyToCollection(T[] array, Collection c) { for (T o: array) { c.add(o); }

29 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Abfrage des Typs Abfrage des Basistyps eines generischen Typs: Aber wir erhalten nicht den genauen generischen Typ –Es gibt nur eine Klasse List (siehe Folie 15) –Die compile-Zeit Information über den formalen Parameter ist zur Laufzeit nicht verfügbar Wir können auch getClass() nutzen: Die Ausgabe ist wieder true – getClass() liefert java.util.List 29 List circles = new ArrayList (); List rects = new ArrayList (); System.out.println(circles instanceof List); // true System.out.println(circles.getClass() == rects.getClass()); System.out.println(circles instanceof List ); // Fehler

30 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Untere Schranken Wir wollen eine Datensenke implementieren –Diese leert eine Collection und gibt das letzte Element zurück Was ist hier das generische Typargument ? –Es gibt keinen gültigen Typ, da die Typen nicht konform sind –Der Aufruf in der letzten Zeile ist damit illegal 30 interface Sink { void flush(T t); } static T flushAll(Collection c, Sink sink) { T last = null; for (T t: c) { last = t; sink.flush(last); } return last; } Sink sink; Collection collection; String lastString = flushAll(collection, sink); Dieser Code wird vom Übersetzer so nicht akzeptiert!

31 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Untere Schranken Das scheint einfach zu beheben zu sein…: Jetzt funktioniert der Aufruf! Aber: T wird nun auf Object abgebildet –Weil das der Elementtyp des Sinks ist –Daher scheitert die Zuweisung des Ergebnisses an String Wir benötigen unbekannt, aber Oberklasse von T In Java-Notation: 31 static T flushAll(Collection c, Sink sink) { static T flushAll(Collection c, Sink sink) {

32 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Implementierungsbeispiel 32 interface Sink { void flush(T t); } class ConcreteSink implements Sink { public void flush(T t) { System.err.println("Flushing " + t + ", type: " +t.getClass().getName()); } static T flushAll(Collection c, Sink sink) { T last = null; for (T t: c) { last = t; sink.flush(last); } return last; } Sink sink = new ConcreteSink (); Collection cs = Arrays.asList("a","bb2","cdf"); System.err.println(flushAll(cs, sink)); Bitte denken Sie sich den jeweiligen Klassenkontext dazu!

33 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Statische Typisierung - Zusammenfassung Statische Typsysteme sind Gegenstand sehr aktiver Forschung Java-ähnliche Typsysteme sind begrenzt, aber im Allgemeinen können Typsysteme sehr mächtig und ausdrucksstark sein –Aber auch sehr kompliziert Manche Programmierer sehen statische Typsysteme als eine Begrenzung ihrer Freiheit ("ich weiß, was ich tue") Andere Programmierer denken, dass statische Typsysteme nicht nur viele Fehler erkennen, sondern auch eine gute Struktur im Code erzwingen ("erst denken, dann schreiben") Die Diskussion ist noch nicht beendet. Sie sollten eine fundierte Meinung darüber haben! 33

34 Dr. G. Rößling Prof. Dr. M. Mühlhäuser RBG / Telekooperation © Grundlagen der Informatik I: T18 Weiterführende Literatur Die folgenden Materialien bieten (viel) mehr zu Generics: –Java Tutorial on Generics (by Gilad Bracha): –Gilad Bracha, Generics in the Java Programming Language Diente als Hauptvorlage für diese Folien –Maurice Naftalin, Philip Wadler: Java Generics and Collections, OReilly,


Herunterladen ppt "Telecooperation/RBG Technische Universität Darmstadt Copyrighted material; for TUD student use only Grundlagen der Informatik I Thema 18: Typkonvertierungen."

Ähnliche Präsentationen


Google-Anzeigen