13. Generics. Prof. Dr. Harald Gall. Institut für Informatik Universität Zürich.

Ähnliche Dokumente
A(T1) A(T2) A(T1) A(T2)

Generisches Programmieren

Objektorientierte Programmierung. Kapitel 12: Interfaces

1 Polymorphie (Vielgestaltigkeit)

Generische Typen in Java 1.5. Die Erweiterung der Java Language Specification

Kapitel 6. Vererbung

Kapitel 6. Vererbung

Kapitel 6. Vererbung

Java Einführung Abstrakte Klassen und Interfaces

Fortgeschrittene Programmierung

Type Erasure in Java 5. Helmi Jouini Institut für Theoretische Informatik Universität Karlsruhe

Abschnitt 9: Schnittstellen: Interfaces

Java Schulung (Java 2 Java Development Kit 5 / 6)

Übung 1 mit C# 6.0 MATTHIAS RONCORONI

Typumwandlungen bei Referenztypen

Algorithmen und Datenstrukturen

5.4 Klassen und Objekte

Java: Eine Übersicht. Dennis Giffhorn. Lehrstuhl für Programmierparadigmen Universität Karlsruhe

Java Generics & Collections

Test zu Grundlagen der Programmierung Leitung: Michael Hahsler. 21. November 2003

Ein erstes Java-Programm

Prinzipien Objektorientierter Programmierung

Java für Computerlinguisten

Objektorientierte Programmierung

Algorithmen und Datenstrukturen 07

Proseminar: C# und.net. 6. Vortag Generische Klassen. Sebastian Wolf

Programmieren in Java

2.4.3 Polymorphie (Wiederholung von Alp2)

Probeklausur: Programmierung WS04/05

5.6 Vererbung. Vererbung

Seminar Scala SS2010, Einführung. R. Schiedermeier Fakultät 07 für Informatik und Mathematik

3 Objektorientierte Konzepte in Java

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 11/12. Kapitel 13. Bäume. Bäume

Objektorientierte Programmierung

Programmieren I. Strategie zum Entwurf von Klassen. Beispiele. Design von Klassen. Dr. Klaus Höppner. Beispiel: Bibliothek

Objekt-Orientierte Programmierung

Spec# Einführung. Formale Software-Entwicklung Seminar SS 07 Universität Karlsruhe Hilal Akbaba

Vererbung & Schnittstellen in C#

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Repetitorium Informatik (Java)

Formale Spezialisierungstechniken. am Beispiel des binären Baums. Hybride Programmiersprachen Daniel Krompass Berlin, 2009

Generische Datenstrukturen

Einführung Datentypen Verzweigung Schleifen Funktionen Dynamische Datenstrukturen. Java Crashkurs. Kim-Manuel Klein

7. Objektorientierte Softwareentwicklung/3. Informatik II für Verkehrsingenieure

Javakurs 2013 Objektorientierung

Java Einführung Methoden in Klassen

Schnittstellen implementieren am Beispiel Suchbaum

II.1.1. Erste Schritte - 1 -

Prof. Dr. Uwe Schmidt. 21. August Aufgaben zur Klausur Objektorientierte Programmierung im SS 2007 (IA 252)

Problemstellung. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 24: Reflection 1. IDE und automatische Tests.

Java: Vererbung. Teil 3: super()

12) Generische Datenstrukturen

Klassenbeziehungen & Vererbung

Java Einführung VARIABLEN und DATENTYPEN Kapitel 2

Javakurs für Anfänger

Eine Klasse beschreibt Objekte mit gleichen Attributen und Methoden.

PIWIN I. Praktische Informatik für Wirtschaftsmathematiker, Ingenieure und Naturwissenschaftler I. Vorlesung 3 SWS WS 2008/2009

1. Grundlegende Eigenscha5en 2. Redefini+on 3. Polymophie 4. Mehrfachvererbung

VIII: Vererbung. Unterklassen einer Klasse. Vererbung von Methoden und Instanzvariablen. Überschreiben von Methoden

Allgemeine Informatik 1 (AI1)

