Einführung in die Programmierung

Ähnliche Dokumente
Überblick. Peer Kröger (LMU München) Einführung in die Programmierung WS 16/ / 861

Abschnitt 10: Typisierte Klassen

Einleitung Typsystem Typisierung Zusammenfassung Literatur. Typisierung. Effiziente Programmierung. Thomas Schnieders

Realisierungsmöglichkeiten für parametrische Polymorphie

Einstieg in die Informatik mit Java

Die abstrakte Klasse Expression:

12 Abstrakte Klassen, finale Klassen und Interfaces

Faulheit professionell: Fertige Datenbehälter. Das Java-Collections-Framework Typsicherheit Generische Klassen

1 Einleitung Generizität Syntax... 2

Johannes Unterstein - TINF16 - Java - Sommersemester 2017 JAVA. Weiterführende Spracheigenschaften

4. Vererbung Die Klasse Object. Die Klasse Object

1 Abstrakte Klassen, finale Klassen und Interfaces

Objektorientierte Programmierung

Programmieren in Java

Kapitel 8. Programmierkurs. Methoden. 8.1 Methoden

Vererbung, Polymorphie

Vererbung. Gerd Bohlender. Institut für Angewandte und Numerische Mathematik. Vorlesung: Einstieg in die Informatik mit Java 23.5.

Generisches Programmieren. Generisches Programmieren

Institut für Programmierung und Reaktive Systeme. Java 7. Markus Reschke

Neben der Verwendung von Klassen ist Vererbung ein wichtiges Merkmal objektorientierter

Einstieg in die Informatik mit Java

Javakurs für Anfänger

JAVA 5 Generics. Proseminar Programmiersprachen Thema Java 5 Generics 1

Vorkurs Informatik WiSe 15/16

Die Klasse java.lang.object. Thorsten Treffer

15 Unified Modeling Language (UML) 7 UML und Java Informatik 2 (SS 07) 595

II.4.5 Generische Datentypen - 1 -

Einfache Liste: Ein Stapel (Stack) Ansatz. Schaubild. Vorlesung 1. Handout S. 2. Die einfachste Form einer Liste ist ein Stapel (stack).

Programmieren 2 16 Java Collections und Generizität

Vererbung. Gerd Bohlender. Institut für Angewandte und Numerische Mathematik. Vorlesung: Einstieg in die Informatik mit Java 14.1.

Java Vererbung. Inhalt

Kapitel 13. Abstrakte Methoden und Interfaces. Fachgebiet Knowledge Engineering Prof. Dr. Johannes Fürnkranz

Java für Bauingenieure

Algorithmen und Datenstrukturen

14 Abstrakte Klassen, finale Klassen, Interfaces

Objektorientierte Programmierung. Kapitel 22: Aufzählungstypen (Enumeration Types)

14 Abstrakte Klassen, finale Klassen, Interfaces. Auswertung von Ausdrücken. Beispiel. Abstrakte Methoden und Klassen

Programmieren in Java

Java Einführung Vererbung und Polymorphie. Kapitel 13

Kapitel 9. Programmierkurs. Attribute von Klassen, Methoden und Variablen. 9.1 Attribute von Klassen, Methoden und Variablen

14 Abstrakte Klassen, finale Klassen, Interfaces

Kapitel 4. Programmierkurs. Datentypen. Arten von Datentypen. Wiederholung Kapitel 4. Birgit Engels, Anna Schulze WS 07/08

Einstieg in die Informatik mit Java

Javakurs für Anfänger

1. Abstrakte Klassen

Neuere Sprachelemente in Java

Javakurs für Anfänger

OOP und Angewandte Mathematik. Eine Einführung in die Anwendung objektorientierter Konzepte in der angewandten Mathematik

Kapitel 5: Interfaces

Beuth Hochschule Parameter-Übergabe-Mechanismen WS17/18, S. 1

II.4.4 Exceptions - 1 -

