Generische Typen in Java



Ähnliche Dokumente
Java Einführung Collections

Objektorientierte Programmierung. Kapitel 12: Interfaces

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

Abschnitt 10: Typisierte Klassen

Programmieren in Java

Java: Vererbung. Teil 3: super()

Kapitel 6. Vererbung

Das Typsystem von Scala. L. Piepmeyer: Funktionale Programmierung - Das Typsystem von Scala

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

Java Kurs für Anfänger Einheit 5 Methoden

Einführung in die Programmierung

Kapitel 6. Vererbung

Programmierkurs Java

Prinzipien Objektorientierter Programmierung

Einführung in die objektorientierte Programmierung mit Java. Klausur am 19. Oktober 2005

Gebundene Typparameter

Kapitel 6. Vererbung

Aufgabenblatt Nr. 5 Generizität und TicTacToe

Objektorientierte Programmierung

Einführung in die Java- Programmierung

Test-Driven Design: Ein einfaches Beispiel

Computeranwendung und Programmierung (CuP)

Vererbung & Schnittstellen in C#

U08 Entwurfsmuster (II)

Assoziation und Aggregation

Software Engineering Klassendiagramme Assoziationen

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Client-Server-Beziehungen

Generische Datenstrukturen

Objektorientierte Programmierung

3 Objektorientierte Konzepte in Java

5. Abstrakte Klassen. Beispiel (3) Abstrakte Klasse. Beispiel (2) Angenommen, wir wollen die folgende Klassenhierarchie implementieren:

Software Entwicklung 1

Algorithmen und Datenstrukturen

Institut für Programmierung und Reaktive Systeme 25. August Programmier-Labor Übungsblatt. int binarysearch(int[] a, int x),

12) Generische Datenstrukturen

Java Generics & Collections

II. Grundlagen der Programmierung. 9. Datenstrukturen. Daten zusammenfassen. In Java (Forts.): In Java:

5. Abstrakte Klassen

Klassenentwurf. Wie schreiben wir Klassen, die leicht zu verstehen, wartbar und wiederverwendbar sind? Objektorientierte Programmierung mit Java

JAVA KURS COLLECTION

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

Der Aufruf von DM_in_Euro 1.40 sollte die Ausgabe 1.40 DM = Euro ergeben.

Große Übung Praktische Informatik 1

Einführung in Java. PING e.v. Weiterbildung Andreas Rossbacher 24. März 2005

Java Einführung Umsetzung von Beziehungen zwischen Klassen. Kapitel 7

Kapitel 9. Inner Classes. 9.1 Wiederholung: Iteratoren. Ausführen einer Operation auf allen Elementen einer Containerklasse

Javakurs zu Informatik I. Henning Heitkötter

Einfache Arrays. Annabelle Klarl. Einführung in die Informatik Programmierung und Softwareentwicklung

Innere Klassen in Java

Einführung in die Programmierung für Wirtschaftsinformatik

Studentische Lösung zum Übungsblatt Nr. 7

Javakurs 2013 Objektorientierung

Klausur zur Einführung in die objektorientierte Programmierung mit Java

Programmieren Tutorium

Software Entwicklung 1

Fachdidaktik der Informatik Jörg Depner, Kathrin Gaißer

Fachgebiet Informationssysteme Prof. Dr.-Ing. N. Fuhr. Programmierung Prof. Dr.-Ing. Nobert Fuhr. Übungsblatt Nr. 6

IT I: Heute. abstrakte Methoden und Klassen. Interfaces. Interfaces List, Set und Collection IT I - VO 7 1

1 Polymorphie (Vielgestaltigkeit)

Einstieg in die Informatik mit Java

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

II.4.6 Collections - 1 -

Das erste Programm soll einen Text zum Bildschirm schicken. Es kann mit jedem beliebigen Texteditor erstellt werden.

Java Einführung Abstrakte Klassen und Interfaces

Wintersemester Maschinenbau und Kunststofftechnik. Informatik. Tobias Wolf Seite 1 von 22

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