Vererbung. Vererbung von Methoden und Instanzvariablen. Vererbung als Realisierung einer is-a Beziehung.

Bäume. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 10: Collections 4. Inhalt. Bäume. Einführung. Bäume.

Java Tipps für Lehrer. Table des matières. Einleitung

Vorlesung Programmieren

Das Liskovsche Substitutionsprinzip

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 14/15. Kapitel 11. Fehler und Ausnahmen 1

3 Objektorientierte Konzepte in Java

Objects First With Java A Practical Introduction Using BlueJ. Mehr über Vererbung. Exploring polymorphism 1.0

Teil 1: Grundeigenschaften von Rechnern und Software

10. Klassen. Prof. Dr. Markus Gross Informatik I für D-ITET (WS 03/04)

Klassen in Java. Klassen

Über den Autor 7. Teil I Los geht s mit Java für die Android-Entwicklung 25. Kapitel 1 Alles über Java und Android 27

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck

Klausur zur Einführung in die objektorientierte Programmierung mit Java

equals und hashcode SortedSet NavigableSet Assoziative Container Programmieren II Dr. Klaus Höppner Hochschule Darmstadt Sommersemester / 32

13. Tutorium zu Programmieren

4 Vererbung, Polymorphie

Info: Standard DO-178B. 5. Mocking. Zusammenspiel von Klassen testen. Allgemein: Klassen testbar machen

Versuchsziele Kenntnisse in der Anwendung von: Sortieren mit Klassen Benutzung von generischen Klassen o Definition o Sortierung.

Allgemein: Klassen testbar machen. 5. Mocking. Mocks programmieren. Zusammenspiel von Klassen testen

Java-Schulung Grundlagen

Vorkurs C++ Programmierung

COPPER Best Practices

Java Kurs für Anfänger Einheit 5 Methoden

12) Generische Datenstrukturen

Der linke Teilbaum von v enthält nur Schlüssel < key(v) und der rechte Teilbaum enthält nur Schlüssel > key(v)

Datenbankanwendungsprogrammierung Crashkurs Java

Propädeutikum zur Programmierung

Einführung in AOP. Rico Schiekel rschiekel@web.de. Agenda. Kernproblem der Objekt Orientierung

Folge 18 - Vererbung

Workshop 6. Einführung in die objektorientierte Programmierung. Teil: Java mit BlueJ

C++ - Operatoren. Eigene Klassen mit neuen Funktionen

Abstrakte Datentypen.

Universität Karlsruhe (TH)

Einführung in die. objektorientierte Programmierung

Web-Services Implementierung mit Java

Themen. Web Service - Clients. Kommunikation zw. Web Services

Grundlagen der Informatik Generische Klassen