Th. Letschert OOP 2 1. Vererbung I : Subklasse und Subtyp

Prozeduren vs. Funktionen

9. Kapitel GENERICS. Techniken der Programmentwicklung Prof. Dr. Wolfgang Schramm

Vorlesung Datenstrukturen

II.4.4 Exceptions - 1 -

Polymorphismus 44. Function.hpp. #include <string>

Einführung in die Programmierung

Polymorphie. 15. Java Objektorientierung II

TECHNISCHE UNIVERSITÄT MÜNCHEN FAKULTÄT FÜR INFORMATIK

Objektorientierte Programmierung Studiengang Medieninformatik

Informatik I Das Typsystem (am Bsp. Python vs. C++)

Polymorphie. 15. Java Objektorientierung II

Klassen und ihre Beziehungen II: Einfache Vererbung und Abhängigkeit

Implementieren von Klassen

Einführung in C# Teil 3. Matthias Nübling

Informatik I Das Typsystem (am Bsp. Python vs. C++)

Interfaces und Generics

TU München, Fakultät für Informatik Lehrstuhl III: Datenbanksysteme Prof. Alfons Kemper, Ph.D.

7. Schnittstellen Grundlagen zu Schnittstellen. 7. Schnittstellen

Weitere Beispiele. Beispiel CD-Spieler: Exemplare eines abstrakten Konzepts. 7. Schnittstellen. Schnittstelle: Syntax

Delegaten. d. h. eine Tätigkeitsanforderung wird weitergeleitet

Objektorientierte Programmierung mit C++ SS 2007

Programmieren in Java

Institut für Programmierung und Reaktive Systeme 2. Februar Programmieren I. Übungsklausur

Einstieg in die Informatik mit Java

Methoden und Wrapperklassen

Polymorphismus 179. Function.h. #include <string>

Algorithmen und Datenstrukturen. Übersicht. Interfaces und Generics. InsertionSort für Punkte. InsertionSort für Punkte

IT I: Heute. Nachbetrachtung Wissensüberprüfungen. Einführung Vererbung. Roboter in becker.robots. falls Zeit: Scheduling 8.11.

Vererbung und Polymorphie

Programmieren 2 Java Überblick

Vorausgesetzte Grundkenntnisse. Inhalt. Klassenhierarchie und Vererbung. Vererbung. Klassenhierarchie und Vererbung. Einführung in C# Teil 3

Programmieren 1 09 Vererbung und Polymorphie

Algorithmen und Programmierung II

Prof. Dr. Wolfgang Schramm. Vorlesung. Techniken der Programmentwicklung. Exkurs: Anonyme Klassen

Programmieren in Java

Informatik II Übung 6

Vererbung. Martin Wirsing. Ziele. Vererbung

Erste Java-Programme (Java Wiederholung & Vererbung)

Dynamische Typinformation A01 OOP. Dynamische Typinformation

Skript Informatik B. Grundlagen der Software-Entwicklung

Institut für Programmierung und Reaktive Systeme. Java 6. Markus Reschke

Grundzüge der Programmierung. Wiederverwendung VERERBUNG

Transkript:

Einführung in die Programmierung Teil 10: Typsicherheit durch generische Typen Prof. Dr. Peer Kröger, Florian Richter, Michael Fromm Wintersemester 2018/2019

Übersicht 1. Grundlagen 2. Typvariablen 3. Grenzen der Typ-Polymorphie durch Vererbung 4. Typvariablen und generische/typisierte Klassen 5. Vererbung bei typisierten Klassen

Kapitel 1: Grundlagen i 1. Grundlagen 2. Typvariablen 3. Grenzen der Typ-Polymorphie durch Vererbung 4. Typvariablen und generische/typisierte Klassen 5. Vererbung bei typisierten Klassen Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 1. Grundlagen 3