Distributed Computing Group

Javadoc. Programmiermethodik. Eva Zangerle Universität Innsbruck

3 Objektorientierte Konzepte in Java

SEP 114. Design by Contract

Vorkurs C++ Programmierung

Factory Method (Virtual Constructor)

Überblick. Lineares Suchen

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Objektorientierte Programmierung

12) Generische Datenstrukturen

Software Engineering Klassendiagramme Einführung

Einführung in die Java- Programmierung

WPF Steuerelemente Listbox, ComboBox, ListView,

Delegatesund Ereignisse

Programmierkurs Java

ADT: Java Collections und ArrayList

Schnittstellen implementieren am Beispiel Suchbaum

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

Neuere Sprachelemente in Java

Einführung in die Programmierung

Übungen Programmieren 1 Felix Rohrer. Übungen

Typumwandlungen bei Referenztypen

Grundlagen von Python

5. Tutorium zu Programmieren

M. Graefenhan Übungen zu C. Blatt 3. Musterlösung

Übungen zu Softwaretechnik

368 4 Algorithmen und Datenstrukturen

Die Bedeutung abstrakter Datentypen in der objektorientierten Programmierung. Klaus Kusche, September 2014

Klausur WS 2006/07 Programmiersprache Java Objektorientierte Programmierung II 15. März 2007

Übung Grundlagen der Programmierung. Übung 03: Schleifen. Testplan Testergebnisse

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Einführung in die Programmierung für NF

Abschnitt 12: Strukturierung von Java-Programmen: Packages

Transkript:

Generische Typen in Java Martin Wirsing in Zusammenarbeit mit Moritz Hammer und Axel Rauschmayer SS 06

2 Ziele xkurs: Wrapper-Klassen für Grundatentypen kennen lernen Verstehen von parametrischer Typ-Polymorphie in Java Die Kollektionshierarchie kennen lernen

3 xkurs: Grunddatentypen und ihre Klassen Zu jedem Grunddatentyp gibt es eine korrespondierende Klasse: Wrapper-Klasse Primitiver Typ Integer int Double double Boolean boolean Character char Autoboxing: Java unterstützt die automatische Konversion zwischen prim. Typ und Klasse. Beispiel: Integer j1 = new Integer(1906); int i = 1906; System.out.println(j.equals(j1)); //true Integer j = i; System.out.println(j == j1); //false int k = j; int k1 = j1; System.out.println(k == k1); //true Achtung: Durch Klassen werden neue Objekte erzeugt => hoher Speicherplatzverbrauch == auf Klassen vergleicht Objekt-Referenzen; besser equals verwenden!