Informatik II. /* c) Baumstruktur in einen String schreiben und zurueckgeben */ public String tostring() {

Institut fu r Informatik

Transkript:

13. Generics Prof. Dr. Harald Gall Institut für Informatik Universität Zürich http://seal.ifi.uzh.ch

Lernziele! Wie kann man mehr Flexibilität hinsichtlich der Typen erreichen?! Wie kann man Typen als Variablen verwenden?! Was sind Generics und wie setzt man diese ein?! Was ist der Unterschied zu Vererbung und Interfaces?! Was muss bei Generics beachtet werden? 2

Motivation! Container und Elemente! Beispiel: Knotenklasse! Probleme! Generische Typen! Verwechslungsgefahr! Begriffe 3

Container und Elemente! Container = Klassen zum Speichern anderer Objekte als Elemente! Beispiele:! Strings (eingeschränkt), Arrays, Collections! Arbeitsweise eines Containers unabhängig vom konkreten Elementtyp! Problem: Definition neuer Containertypen 4

Beispiel: Knotenklasse! Idee! Knoteninformation! Knotenklasse! Konstruktoren! Aufbau eines Baums! Getter und Setter 5

Knotenklasse: Problem! Elementtyp Object erlaubt beliebige Knoteninformation (via Autoboxing auch primitive Typen)! Aber: selber Knotentyp innerhalb eines Baums oft sinnvoll oder notwendig! Keine Unterstützung durch Knotenklasse. Beispiel: Node n1 = new Node("foo"); Node n2 = new Node(3.141592); Node n0 = new Node(23, n1, n2);! Auslesen von Knoteninformationen erfordert Typecast, weil getinfo als Ergebnis nur Object liefert: String s = (String)n.getInfo();!! Typecasts immer problematisch 6

Generische Typen! Lösung: Generische Klassen! Definition: Elementtyp bleibt unbestimmt, vertreten durch eine Typvariable! Verwendung: konkretes Typargument ersetzt die Typvariable der Definition neuer Typ! Beispiel Knotenklasse:! Definition: Typvariable für Knoteninformation (statt Object)! Verwendung: Angabe eines konkretes (Referenz-)Typs für die Typvariable, fixiert Typ der Knoteninformation 7

Verwechslungsgefahr! Begrifflich ähnlich wie Argumente und Parameter bei Methodenaufrufen! Aber:! Methodenaufrufe werden zur Laufzeit abgewickelt (von der JVM),! Ersetzen von Typargumenten beim Übersetzen (vom Compiler)! Völlig verschiedene Mechanismen! 8

Begriffe! Generische Klasse = Klasse mit Typvariablen! Generischer Typ = Typangabe aus generischer Klasse + konkretem Typargument! 1 generische Klasse viele generische Typen! Interfaces in diesem Zusammenhang unter dem Begriff "Klasse" subsumiert 9

Definition und Anwendung! Typvariable! Typvariable im Rumpf! Generische Typen! Typprüfung! Generische Interfaces! Implementierung generischer Interfaces! Mehrere Typvariablen! Mehrere Typargumente 10

Typvariable! Definition einer generischen Klasse! normale, nicht-generische Klasse! Aber: Typvariable in spitzen Klammern nach dem Klassennamen: class Node<T> {...}! Typvariable = beliebiger Java-Identifier! Per Konvention einzelner Großbuchstabe in alphabetischer Nähe zum "T" 11

Typvariable im Rumpf! Im Klassenrumpf: Typvariable (weitgehend) wie konkreter Typ class Node<T> { private T info; private Node<T> left; private Node<T> right; }! Konstruktoren akzeptieren als Parameter nur gleiche Typvariablen (Knoten mit gleichen Typvariablen): Node(T i) { this(i, null, null); } Node(T i, Node<T> l, Node<T> r) { info = i; left = l; right = r; } 12

Typvariable im Rumpf (2)! Ergebnis der Getter und Parameter der Setter beziehen sich auf die Typvariable:... T getinfo() {...} Node<T> getleft() {...} Node<T> getright() {...} void setinfo(t i) {...} void setleft(node<t> l) {...} void setright(node<t> r) {...} 13

Generische Typen! "Anwendung" einer generischen Klasse: Konkretes Typargument für die Typvariable! Generische Klasse + Typargument = generischer Typ! Jeder generische Typ ist eigenständig, gleichrangig zu anderen Javatypen. Beispiel: String-Knoten Node<String> ns; ns = new Node<String>("foo");! In einem Programm verschiedene generische Typen derselben generischen Klasse erlaubt:... Node<Integer> ni; ni = new Node<Integer>(1); Node<Rational> nr; nr = new Node<Rational>(new Rational(2, 3)); 14

Typprüfung! Node<String> und Node<Integer> sind inkompatibel: Node<Integer> ni; ni = new Node<String>("foo"); // Typfehler! Nur Bäume mit Knoten desselben Typs konstruierbar: Node<Integer> ni = new Node<Integer>(1); Node<String> ns = new Node<String>("foo", ni, null); //Typfehler! Typecasts nicht mehr nötig: String s = ns.getinfo(); Node<String> l = ns.getleft(); // ohne Typecast! Compiler sichert korrekte Verwendung ab, keine Tests zur Laufzeit 15

Generische Interfaces! Generische Interfaces enstprechend zu generischen Klassen! Beispiel: Generisches Interface Taggable mit zwei Methoden zum! Anbringen einer Markierung (engl. "tag") und! Ablesen der Markierung! Definition: interface Taggable<T> { void settag(t tag); T gettag(); } 16

Implementierung generischer Interfaces! Nicht-generische Klasse kann generisches Interface durch Angabe eines Typarguments implementieren! Beispiel: class Someclass implements Taggable<String> { private String tag; public void settag(string t) {...} public String gettag() {...} }... 17

Implementierung generischer Interfaces (2)! Generische Klasse kann generisches Interface durch "Übergabe" der Typvariablen implementieren! Beispiel: class Node<T> implements Taggable<T> { private T tag; } public void settag(t t) {...} public T gettag() {...}...! Knoteninformation und Tag haben hier denselben Typ 18

Mehrere Typvariablen! Beliebig viele Typparameter einer generische Klasse! Beispiel: generische Klasse Pair verknüpft zwei Objekte class Pair<T, U> { private final T first; private final U second; }! Typvariablen T, U = unbekannte, unabhängige Typen class Pair<T, U> { Pair(T fst, U snd) { first = fst; second = snd; } T getfirst() { return first; } U getsecond() { return second; } } 19

Mehrere Typargumente! Generische Klasse mit mehreren Typvariablen mehrere Typargumente, eines für jede Typvariable Pair<String, Integer> psi;! Compiler verhindert Typfehler Pair<String, Integer> p; p = new Pair<String, Integer>("foo", 1); int i = p.getfirst(); // Fehler! int j = p.getsecond(); // ok! Generische Typen = vollwertige Typen --> selbst als Typargumente zulässig: Pair<Integer, Pair<String, Integer>> pp; pp = new Pair<Integer, Pair<String, Integer>>(23, p); int k = pp.getsecond().getsecond(); // ok 20

Typebounds! Idee! Beispiel! Mehrfache Typebounds! Beispiel! Typebounds mit Typvariablen! Problem 21

Typebounds: Idee! Generische Klasse akzeptiert (bisher) beliebige Typargumente! Oft sinnvoll: Einschränkung der Typargumente! Lösung: Typebound bei der Definition einer generischen Klasse: class Someclass<T extends U> {...}! Folge: spätere Typargumente müssen zum Typebound U kompatibel sein! "extends" hier für Klassen und Interfaces 22

Typebounds: Beispiel! Beispiel: Knoten mit ausschließlich numerischen Informationen: class Node<T extends Number> {...}! Number ist Basisklasse von Integer, Double etc., nicht aber von beispielsweise String, Object! Compiler lehnt unpassende Typargumente ab: Node<Integer> ni; // ok Node<Double> nd; // ok Node<Object> no; // Fehler! Node<String> ns; // Fehler! 23

Mehrfache Typebounds! Liste von Typebounds mehrfache Einschränkungen! Typvariablen müssen zu jedem Typebound kompatibel sein! Syntax: class Someclass<T extends U1 & U2 & U3...> {...}! Einschränkung:! Erster Typebound U1 darf ein beliebiger Typ sein! Weitere Typebounds U2, U3,... müssen Interfaces sein! Reihenfolge der weiteren Typebounds nach dem ersten irrelevant 24

Beispiel! Bäume sollen auf Streams geschrieben werden können müssen das Interface Serializable implementieren! Bäume sollen kopierbar sein müssen das Interface Cloneable implementieren! Gilt ebenso für Knoteninformation! Einfordern mit Typebounds: class Node<T extends Serializable & Cloneable> {...}! Knoten damit selbst serialisierbar und kopierbar: class Node<T extends Serializable & Cloneable> implements Serializable, Cloneable {...} 25

Typebounds mit Typvariablen! Beispiel: geordnete Bäume! Bezüglich jedes Knotens: alle Informationen im linken Teilbaum kleiner und alle Informationen im rechten Teilbaum größer oder gleich! Binärer Baum: 26

Binärer Baum! Voraussetzung: Knoteninformationen kann verglichen werden! Technisch: Knotentyp implementiert das Interface Comparable! Comparable ist ein generisches Interface! Definition einer generischen Knotenklasse für geordnete Bäume: class Node<T extends Comparable<T>> {...}! Compiler stellt Konsistenz sicher: Node<String> ns; // ok Node<Integer> ni; // ok Node<Object> no; // Fehler 27

Binärer Baum (2)! Lösung noch mangelhaft: Von Comparable abgeleitete Klasse wird nicht als Typargument akzeptiert! Beispiel: class Base implements Comparable<Base> {...} class Derived extends Base {...}... Node<Base> nb; // ok Node<Derived> nd; // Fehler! Problem: Typebound verlangt, dass das Typargument selbst direkt Comparable implementiert zu streng! Lösung: contravariante Wildcardtypen 28

Wildcardtypen! Motivation! Invarianz! Bivarianz! Covarianz! Contravarianz! Gegenüberstellung Varianzen! Varianzen und Objekte! Wozu Wildcardtypen? 29

Motivation! Kompatibilität eines Typs T zu einem Typ U (kurz T " U) heisst:! Werte vom Typ T können Variablen vom Typ U zugewiesen werden. T t =...; U u = t;! Kompatibilität zwischen Typen bisher:! Implizite Typkonversion: für bestimmte primitive Typen, zb int " double! Implementierung: Klasse zu Interface, einschließlich Arrays! Vererbung: Abgeleitete Klasse zu Basisklasse, zb String " Object, einschließlich Arrays! Autoboxing: Primitiver Typ zu Wrapperklasse, zb int " Integer! Auto-Unboxing: Wrapperklasse zu primitivem Typ, zb Integer " int! Generische Typen der gleichen generischen Klasse bisher inkompatibel! Mit Wildcardtypen Einführung von Kompatibilitäten mehr Flexibilität 30

Invarianz! Generische Typen der gleichen generischen Klasse bisher inkompatibel! Kompatibilität zwischen Typargumenten wird ignoriert! Beispiel: Integer ist kompatibel zu Number, aber Node<Integer> nicht kompatibel zu Node<Number> Number n = new Integer(23); // ok Node<Number> nn = new Node<Integer>(23); // Fehler! Bezeichnung als "Invarianz": Eine Variation des Typargumentes bzgl. der Vererbungshierarchie wird nicht auf die generischen Typen übertragen. 31

Bivarianz! Generischer Typ mit Wildcardzeichen "?" als Typargument = Wildcardtyp! Syntax: C<?>! Beispiel: Node<?> nx;! Wildcardtyp erlaubt zur Definition von Variablen, nicht zu Instanziierung von Objekten (siehe Interfaces und ABCs)! Beispiel: Node<?> nx; nx = new Node<?>(); // Fehler! 32

Kompatibilität! Jeder generische Typ derselben generischen Klasse ist kompatibel zum Wildcardtyp! Allgemein (" heißt "ist kompatibel zu"):! C<A> " C<?>! für jedes A! Beispiel: Node<?> nx; nx = new Node<String>("foo"); nx = new Node<Integer>(1); nx = new Node<Double>(3.14);! Bezeichnung als Bivarianz Zu einem Wildcardtyp sind alle generischen Typen der gleichen generischen Klasse kompatibel. 33

Ähnlichkeit zur Ableitung! Kompatibilität konkreter generischer Typ " Wildcardtyp ist asymmetrisch: Node<?> nx;... Node<String> ns = nx; // Fehler! Verhältnis formal ähnlich wie Ableitung:! konkreter generischer Typ " Wildcardtyp! abgeleitete Klasse " Basisklasse 34

Anwendung! Wildcardtypen sinnvoll, wenn das konkrete Typargument keine Rolle spielt! Beispiel: Methode nodescount zum Zählen der Knoten in einem Baum! Inhalt der Knoten irrelevant, nur Baumstruktur wichtig class Util { int nodescount(node<?> n) { if(n == null) return 0; else return 1 + nodescount(n.getleft()) + nodescount(n.getright()); }... } 35

Einschränkungen! Compiler kennt konkreten Typ des Wildcardargumentes nicht! Kein lesender Zugriff mit konkretem Typargument: Node<?> nx;... Integer i = nx.getinfo(); // Fehler! Kein schreibender Zugriff mit konkretem Typargument: Node<?> nx;... nx.setinfo(1); // Fehler! Das tatsächliche, konkrete Typargument zur Laufzeit spielt keine Rolle: Node<?> nx; nx = new Node<Integer>(23); Integer i = nx.getinfo(); // Fehler nx.setinfo(1); // Fehler 36

Begrenzte Zugriffe! Compiler kennt das Typargument zur Laufzeit nicht! Jeder Referenztyp ist kompatibel zu Object Lesen als Object immer möglich: Node<?> nx;... Object x = nx.getinfo(); // ok! null ist kompatibel zu jedem Referenztyp => Schreiben von null immer möglich: Node<?> nx;... nx.setinfo(null); // ok 37

Covarianz! Wildcard? führt zu Kompatibilität mit generischen Typen aller Typargumente! Einschränken auf bestimmte Typargumente mit Typebound! Syntax: C<? extends B>! Nur generische Typen kompatibel, deren Typargument zu B kompatibel ist! Beispiel: Node<? extends Number> n; n = new Node<Integer>(23); // ok n = new Node<Object>(new Object()); // Fehler 38

Covarianz: Kompatibilität! Bezeichnung als "Covarianz": Die Kompatibilität der generischen Typen folgt der Kompatibilität des Typargumentes.! Allgemein (""" heißt "ist kompatibel zu"):! C<A> " C<? extends B>! wenn A " B! Typebound B = "Upper-Typebound": Aus Sicht einer Vererbungshierarchie die "Obergrenze" für konkrete Typargumente 39

Covariante Arrays! Arrays verhalten sich covariant:! A[] " B[]! wenn A " B! Problem: Lücke im statischen Typsystem! Number[] a = new Integer[23]; a[0] = new Double(3.14); // ArrayStoreException! Ohne weitere Schutzmassnahmen: Fehler übertragen auf covariante Wildcardtypen: Node n = new Node(23); n.setinfo(3.14); //?? 40

Gesperrte Schreibzugriffe! Schutz gegen Lücke im statischen Typsystem: Keine schreibenden Zugriffe über covariante Wildcardtypen. Z.B! Beispiel: Node<? extends Number> n;... n.setinfo(1); // Schreiben - unzulässig! Ratio: "? extends Number" ist irgendein zu Number kompatibler Typ, vielleicht Byte; Integer muss zu diesem Typ nicht kompatibel sein! Ausnahme: null passt zu jedem Referenztyp, wird immer akzeptiert Node<? extends Number> n;... n.setinfo(null); // Schreiben von null - ok 41

Gesperrte Schreibzugriffe (2)! Lesender Zugriff kein Problem: Node<? extends Number> n;... Number x = n.getinfo(); // Lesen - ok! Ratio: Welcher konkrete Typ sich immer hinter "? extends Number" verbirgt, er ist mit Sicherheit kompatibel zu Number 42

Beispiel Covarianz! Methode copyfrom der generischen Klasse Node<T>: Erwartet einen anderen Knoten als Parameter, kopiert dessen Information in den eigenen Knoten! Information im eigenen Knoten hat Typ T, kann ein Objekt vom Typ T oder einem dazu kompatiblen Typ aufnehmen! Parameter von copyfrom: Wildcard mit T als Upper- Typebound! Definition von copyfrom: class Node<T> {... void copyfrom(node<? extends T> other) { info = other.getinfo(); } } 43

Beispiel Covarianz (2)! Aufruf von copyfrom: Node<Number> n; Node<Integer> i;... n.copyfrom(i); i.copyfrom(n); // ok // Fehler 44

Contravarianz! Einschränkung des Typarguments! Neue Form der Einschränkung auf Basisklassen! Syntax: C<? super B>! Nur generische Typen kompatibel, zu deren Typargument B kompatibel ist (Vorsicht: Verwechslungsgefahr)! Beispiel: Node<? super Number> n; n = new Node<Integer>(23); // Fehler n = new Node<Object>(new Object()); // ok 45

Contravarianz: Definition! Contravarianz: Die Kompatibilität der generischen Typen läuft der Kompatibilität des Typargumentes entgegen.! Allgemein (""" heißt "ist kompatibel zu"):! C<A> " C<? extends B>! wenn A # B! Typebound B = Lower-Typebound: Aus Sicht einer Vererbungshierarchie die "Untergrenze" für konkrete Typargumente 46

Gesperrte Lesezugriffe! Keine lesenden Zugriffe über contravariante Wildcardtypen, zb Node<? super Number> n;... Number x = n.getinfo(); // Lesen - unzulässig! Ratio: "? super Number" ist Number selbst oder irgendeine Basisklasse von Number. Der Typ kann nicht einfach als Number behandelt werden.! Ausnahme: An Object kann jeder Referenztyp zugewiesen werden: Node<? super Number> n;... Object x = n.getinfo(); // Lesen als Object - ok 47

Gesperrte Lesezugriffe (2)! Schreibender Zugriff unproblematisch Node<? extends Number> n;... n.setinfo(1); // Schreiben - ok! Ratio: Was immer sich hinter "? extends Number" verbirgt, eine Number kann mit Sicherheit zugewiesen werden 48

Beispiel Contravarianz! Methode copyto der generischen Klasse Node<T>: Erwartet einen anderen Knoten als Parameter, kopiert die eigene Information in den anderen Knoten! Information im eigenen Knoten hat Typ T, kann in jeden fremden Knoten geschrieben werden, der auch den Typ T oder eine Basisklasse davon hat! Parameter von copyto: Wildcard mit T als Lower- Typebound! Definition von copyto: class Node<T> {... void copyto(node<? super T> other) { other.setinfo(info); } } 49

Beispiel Contravarianz (2)! Aufruf von copyto: Node<Number> n; Node<Integer> i;... n.copyto(i); i.copyto(n); // Fehler // ok 50

Knoten geordneter Bäume class Node<T extends Comparable<T>> {...}! Von Comparable abgeleitete Klasse wird nicht als Typargument akzeptiert --> Lösung: Irgendeine Basisklasse des Typarguments muss Comparable implementieren: class Node<T extends Comparable<? super T>> {...}! Beispiel: class Base implements Comparable<Base> {...} class Derived extends Base {...}... Node<Base> nb; // ok Node<Derived> nd; // ok 51

Varianzen: Gegenüberstellung! Vier Arten der Varianz: 52

Varianzen und Objekte! Varianz: Einschränkungen für Variablen, nicht Objekte! Beispiel: Node<Integer> i = new Node<Integer>(23);! Zuweisen an covarianten Wildcardtyp kein schreibender Zugriff über diese Variable: Node<? extends Number> n = i; n.setinfo(24); // Fehler! Knoten selbst nicht betroffen: i.setinfo(24); // ok 53

Wozu Wildcardtypen?! Mit Wildcardtypen flexiblerer Code! Methoden mit Parametern von Wildcardtypen akzeptieren Argumente vieler unterschiedlicher generischer Typen! Nachteil: Compiler muss Einschränkungen auferlegen, um die statische Typprüfung durchzuhalten! Ohne lückenlose statische Typprüfung: Fehlerfrei übersetztes Programm kann zur Laufzeit mit Typfehler abstürzen 54

Kontrollfragen! Wie werden in Java Generics spezifiziert?! Was ist der Unterschied zwischen Generics und Inheritance? Was passiert zur Laufzeit?! Was ist der Unterschied zwischen einer Generics und einem Interface?! Was ist ein Wildcardtyp?! Was ist eine Varianz und welche 4 Arten werden unterschieden? 55

Zusammenfassung! Generische Klasse = Klasse mit Typvariablen! Generischer Typ = Generische Klasse + Typargument! 1 generische Klasse viele generische Typen! Jeder generische Typ ist eigenständig, gleichrangig zu anderen Javatypen 56