Grundlegendes zu Typsystemen Was würde passieren, wenn wir für zwei Objekte vom Typ String den Operator && ausführen würden? In Java verhindert der Compiler, dass dieser Code überhaupt übersetzt wird, ansonsten gäbe es zur Laufzeit einen Fehler (was schlecht wäre Warum?). Um dies festzustellen, besitzt Java (wie die meisten höheren Programmiersprachen) ein Typsystem. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 1. Grundlagen 4

Grundlegendes zu Typsystemen Ein Typsystem ist eine Komponente einer Programmiersprache, die den Wertebereich von Variablen und den Bildbereich von Methoden einschränkt. Programmiersprachen mit Typsystem nennt man typisiert. Wesentliche Aufgabe ist es, durch Typisierung sicher zu stellen, dass auf den Inhalten von Variablen keine Operationen ausgeführt werden, die syntaktisch oder semantisch fehlerhaft sind (siehe unten). Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 1. Grundlagen 5

Grundlegendes zu Typsystemen Wichtige Bestandteile von Typsystemen sind: Die Typen selbst, die entweder mittels Typ-Definitionen (in Java: Klassen) erzeugt oder in der jeweiligen Sprache fest integriert sind (in Java: primitive Datentypen). Die Möglichkeit, Programmelemente (wie Variablen, Methodenparameter usw.) durch Deklaration an einen bestimmten Typ zu binden. Regeln, nach denen die Werte von Ausdrücken einem bestimmten Typ zugeordnet werden. Regeln zur Prüfung der Zuweisungskompatibilität von Typen. Optional weitere Sprachbestandteile wie typbezogene Operatoren (z.b. der instanceof-operator in Java) zur Ermittlung und Prüfung von Typinformation zur Laufzeit. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 1. Grundlagen 6

Grundlegendes zu Typsystemen Wesentliche Aufgaben von Typsystemen: Erkennung von Typverletzungen bei der Übersetzung und Ausführung: Mit der Typinformation kann verhindert werden, dass Variablen Werte zugewiesen werden, welche die betreffende Variable niemals annehmen sollte (sogenannte Typinvarianten). So wird die Ausführung von Operationen auf den Inhalten dieser Variablen, die entweder unmöglich oder nicht sinnvoll ist, verhindert. Typumwandlung (Type Conversion). In vielen Sprachen stehen hierfür explizite Operationen zur Verfügung. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 1. Grundlagen 7

Das Typsystem von Java Eigenschaften des Typsystems von Java 1 : Starke Typisierung, d.h. die Typen werden streng unterschieden, Datentypen können umgewandelt werden, implizit aber nur ohne Informationsverlust; unsichere Typumwandlung ist zwar erlaubt, aber nur mit explizitem Typcast-Operator. Statische Typisierung, d.h. Typprüfung zur Übersetzungszeit (Achtung Ausnahme: Polymorphismus im Zusammenhang mit Vererbung!!!) Explizite Typisierung, d.h. Typen werden explizit benannt und nicht per type inference abgeleitet. 1 Die Kriterien sind nicht binär sondern eher fließend. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 1. Grundlagen 8

Das Typsystem von Java Tatsächlich ist Java daher so gut wie typsicher, d.h. der Compiler kann Typverletzungen bereits zur Übersetzungszeit feststellen. Eine wichtige (und manchmal lästige Ausnahme) stellt die Polymorphie dar, wie wir in diesem Kapitel diskutieren werden. Das eigentlich sehr schöne Konzept der Polymorphie ist nicht generell böse, es hat nur bzgl. Typsicherheit eine Schwäche um die wir uns wie gesagt nun kümmern. Es gibt i.ü. auch nicht typisierte Sprachen, ein prominentes oo Beispiel ist Python. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 1. Grundlagen 9

Kapitel 2: Typvariablen i 1. Grundlagen 2. Typvariablen 3. Grenzen der Typ-Polymorphie durch Vererbung 4. Typvariablen und generische/typisierte Klassen 5. Vererbung bei typisierten Klassen Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 10