4 Realisierung von Typ-Polymorphie in alten Java-Versionen Bis Java 1.4 wurde Typ-Polymorphie durch Vererbung von der Klasse Object realisiert. Beispiel: ine Container-Klasse zur Aufnahme von Objekten verschiedener Typen public class OldBox { private Object contents; public OldBox(Object cont) { contents = cont; public Object getcontents() { return contents; public void setcontents (Object o) { contents = o; public class TestOldBox { public static void main(string[] args){ OldBox b1 = new OldBox("Apple"); String s = (String) b1.getcontents(); System.out.println(s); OldBox b = new OldBox(new Integer(3)); int i = (Integer) b.getcontents(); System.out.println(s); Typüberprüfung zur Laufzeit

5 (infache) Realisierung mit generischen Typen Ab Java 1.5 kann Typ-Polymorphie parametrisch durch (formale) Typparameter realisiert werden (parametrische Polymorphie eine Art universelle Polymorphie). Beispiel: ine Klasse zur Aufnahme von genau einem Objekt Typvariable public class Box <T> { private T contents; public Box(T cont) { contents = cont; public T getcontents() { return contents; public void setcontents(t o) { contents = o; public static void main(string[] args){ Box<String> b = new Box<String>("Apple"); String s = b.getcontents(); System.out.println(s); Box<Integer> b1 = new Box<Integer>(new Integer(3)); int i = b1.getcontents(); System.out.println(i); Aktueller Typparameter: Typüberprüfung zur Übersetzungszeit!

6 Geschichtliches: Generische Typen in Java 1997: Martin Odersky, Philip Wadler: Pizza. In: Principles of Programming Languages Conference, POPL 97. ine funktionale Spracherweiterung von Java mit generischen Typen 1998: Gilad Bracha, Martin Odersky, David Stoutamire, and Philip Wadler. Making the future safe for the past: Adding Genericity to the Java Programming Language, OOPSLA 98, Vancouver, October 1998. Beschreibt Generic Java (GJ) als Weiterentwicklung von Pizza September 2004: Tiger Release Java 1.5 mit generischen Typen basierend auf GJ. Wadler, Odersky, Bracha, Stoutamire Und von hinten: Making Java easier to type, and easier to type

7 Generische Typen: Syntax Deklaration einer generischen Klasse: class <<Klassenname>> < <<Liste von Typvariablen>> > Instantiierung eines generischen Typs: <<Klassenname>> < <<Liste von Typausdrücken>> > Beispiele für Instantiierungen von Box<T>: Box<String> Box<Integer> Box<Box<String>> //Geschachtelter Typausdruck Box<int> //unzulässig,grunddatentypen nicht erlaubt als Typparameter Box<String, String> //unzulässig, zu viele Parameter Beispiel Box: rweitere z.b. TestBox1 um: Box<Box<String>> bb = new Box<Box<String>>(b); Box<String> b1 = bb.getcontents(); String s1 = b1.getcontents(); System.out.println(s1);

8 infache generische Methoden Deklaration einer generischen Methode: < <<Liste von Typvariablen>> > <<rgebnistyp>> <<Name>> ( <<Parameterliste>> ) Methodenaufruf einer generischen Methode (wie bisher): <<Name>> ( <<Liste von aktuellen Parametern>> ) Beispiel: ine Methode, die zufällig ein rgebnis wählt public class Random { public static <T> T zufall(t m, T n) { return Math.random() > 0.5? m : n; Beispiel Methodenaufrufe: String s = Random.zufall("ssen", "Schlafen"); int i = Random.zufall(100, 50);

9 Übersetzung von generischen Typen Zwei Möglichkeiten zur Übersetzung von generischen Datentypen: Heterogene Übersetzung. Für jede Instantiierung (etwa Box<String>, Box<Integer>, Box<Point>) wird individueller Code erzeugt, also drei Klassen. Homogene Übersetzung. Für jede parametrisierte Klasse (etwa Box<T>) wird genau eine Klasse erzeugt, die die generischen Typinformationen löscht ( type erasure ) und die Typparameter durch die Klasse Object ersetzt. Für jeden konkreten Typ werden zusätzlich Typanpassungen in die Anweisungen eingebaut. Java nutzt die homogene Übersetzung, (C++ die heterogene): Weniger erzeugter Code, Möglichkeit der Übersetzung nach Old Java ohne generische Typen, Aber geringere Ausdrucksmächtigkeit der Typüberprüfung (zur Compilezeit)

10 Übersetzung von generischen Typen Beispiel: Box<T> wird übersetzt in (die von OldBox bekannte Version) : public class Box { private Object contents; public Box(Object cont) { contents = cont; public Object getcontents() { return contents;... public static void main(string[] args){ Box b = new Box("Apple"); String s = (String) b.getcontents(); System.out.println(s);! Das ist eine (gute) Approximation. In Wirklichkeit wird aber direkt in Bytecode übersetzt!

11 Zusammenhang mit nichtgenerischen Typen Generische Klassen können auch ohne Typparameter verwendet werden; damit können sie mit altem Programmcode zusammen arbeiten. in parametrisierter Typ ohne Typangabe heißt Raw-Type. Raw-Types bieten die gleiche Funktionalität wie parametrisierte Typen, Allerdings werden die Parametertypen nicht zur Compilezeit überprüft, was zu Problemen führen kann. Beispiel: Der Raw-Type von Box<T> ist Box. Box<String> sbox = new Box<String>( apple ); Box obox = new Box(); //Jede Parametertypinformation fehlt obox = sbox; obox.setcontents( new Integer(3) ); // Warnung vor Unsafe type operation //clipse schlägt Restrukturierung ( Refactoring ) mit // infer generic type arguments vor. //Denn: System.out.println( sbox.getcontents() ); // führt zu ClassCastxception

12 Vererbung und Generische Typen Von generischen Klassen lassen sich in gewohnter Weise Unterklassen ableiten. Diese Unterklassen können, aber müssen nicht selbst generische Klassen sein. Beispiel: Generische Klasse als rbe: public class Pair<, S> extends Box<> { private S secondcontent; public Pair( first, S second) { super(first); this.secondcontent = second; public S getsecondcontent() {... public void setsecondcontent(s second) {... Beispiel Nichtgenerische Klasse als rbe: class StringBox extends Box<String> { public StringBox(String s) {super(s);

13 Vererbung und Generische Typen Aber: Vererbung bei Parametertypen induziert NICHT Vererbung der generischen Typen! Beispiel: Ist eine Box von Strings auch eine Box von Objects? Box <String> ls = new Box<String>( ); Box <Object> lo; lo = ls; //Typfehler! lo.setcontents(new Object()); String s = lo.getcontents(); //würde zu ClassCastxception führen s wird versucht, einem String ein Object zuzuweisen! Regel: Ist Foo Subtyp (Subklasse oder Subinterface) von Bar und G ist eine generische Deklaration, so ist G<Foo> kein Untertyp von G<Bar>! Aus dem Java Tutorial (G. Bracha): This is probably the hardest thing you need to learn about generics, because it goes against our deeply held intuitions.

14 inschränkung von Typvariablen Mit <<Typvariable>> extends <<Typausdruck>> ist es möglich nur solche Typparameter zuzulassen, die rben von <<Typausdruck>> sind. Beispiel: FruitBox enthält nur Früchte (rben von Fruit) public class Apple extends Fruit{ public class Steak { public class FruitBox <T extends Fruit>{ << analog Box<T> >> public static void main(string[] args) { Apple a1 = new Apple(); Steak s1 = new Steak(); FruitBox<Apple> abox = new FruitBox<Apple>(a1); //ok FruitBox<Steak> sbox = new FruitBox<Steak>(s1);//Compilezeitfehler:Bound Mismatch

15 ine generische Klasse C<T> bzw. C<T extends D> Generische Klassen in UML Repräsentieren wir in UML durch einen kleinen Kasten in der rechten oberen cke der Klasse C, in dem die Typvariable (mit Angabe der Beschränkung) steht. C T bzw. C T < D

16 Platzhalter (Wildcards) Problem: Beim Drucken von FruitBox stoßen wir auf ein Problem: public static void fruitboxprint( FruitBox<Fruit> f) { System.out.println(f); druckt nur Objekte der Klasse FruitBox<Fruit>, da z.b. FruitBox<Apple> keine Unterklasse von FruitBox<Fruit> ist. Lösung: Der Platzhalter (Wildcard, Joker)? erlaubt mit <<Klassenname>> <?> die Verwendung beliebiger (korrekter aktueller) Typen für? Beispiel: Der Platzhalter? erlaubt das Drucken beliebiger Früchteschachteln public static void fruitboxprint( FruitBox<?> f){ System.out.println(f); public static void main(string[] args) { FruitBox<Apple> abox = new FruitBox<Apple>(new Apple); fruitboxprint(abox);

17 Beschränkte Platzhalter (Bounded Wildcards) Der beschränkte Platzhalter (Wildcard, Joker) <<Klassenname>> <? extends <<Typausdruck>> > beschränkt die Verwendung auf Subtypen von <<Typausdruck>> Beispiel: Drucken von Früchteschachteln mit Box<T> public static void fruitboxprint1(box<? extends Fruit> f){ System.out.println(f); public static void main(string[] args) { Box<Apple> abox = new Box<Apple>(new Apple); fruitboxprint1(abox); Analog: Der beschränkte Platzhalter (Wildcard, Joker) <<Klassenname>> <? super <<Typausdruck>> > beschränkt die Verwendung auf Obertypen von <<Typausdruck>>

18 Generische Methoden vs. Platzhalter Wann benutzt man generische Methoden, wann Platzhalter? mit Platzhalter: public static void fruitboxprint1(box<? extends Fruit> f){ System.out.println(f); als generische Methode: public static <T extends Fruit> void fruitboxprint2(box<t> f){ System.out.println(f); Benutzung von Platzhaltern, wenn: der Typparameter T wird nur einmal benutzt wird, der Typ des Rückgabewertes nicht von T abhängt, kein anderes Argument der Methode von T abhängig ist, Das Typ-Argument für Typ-Polymorphie verwendet wird, d.h. dass verschiedene Argumenttypen erlaubt sind. Platzhalter für Typ-Polymorphie mit Subtyping. Generische Methoden verwenden, um Abhängigkeiten zwischen Argumenttypen und/oder Rückgabetypen einer Methode herzustellen.

19 Wann braucht man generische Methoden Bei Abhängigkeiten zwischen Argument- und Resultattyp Beispiel : public static <T> T trace(t t){ System.out.println(t); return t; Bei Abhängigkeiten zwischen zwei oder mehr Argumenttypen Beispiel : public static <T> void tobox(t t, Box<T> b){ b.setcontents(t);

20 ine erste Zusammenfassung Zu jedem Grunddatentyp gibt es eine korrespondierende Wrapper Klasse Java unterstützt die automatische Konversion zwischen prim. Typ und Klasse. Ab Java 1.5 kann Typ-Polymorphie parametrisch durch (formale) Typparameter realisiert werden (parametrische Polymorphie). Generische Klassen und generische Methoden haben Typvariablen als Parameter. Ihre Instantiierungsmöglichkeiten können durch Subtyp-Anforderungen eingeschränkt sein. Vererbung von aktuellen Parametern induziert NICHT die Vererbung der generischen Typen. Generische Klassen werden homogen übersetzt: Für jede parametrisierte Klasse (etwa Box<T>) wird genau eine Klasse erzeugt, die die generischen Typinformationen löscht ( type erasure ) und die Typparameter durch die Klasse Object ersetzt. Für jeden konkreten Typ werden zusätzlich Typanpassungen in die Anweisungen eingebaut.

21 Das Collection Framework Das Collection Framework ist ein System von generischen Schnittstellen und Klassen zur Darstellung mengenartiger Datentypen. ine Menge ist eine Collection, für deren lemente KIN Duplikate zugelassen sind. <<interface>> Collection in Collection Objekt fasst endlich viele lemente gleichen Typs zu einer Gruppe zusammen. <<interface>> Set <<interface>> List HashSet Aufsteigend geordnete Listen ohne Duplikate <<interface>> SortedSet TreeSet ArrayList LinkedList ine Liste ist eine geordnete Collection, in der lemente auch mehrfach vorkommen können.

22 Das Collection Framework Das Collection Framework ist ein System von generischen Schnittstellen und Klassen zur Darstellung mengenartiger Datentypen. <<interface>> Collection <<interface>> Set <<interface>> List HashSet <<interface>> SortedSet ArrayList LinkedList Implementiert Set durch Hashtabellen TreeSet Implementiert List mit Hilfe von Reihungen Implementiert SortedSet durch geordnete Bäume Implementiert List durch (doppelt) verkettete Listen.

23 Das Die Schnittstelle Collection interface Collection<> extends Iterable bietet u.a. folgende Methoden an: boolean add( o ) Fügt dem Container ein lement hinzu und gibt true zurück, falls sich das lement einfügen lässt. Gibt false zurück, wenn schon ein Objekt gleichen Werts vorhanden ist und doppelte Werte nicht erlaubt sind. boolean addall( Collection<? extends > c ) Fügt alle lemente der Collection c dem Container hinzu. boolean contains( Object o ) Liefert true, falls der Container ein inhaltlich gleiches lement enthält. boolean containsall( Collection<?> c ) Liefert true, falls der Container alle lemente der Collection c enthält. boolean ismpty() Liefert true, falls der Container keine lemente enthält. Iterator<> iterator() Liefert ein Iterator-Objekt über alle lemente des Containers. boolean remove( Object o ) ntfernt das angegebene Objekt aus dem Container, falls es vorhanden ist.

24 Die Schnittstelle List und eine Implementierung Das Schnittstelle interface List<> extends Collection<> spezifiziert, dass die geerbten Methoden add und addall lemente am nde der Liste einfügen und dass remove das erste lement entfernt. Weitere Operationen sind u.a.: void add( int index, element ) Fügt ein Objekt an der angegebenen Stelle in die Liste ein. get( int index ) liefert das lement an der angegebenen Stelle der Liste Die Klassen class ArrayList<> class LinkedList<> (siehe spätere Vorlesung) implementieren List<>.

25 import java.util.*; public class CollectionInfo { ine Anwendung von List /** Methode zur Ausgabe von Infos über eine Integer Collection */ public static void printinfo(collection<integer> c) { System.out.println("Die Menge enthält " + c.size() + " lemente."); System.out.println("Ist 0 in der Menge? " + c.contains(new Integer(0))); System.out.println("Ist 17 in der Menge? " + c.contains(17)); System.out.println("Alle lemente: "); for(integer x : c)system.out.println(x); /**bildet Liste aus den ingaben der Kommandozeile und druckt dafür Infos*/ public static void main(string[] args) { List<Integer> l = new ArrayList<Integer>(); for(string k : args) l.add(integer.parseint(k)); printinfo(l); // Infos ueber die Liste der ingaben

26 Die Schnittstelle Set und eine schnelle Implementierung Das Schnittstelle interface Set<> extends Collection<> spezifiziert, dass die geerbten Methoden add und addall keine lemente zusätzlich aufnehmen, die schon vorhanden sind. Für Set-Objekte u,v entspricht u.addall(v) der Mengenvereinigung, u.retainall(v) dem Mengendurchschnitt, u.removeall(v) der Mengendifferenz u\v. Die Klasse class HashSet<> implementiert u.a. Set<> mit einer schnellen Hash-basierten Datenstruktur. Konstruktoren sind: HashSet() rzeugt ein neues HashSet-Objekt mit 16 freien Plätzen und einem Füllfaktor von 0,75. HashSet( Collection<? extends > c ) rzeugt ein neues HashSet aus der Menge c gegebener lemente. Konstante Zeitkompl. für add, remove, contains

27 ine Anwendung von Set Um Mengen (ohne Duplikate) zu betrachten, kann man die HashSet-Implementierung von Set verwenden:... Set<Integer> s = new HashSet<Integer>(); for(string k : args) s.add(integer.parseint(k)); printinfo(s); // Infos ueber die Menge ohne Duplikate

28 Nochmals Vererbung und Generische Typen Vererbung bei Parametertypen induziert NICHT Vererbung der generischen Typen! Beispiel: Ist eine Liste von Strings auch eine Liste von Objects? List <String> ls= new ArrayList<String>(); List <Object> lo; lo = ls; lo.add(new Object()); String s = lo.get(0); s wird versucht, einem String ein Object zuzuweisen! Nochmals Regel: Ist Foo Subtyp (Subklasse oder Subinterface) von Bar und G ist eine generische Deklaration, so ist G<Foo> kein Untertyp von G<Bar>!

29 Zusammenfassung Das Collection Framework ist ein System von generischen Schnittstellen und Klassen zur Darstellung mengenartiger Datentypen. Collection ist die Basisschnittstelle, sie wird von der Listenschnittstelle List und der Mengenschnittstelle Set erweitert. Listen-Implementierungen sind ArrayList und LinkedList; Mengen-Implementierungen sind HashSet und TreeSet.