Polymorphie mit Typvariablen Wir haben das Konzept der Polymorphie im Zusammenhang mit Vererbung kennengelernt: Eine Methode, die Objekte der Klasse A als Parameter übergeben bekommen kann, kann auch Objekte jeder Unterklasse von A als Parameter übergeben bekommen. Manchmal kann es wünschenswert sein, eine Methode (oder Klasse) zwar allgemein zu definieren, beim Verwenden aber sicher zu sein, dass sie jeweils nur mit einem ganz bestimmten Typ verwendet wird (d.h. typsicher ist). Lösung: Man führt eine Typvariable ein. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 11

Polymorphie mit Typvariablen Variablen, die wir in Programmen bisher gesehen haben, sind Variablen, die verschiedene Werte annehmen können, aber nicht verschiedene Typen (außer vererbungs-polymorphe Typen). Eine Typvariable hat als Wert einen Typ. Der Typ einer Typvariablen ist der Typ aller Typen, in Java auch als class bezeichnet. Vergleich: Typ Wert ein beliebiger Wert des Typs (z.b. auch ein beliebiger, aber fester Variable ein Objekt der Klasse) A (oder einer Typ A Unterklasse) Typvariable class eine beliebige Klasse Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 12

Intuition von Typvariablen Das Konzept der Typvariablen kennen wir natürlich: In der Definition von Eigenschaften zweistelliger Relationen wurde eine Typvariable verwendet: R M M Hier steht M für eine beliebige Menge. Wichtig ist aber, dass R Teilmenge des zweistelligen Kreuzproduktes derselben Menge ist. Eigenschaften von Funktionen wurden abstrakt für die Menge D als Definitionsbereich und die Menge B als Bildbereich definiert D und B sind wiederum Typvariablen. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 13

Intuition von Typvariablen Auch das Überladen von Operatoren kann mit Typvariablen beschrieben werden, z.b.: Arithmetische Operatoren: S S S mit S {byte,short,int,... Vergleichsoperatoren: S S boolean mit S {byte,short,int,... In all diesen Fällen beschreiben wir mit Hilfe der Typvariablen die abstrakte Syntax. Die Syntax legt bereits fest, dass mit jedem Vorkommen derselben Typvariablen S der selbe Typ bezeichnet wird. Die Semantik (Bedeutung) kommt zustande durch Belegung der Typvariable mit einem konkreten Wert (d.h. einem bestimmten Typ). Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 14

Keine Typ-Inferenz in Java für Variablen Es gibt streng typisierte Sprachen mit automatischer Typ-Inferenz (dies wird in der Vorlesung des zweiten Semesters genauer studiert). In einer Deklaration wie z.b. fun f(a,b,c) = if a(b) then b else c+1; kann der Interpreter der Sprache (hier: SML) die Typen der vorkommenden Variablen ableiten, der Programmierer muß sie nicht explizit angeben: val f = fn : (int -> bool) * int * int -> int In Java muß der Typ jeder vorkommenden Variablen explizit festgelegt werden. Java erlaubt grundsätzlich keine Typ-Inferenz für Variablen. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 15

Erinnerung: Überladen von Methoden Eine Art Polymorphie ist das Überladen von Methoden (gleiche Namen aber unterschiedlichen Parameter-Typen): public static void methode(object o) { System.out.println("01"); public static void methode(tier t) { System.out.println("02"); public static void methode(schaf s) { System.out.println("03"); Diese drei Methoden sind unterschiedlich, denn sie haben eine unterschiedliche Signatur! Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 16

Inferenz der richtigen Methode Anhand des (Laufzeit-)Typs eines Parameters kann JRE entscheiden welche Methode aufgerufen wird: Schaf s = new Schaf(); Object o = (Object) s; Tier t = (Tier) s; methode(o); methode(t); methode(s); Ausgabe: 01 02 03 Sie sehen hier übrigens eine Variante der Vererbung, die wir so noch nicht genau besprochen haben: Man kann (mit explizitem Typcast) Objekte entlang ihrer Vererbungshierarchie vom spezielleren Typ zum generischeren Typ casten. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 17

Abgrenzung: Polymorphie von Methoden Eine andere Art der Polymorphie ist das Überschreiben von Objekt-Methoden in Unterklassen. Hier wird der tatsächliche Typ des Objektes (zur Laufzeit) bestimmt und die entsprechende Methode verwendet: public class Tier { public String tostring() { return "Tier"; public class Schaf extends Tier { public String tostring() { return "Schaf"; Schaf s = new Schaf(); Object o = (Object) s; Tier t = (Tier) s; System.out.println(o.toString()); // Ausgabe: Schaf System.out.println(t.toString()); // Ausgabe: Schaf System.out.println(s.toString()); // Ausgabe: Schaf Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 18

Überladene Methoden: Auswahl Bei überladenen Methoden entscheidet der Compiler für eine gegebene (deklarierte) aktuelle Parametrisierung welche Methode für diese Parametrisierung die Spezifischste ist. Dies ist ähnlich zur Auswahl der spezifischsten Objekt-Methode bei polymorphen Variablen. Diese spezifischste Methode wird jeweils ausgeführt. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 19

Überladene Methoden: Auswahl Beispiel: public static void methode(object o) { System.out.println("01"); public static void methode(tier t) { System.out.println("02"); public static void methode(schaf s) { System.out.println("03"); Schaf s = new Schaf(); methode(s); // Ausgabe: 03 Obwohl der Parameter s nicht nur vom Typ Schaf, sondern (aufgrund der Vererbung) auch vom Typ Tier und Object ist, wird die dritte Methode verwendet, die Spezifischste für den aktuellen Parameter. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 2. Typvariablen 20

Kapitel 3: Grenzen der Typ-Polymorphie durch Vererbung i 1. Grundlagen 2. Typvariablen 3. Grenzen der Typ-Polymorphie durch Vererbung 4. Typvariablen und generische/typisierte Klassen 5. Vererbung bei typisierten Klassen Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 3. Grenzen der Typ-Polymorphie durch Vererbung 21

Typ-Polymorphie durch Vererbung DATABASE SYSTEMS GROUP 10.2 Polymorphie: Revisited 10.2.2 Typ-Polymorphie Wie wir gesehen haben, ermöglicht Vererbung Polymorphie. Wie wir gesehen haben, ermöglicht Vererbung Polymorphie. Gegeben folgendes Beispiel: Gegeben folgendes Beispiel: Tier Stall + setbewohner(tier) + getbewohner( ) : Tier Schaf Kuh Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 3. Grenzen der Typ-Polymorphie durch Vererbung 22

Typ-Polymorphie durch Vererbung Eine Klasse Stall wurde in diesem Beispiel für Objekte vom Typ Tier entworfen. public class Tier {... public class Stall { private Tier bewohner; public void setbewohner(tier tier) { this.bewohner = tier; public Tier getbewohner() { return this.bewohner; Welche Probleme können bei dieser Modellierung auftreten? Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 3. Grenzen der Typ-Polymorphie durch Vererbung 23

Typ-Polymorphie durch Vererbung Der Stall kann jedes beliebige Objekt, das vom Typ Tier oder vom Typ einer Unterklasse von Tier ist, aufnehmen: public class Schaf extends Tier {... public static void main(string[] args) { Stall schafstall = new Stall(); schafstall.setbewohner(new Schaf()); Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 3. Grenzen der Typ-Polymorphie durch Vererbung 24

Grenzen der Typ-Polymorphie durch Vererbung Problem Wenn man das Tier wieder aus dem Stall führt, weiß der Stall nicht mehr, was für ein Tier es ist: public static void main(string[] args) { Stall schafstall = new Stall(); schafstall.setbewohner(new Schaf());... Tier bewohner = schafstall.getbewohner(); Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 3. Grenzen der Typ-Polymorphie durch Vererbung 25

Grenzen der Typ-Polymorphie durch Vererbung Lösung ohne generische Typen Der Programmierer merkt es sich und führt einen expliziten Typecast durch: public static void main(string[] args) { Stall schafstall = new Stall(); schafstall.setbewohner(new Schaf());... Schaf schaf = (Schaf) schafstall.getbewohner(); Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 3. Grenzen der Typ-Polymorphie durch Vererbung 26

Grenzen der Typ-Polymorphie durch Vererbung Das ist bestenfalls lästig für den Programmierer (häufige Typecasts). Das ist aber auch überaus fehleranfällig (v.a. bei vielen Programmiereren), da die Typüberprüfung erst zur Laufzeit stattfindet: public class Kuh extends Tier {...... // Code Fragment Stall stall = new Stall(); stall.setbewohner(new Schaf()); // Code an entfernter Stelle (anderer Programmierer) stall.setbewohner(new Kuh()); // wiederum andere Stelle (gueltiger Code!) Schaf schaf = (Schaf) stall.getbewohner(); // RuntimeException: // ClassCastException Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 3. Grenzen der Typ-Polymorphie durch Vererbung 27

Kapitel 4: Typvariablen und generische/typisierte Klassen i 1. Grundlagen 2. Typvariablen 3. Grenzen der Typ-Polymorphie durch Vererbung 4. Typvariablen und generische/typisierte Klassen 5. Vererbung bei typisierten Klassen Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 28

Typ-Polymorphie durch typisierte Klassen In diesem Kapitel lernen wir eine neuere Lösung kennen, die mit Version 5.0 in Java eingeführt wurde: Polymorphie wird nicht nur durch Vererbung, sondern auch durch generische Klassen ermöglicht (Generics). Das ist nicht nur bequemer, sondern ermöglicht die Typüberprüfung normalerweise bereits zur Übersetzungszeit. Eine generische Klasse ist allgemein für variable Typen implementiert die Typen können bei der Verwendung der Klasse festgelegt werden, ohne dass die Implementierung verändert werden muss. Beide Konzepte der Polymorphie können auch gleichzeitig verwendet werden. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 29

Generische Klassen Beispiel: Die Klasse Stall wird durch Einführen einer Typvariablen generisch gehalten: public class Stall<T> // Typvariable: T { private T bewohner; public void setbewohner(t tier) { this.bewohner = tier; public T getbewohner() { return this.bewohner; Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 30

Typisierte Klassen Im Gebrauch wird die Klasse durch Belegen der Typvariable mit einem bestimmten Typ typisiert (man spricht dann von einem parametrisierten Typ):... Stall<Schaf> stall = new Stall<Schaf>();... Die Typvariable T wird hier für das Objekt stall mit Schaf substituiert, d.h. überall in der Definition von Stall steht beim Objekt stall nun T fuer Schaf. Folgendes Fragment ist also erlaubt: stall.setbewohner(new Schaf()); Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 31

Typisierte Klassen Das folgende Fragment ist aber nicht mehr erlaubt: stall.setbewohner(new Kuh()); Es führt zu einem Kompilierfehler: // The method setbewohner(schaf) in the type Stall<Schaf> // is not applicable for the arguments (Kuh) Beim Herausnehmen (Getter) ist nun kein Cast mehr nötig, da der Rückgabetyp T also Schaf ist: Schaf schaf = stall.getbewohner(); Die Gefahr der Runtime-Exception wegen dem Typ-Cast ist gebannt und folgendes Konstrukt ist natürlich auch nicht mehr möglich: Kuh muh = stall.getbewohner(); denn auch das würde der Compiler nicht akzeptieren. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 32

Erinnerung: Parameter bei Methoden Die Einführung einer Typvariablen bei der Definition der generischen Klasse Stall erinnert ein wenig an Parameter bei Methoden. public class Streckenberechnung { public static double strecke(double m, double t, double k) { return 0.5 * k/m * (t * t); public static void main(string[] args) { System.out.println(strecke(2.3, 42, 17.5)); Die Berechnungsvorschrift der Methode strecke wird abstrakt mit den formalen Parametern (m,t,k) definiert. Die konkrete Berechnung wird aber mit Werten durchgeführt, die den Parametern zugewiesen werden (den aktuellen Parametern), d.h. die formalen Parameter werden durch diese Werte substituiert. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 33

Generische Klassen Entsprechend ist der Typparameter bei Definition der Klasse ein formaler Typparameter. public class Stall<T> { // Typvariable: T (formaler Typ-Parameter) private T bewohner;... public T getbewohner() { return this.bewohner; Konkreter Gebrauch der Klasse durch Belegen der Typvariable mit einem bestimmten Typ (aktuelle Typparameter): Stall<Schaf> stall = new Stall<Schaf>(); // aktueller Typ-Parameter: Schaf Dadurch Typsicherheit (u.a. ist auch Typprüfung möglich): Schaf schaf = stall.getbewohner(); Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 34

Syntax für generische Typen Deklaration einer generischen Klasse: class <Klassenname> < <Typvariable(n)> > Instantiierung eines generischen Typs (= Typisierung der Klasse, Parametrisierung des Typs): <Klassenname> < <Typausdruck/Typausdruecke> > Beispiele für Instantiierungen von Stall<T>: Stall<Tier> Stall<Schaf> Stall<Kuh> Stall<Schaf,Kuh> //ungueltig: zu viele Parameter Stall<String> //gueltig, aber unerwuenscht Stall<int> //ungueltig (Warum???) Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 35

Syntax für generische Typen Eine generische Klasse kann also auch mit mehreren Typ-Parametern definiert werden public class TripelStall<S, T, U> { private S ersterbewohner; private T zweiterbewohner; private U dritterbewohner;... Beispiele für Instantiierungen von TripleStall<S, T, U>: Stall<Tier, Tier, Tier> Stall<Kuh, Kuh, Kuh> Stall<Tier, Schaf, Kuh> Stall<Kuh, Schaf, Kuh> Stall<Schaf, Kuh, Kuh, Tier> //ungueltig: zu viele Parameter Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 36

Übersetzung von generischen Typen Zur Übersetzung von generischen Typen gibt es grundsätzlich zwei Möglichkeiten: Heterogene Übersetzung: Für jede Instantiierung (Stall<Tier>, Stall<Schaf>, Stall<Kuh> etc.) wird individueller Byte-Code erzeugt, also drei unterschiedliche (heterogene) Klassen. Homogene Übersetzung: Für jede parametrisierte Klasse (Stall<T>) wird genau eine Klasse erzeugt, die die generische Typinformation löscht (type erasure) und die Typ-Parameter durch die Klasse Object ersetzt; für jeden konkreten Typ werden zusätzlich Typanpassungen in die Anweisungen eingebaut. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 37

Übersetzung von generischen Typen Java nutzt die homogene Übersetzung (C++ die Heterogene). Der Byte-Code für eine generische Klasse entspricht also in etwa dem Byte-Code einer Klasse, die nur Typ-Polymorphie durch Vererbung benutzt. Gewonnen hat man aber die Typ-Sicherheit zur Übersetzungszeit. Vorteil/Nachteil der homogenen Übersetzung: + weniger erzeugter Byte-Code, Rückwärtskompatibilität geringere Ausdrucksmächtigkeit der Typüberprüfung zur Übersetzungszeit Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 38

Verwendung generischer Typen ohne Typ-Parameter Generische Klassen können auch ohne Typ-Parameter verwendet werden. Ein generischer Typ ohne Typangabe heißt Raw-Type und bietet die gleiche Funktionalität wie ein parametrisierter Typ, allerdings werden die Parametertypen nicht zur Übersetzungszeit überprüft. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 39

Verwendung generischer Typen ohne Typ-Parameter Beispiel: Raw-Type von Stall<T> ist Stall Stall<Schaf> schafstall = new Stall<Schaf>(); Stall stall = new Stall(); stall = schafstall; stall.setbewohner(new Kuh()); // Warnung: // Type safety: The method setbewohner(tier) // belongs to the raw type Stall. // References to generic type Stall<T> // should be parameterized // Die Warnung ist gerechtfertigt, denn: Schaf poldi = schafstall.getbewohner(); // ist gueltiger Code, der aber zu einer // RuntimeException (ClassCastException) fuehrt Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 4. Typvariablen und generische/typisierte Klassen 40

Kapitel 5: Vererbung bei typisierten Klassen i 1. Grundlagen 2. Typvariablen 3. Grenzen der Typ-Polymorphie durch Vererbung 4. Typvariablen und generische/typisierte Klassen 5. Vererbung bei typisierten Klassen Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 5. Vererbung bei typisierten Klassen 41

Unterklassen von generischen Klassen Von generischen Klassen lassen sich in gewohnter Weise Unterklassen ableiten: public class SchafStall extends Stall<Schaf> {... Dabei kann der Typ der Oberklasse weiter festgelegt werden (in diesem Beispiel wird die Oberklasse typisiert). Die Unterklasse einer generischen Klasse kann auch selbst wieder generisch sein: public class GrossviehStall<T> extends Stall<T> {... Die Unterklasse kann auch einen weiteren Typ einführen: public class DoppelStall<T, S> extends Stall<T> { private S zweiterbewohner;... Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 5. Vererbung bei typisierten Klassen 42

Platzhalter (Wildcards) Zur Typisierung kann man auch Wildcards verwenden: public class IrgendeinStall<?> Das ist so zunächst nur sinnvoll, wenn der genaue Typ keine Rolle spielt. Sinnvolle Verwendung finden Platzhalter zusammen mit oberen und/oder unteren Schranken. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 5. Vererbung bei typisierten Klassen 43

Obere Typ-Schranke Wie kann eine unerwünschte Typisierung Stall<String> verhindert werden? Die Typvariable kann innerhalb einer Typ-Hierarchie verortet werden, indem eine obere Schranke angegeben wird: public class Stall<T extends Tier> {... // Code Fragment Stall<String> // ungueltig: // String ist nicht Unterklasse von Tier Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 5. Vererbung bei typisierten Klassen 44

Untere Typ-Schranke Analog zur oberen Schranke kann man auch eine untere Schranke definieren. Das ist jedoch nur für Wildcards möglich, und nicht in Klassen-Definitionen, sondern nur in Deklarationen von Variablen: Stall<? super Schaf> stall;... // Code Fragment stall.setbewohner(new Kuh()) // ungueltig: // The method setbewohner(capture-of? super Schaf) // in the type Stall<capture-of? super Schaf> is // not applicable for the arguments (Kuh) Die Variable stall kann also nur Schafe oder deren Oberklassen aufnehmen (und damit keine Kühe). Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 5. Vererbung bei typisierten Klassen 45

Sinn von Schranken Wann ist eine obere, wann eine untere Schranke sinnvoll? Wenn der Typ-Parameter T nur als Argument verwendet wird, ist oft eine untere Schranke sinnvoll (? super T). Wenn der Typ-Parameter T nur bei Rückgabewerten eine Rolle spielt, kann man dem Benutzer oft mehr Freiheit geben, indem man eine obere Schranke benützt (U extends O). In der Unterklasse einer generischen Klasse können neue Schranken eingeführt werden. Mit dem Token & können dabei mehrere Schranken verbunden werden (z.b. U extends O1 & O2). Ab der zweiten oberen Schranke kann es sich dabei natürlich nur noch um Interfaces handeln. Prof. Dr. Peer Kröger: EiP (WS 18/19) Teil 10: Typsicherheit durch generische Typen 5. Vererbung bei typisierten Klassen 46