Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Generizität in Java und C#

Ähnliche Präsentationen


Präsentation zum Thema: "Generizität in Java und C#"—  Präsentation transkript:

1 Generizität in Java und C#
Riad Djemili Seminar Objektorientierte Programmiersprachen Prof. Dr.-Ing. Klaus-Peter Löhr FU-Berlin WS 03/04

2 Übersicht Motivation Generizität Polymorphie Probleme
Grundlagen (Eiffel, C++) Java C#

3 Motivation

4 Polymorphie Polymorphie Eigenschaft von Variablen, Objekte unterschiedlichen Typs speichern zu können. Variablen können Objekte zugewiesen werden, die vom gleichen Typen wie diese Variable oder von einem abgeleiteten Typen sind. List list = new LinkedList(); Statischer Typ In der Variablendeklaration festgelegter Datentyp. Dynamischer Typ Beim Erzeugen des Objekts festgelegter Typ.

5 Probleme Mächtiges Paradigma, aber nicht perfekt!
Statischer Datentyp ist fest und kann für eigene Anwendungen nicht leicht angepasst werden. Klassische Lösung: Nutzung des niedrigsten gemeinsamen Typen der Klassenhiarchie. Spezialiserte Implementationen mit unterschiedlichen Typen.

6 Ansatz 1: Nutzung von Vaterobjekten
Beispiel Java: Liste class MyList { boolean add(Object o) {..} Object get(int index) {..} } .. //associates Integer-Objects MyList ints = new MyList(); ints.add(new Integer(4)); Integer foo = (String)ints.get(0); Unsichere Konvention, statt expliziter Sprachunterstützung. Typwandlungs-Laufzeitfehler, statt Übersetzungsfehler. Teure Typwandlungen zu Basisklasse und zurück. Nicht alle Programmiersprachen kennen gemeinsame Vaterobjekte. Containerklassenansatz ausführlich

7 Ansatz 2: Spezialisierte Implementationen
Beispiel Java: Math-Methoden public static double abs(double a) {..} public static float abs(float a) {..} public static int abs(int a) {..} public static long abs(long a) {..} Methodenüberladen (gleiche Methodennamen mit unterschiedlichen Signaturen), um verschiedene Datentypen zu unterstützen. Effizient, aber aufgeblähter und unübersichtlicher Code! Grosses beispiellisting

8 Lösung: Generizität (I)
Polymorphie Ad hoc – Polymorphie (überladen) Universelle Polymorphie Inklusions-Polymorphie (überschreiben) Parametrische Polymorphie (Generizität) Möglichkeit nicht nur dynamischen Typ, sondern auch statischen Typ zu variieren.

9 Lösung: Generizität (II)
Ziele Höhere Typsicherheit, durch Vermeidung von unsicheren Typumwandlungs-Laufzeitfehlern. Wiederverwendbarer Code. Bessere Lesbarkeit, durch expliziter Syntax, statt impliziter Konvention. Effizienz, da keine unnötigen Typwandlungen.

10 Klassische Generizität in Eiffel und C++

11 Klassen Generizität Klassen werden mit formalen Typparametern deklariert. Tatsächliche Datentypen werden als Parameter übergeben. Ungenerischer Stack in Eiffel Generischer Stack in Eiffel class STACK .. feature push ( elem: INTEGER ) is do .. end top: INTEGER is end Anwendung: intstack : STACK; intstack.push(3); class STACK [T] .. feature push ( elem: T ) is do .. end top: T is end Anwendung: intstack : STACK[INTEGER]; intstack.push(3);

12 Mehrere Parametertypen
Ausserdem mehrere generische Parametertypen möglich. Beispiel: Ein generisches Paar in Eiffel class PAIR[T, U] feature {NONE} // private first : T; second : U; end Anwendung: birthdate : PAIR[STRING,DATE]; //TODO: RIGHT SYNTAX???

13 Methoden Generizität Generische Typen existieren auch für Funktionen!
Beispiel: Vertausche-Operation in C++ template<class T> void swap(T& x, T& y) { T temp = x; x = y; y = temp; } Anwendung int    i,j;  swap<int> (i,j); //a swap for int char   i,j;  swap<char>(i,j); //a swap for char Nicht in Eiffel verfügbar

14 Methoden Generizität (II)
Im Gegensatz zu generischen Klassen können Typparameter bei Methoden implizit aus Argumenten abgeleitet werden! Beispiel in C++: int    i,j;  swap(i,j); // a swap for int float  i,j;  swap(i,j); // a swap for float Ohne explizite Datentypangabe.

15 Eingeschränkte Generizität
Typeinschränkungen mittels klassischer Polymorphie: bool pos(Comparable foo) {return foo.compareTo(x);} Problem: Wie können wir ähnlich sichere Annahmen für generische Typen machen? Lösung: Constrained Genericty. class SORTED_LIST [T->COMPARABLE] .. end Erzwingt in Eiffel, dass T Unterklasse von Comparable sein muss, ansonsten Übersetzungsfehler. (Mehrfachvererbung erlaubt in Eiffel). Welche notation für mehrere constraints? Wohl nicht erlaubt! Lösung etwas formaler definieren

16 Java

17 Übersicht Seit 1995 von Sun Microsystems entwickelt.
Stark objektorientiert. Umfangreiche Klassenbibliothek. Automatische Speicherverwaltung. Plattformunabhängig. Aus „Generic Java“ entwickelt und offiziell ab Java 1.5 (Sommer 2004, Codename: Tiger) unterstützt.

18 Ziele der Java-Implementation
Vollständige Ersetzung der aktuellen Java API durch generische Version. „Retrofitting“ alten Codes. Vollständige Rückwärtskompabilität. Alter Code soll ohne Änderung ausführbar bleiben.

19 Parametertypen Erlaubte Typarten:
Klassen sind als Parametertypen erlaubt. Primitive Typen sind nicht erlaubt. Unteranderem da für sie kein einheitliches Typsystem existiert. Sie müssen jeweils (uneffizient) in ihre Wrapper-Klassen gekapselt werden z.B. int → Integer, boolean → Boolean Übrigens automatisches „Casting“ (Autoboxing) auch ab Java 1.5. Ausserdem mehrere Typparameter erlaubt. PolyJ claims to be able to use some of the primitive types as parameters.  Most of the primitive types (such as int) take up the same space as an object reference, and therefore they can be used as parameters.  The where-routines used to bound the types are not accessed through the object, so there is not a problem when using the primitives.  The relevant byte codes do not distinguish between references and primitive values, therefore there is no problem there.  The larger primitives (such as long or double) cannot be used as type parameters because they take up more space than an object reference, and therefore would cause problems with the various byte codes that would access them.

20 Klassen Generizität Beispiel: Die neue java.util.Stack Klasse class Stack<E> extends Vector<E> { public E push(E item) {..} public synchronized E pop() {..} public synchronized E peek() {..} public boolean empty() {..} public synchronized int search(Object o) {..} } Anwendung: Stack<String> foo = new Stack<String>(); Search nach Object

21 Methoden Generizität Methoden-Generics unterstützt.
Typangabe (unintuitiverweise) vor Methodenname! Begründung ist leichteres Parsing. Beispiel: Eine vertausche-Operation static <Elem> void swap(Elem[] array, int x, int y) { Elem  temp = array[x]; array[x]  = array[y]; array[y]  = temp; } Aufrufe auch mit impliziter Typangabe. swap(ints, 1, 3) sort(strings) <Integer>swap(ints, 1, 3) <String>sort(strings)

22 Bounds Einschränkung (bounding) der Typen durch
maximal eine Oberklasse und/oder beliebiger Anzahl von Interfaces. Beispiel: Sortierte Liste class SortedList<T extends Entry implements Comparable> {..} Keine neuen Schlüsselwörter

23 Übersetzung (Bytecode)
Übersetzung (I) Java Implementierung von Generizitäts-Erweiterungen auf Ebene der Übersetzung. Übersetzung (Bytecode) Ausführung (JVM) Linux Windows .. Mobile Plattformen

24 Übersetzung (II) Oberster Grundsatz: Die Java Virtual Machine wird nicht verändert! Homogener Vorgang (für jeden generischen Typen wird einmalig neuer Code generiert) Generische Datentypen werden durch untere Grenze ersetzt (Erasures). Casting geschieht bei Attributzugriffen und Methodenrückgaben. Einsetzung von Bückenmethoden bei kovarianter Vererbung. (siehe später) Vorgang fast analog zum „manuellen“ Vorgang bisher. Neue Compiler sind natürlich nötig Unterstützung von Legacy Programmen Übersetzung genau wie ein Programmierer manuell arbeiten würde. Vorgang entspricht eher der eines Preprozessors

25 Übersetzung in JVM – konformen Code.
Übersetzung (III) Übersetzung in JVM – konformen Code. class Cell<A> { A value; A getValue(); } .. String f(Cell<String> cell){ return cell.value; } class Cell { Object value; Object getValue(); } .. String f(Cell cell){ return (String)cell.value; } Klasse Cell wird nur einmal generiert und kann für alle Parametertypen wiederverwendet werden.

26 Legacy-Code (I) Java API soll mit generischen Typen aktualisiert werden. Stack s = new Stack(); geht aber immernoch (sogenannte „Raw Classes“)! Ohne Angabe eines Typparameters wird implizit niedrigste Typschranke angenommen. Hier also: Stack<Object> s = new Stack<Object>(); Ermöglicht „Rückwärts-Kompabilität“, dh. alter Code kann ohne Änderung weiter mit „retrofitted“ API Klassen arbeiten. Evtl. auch „Vorwärts-Kompabilität“ denkbar. Evtl auch Vorwärts-Kompabilität, aber noch unklar.

27 Legacy-Code (II) Zuweisungen
Erlaubt Stack s = new Stack<Integer>(); Übersetzer-Warnungen, bei Methodenaufrufem mit veränderten Argumenttypen. Attributzugriffe mit veränderten Typen. s.push(new Integer(5)); //compile-warning Erlaubt, aber „deprecation“-Warnung, da unsicher. Stack<Integer> s = new Stack();

28 Kovarianz (I) Bisher: Invariante Rückgabetypen
Rückgabetyp einer Methode muss identisch sein mit der überschriebenen Methode. Jetzt: Kovariante Rückgabetypen Rückgabetyp einer Methode muss Untertyp sein für alle Methoden, die sie überschreibt. Kovarianz wird durch Brückenmethoden realisiert.

29 Kovarianz (II) class A<T> { T something() { .. } } class B<T implements Comparable> extends A<T> { T something() { .. } } class A { Object something() { .. } } class B extends A { Comparable something() { .. } Object something/*2*/() { return something() } } Kovarianz wird durch Erasure-Übersetzung notwendig gemacht. JVM unterstützt intern auch Methoden mit Signaturen, die sich nur im Rückgabetypen unterscheiden.

30 Vererbung (I) Unintuitive Typbeziehung
LinkedList<String> ist Untertyp von List<String>. List<String> ist aber nicht Untertyp von List<Object>.

31 Vererbung (II) Naive generische Implementation von Interface Collection: interface Collection<E> { boolean addAll(Collection<E> c); boolean containsAll(Collection<E> c); } Nachteil: Aufgrund von fehlerender Typbeziehung kann die generische Methode nur eigenen Typen aufnehmen. Collection<Number> = new Collection<Number> col; Collection<Integer> = new Collection<Integer> ints; col.addAll(ints); Typfehler!

32 Vererbung (III) Bessere generische Implementation erlaubt kovariante Argumente: interface Collection<E> { <T extends E> boolean addAll(Collection<T> c); <T> boolean containsAll(Collection<T> c); } Auch wenn aktueller Typparameter bei Methodenaufruf implizit übergeben werden kann: Unleserliche und umständliche Notation für häufiges Programmierziel. Implementation mit intuitiv richtigen Verhalten. Aktueller Typparameter kann meist weggelassen werden.

33 Vererbung (IV) Vorangetrieben durch „Variant Generic Java” WildCard-Syntax. Ermöglicht bessere Lesbarkeit durch anonyme Typparameter. interface Collection<E> { boolean addAll(Collection<? extends E> c); boolean containsAll(Collection<?> c); } Ermöglicht auch Kontravarianz. interface Collection<E> { boolean addAll(Collection<? super E> c); boolean containsAll(Collection<?> c); } Aber, was trotzdem nicht geht: List<? extends Number> = new List<Integer>; VGJ ist eine eingereichte Extension zu GJ.

34 Exceptions Nicht vollständig unterstützt.
Generics dürfen nicht von java.lang.Throwable ableiten. Typvariablen sind erlaubt in throws – Anweisung. nicht erlaubt in catch – Anweisung. beispiel

35 Instanziieren von Parametertypen
Aufgrund von Erasures ist es nicht möglich Parametertypen zu instanziieren. class Singleton<T> { private T instance; public T getInstance() { if (instance == null) instance = new T(); return instance; } } Nicht erlaubt! new T[10] geht auch nicht.

36 Reflection Generische Klassen als Typen bekannt, allerdings keine Kenntnis über aktuelle Typparameter zur Laufzeit, da diese beim Übersetzen entfernt werden (erasures). class SortedSet<T extends Comparable<T>> { public SortedSet() { if (T.class == Date.class) { } else if (T.class == Integer.class) { } } } Kann nicht funktionieren, da T.class hier immer vom Typ Comparable ist.

37 Schwächen von Erasures
Unerwartete Fehler aufgrund von gleichen Erasures class Tool { public void do(Collection<Integer>) {..} public void do(Collection<String>) {..} } class C<A> { A id(A x) {..} } interface I<A> { A id(A x); } class D extends C<String> implements I<Integer> { String id(String x) {..} Integer id(Integer x) {..} }

38 Zusammenfassung Vorteil Nachteil
Leichter Übergang zwischen generischem und ungenerischem Code. Keine neue konkurrierende Java API. Anonyme Typparameter (Wildcards). Nachteil Keine primitiven Datentypen erlaubt. Uneffizient, da up/down - casting intern immernoch nötig. Kein Wissen über aktuelle generische Typparameter. Typparameter können nicht instanziiert werden. Verschiedene Restriktionen im Zusammenhang mit Erasures Java macht „nur“ was der programmierer zuvor explizit gemacht hat.

39 C#

40 Übersicht Seit Februar 2001 von Microsoft entwickelt.
Stark objektorientiert. Umfangreiche Klassenbibliothek. Automatische Speicherverwaltung. Teil des .NET Frameworks Bald (Mitte/Ende 2004!?) auch Generics.

41 Ziel der .Net Implementation
Saubere vollständige Implementation von Generics. Einführung neuer Intermediate Language Typen. Einführung neuer generischer Klassen in das .NET Framework. Aktuelles nicht-generisches .NET Framework bleibt erhalten.

42 Parametertypen Typarten: Auch mehrere generische Typen erlaubt.
Klassen sind als Parametertypen erlaubt. Primitive Typen sind erlaubt, da alle Typen (Referenz- und Datentypen) einen gemeinsamen Obertypen haben. Auch mehrere generische Typen erlaubt.

43 Klassen Generizität Beispiel: Eine sortierte Liste class SortedList<EntryType> where EntryType : IComparable{ public void insert(EntryType item) {..} public void remove(EntryType item) {..} public bool contains(EntryType item) {..} public bool empty() {..} } Anwendung: SortedList<int> ss = new SortedList<int>(); Ausserdem Unterstützung für Structs und Delegates.

44 Methoden Generizität Methoden-Generics unterstützt. Typangabe intuitiverweise hinter Methodenname! Beispiel: swap static void swap<Elem>(Elem[] array, int x, int y) { Elem  temp = array[x]; array[x]  = array[y]; array[y]  = temp; } Aufrufe auch mit impliziter Typangabe. swap(ints, 1, 3) sort(strings) swap<int>(ints, 1, 3) sort<string>(strings) Syntax analog zu Klassen.

45 Constraining Einschränkung (analog zu Java) der Typen durch
maximal eine Oberklasse und/oder beliebiger Anzahl von Interfaces. Beispiel: Zwei eingeschränkte Typparameter. pulic class MyList<K,T> where K : Icomparable<K>, IEnumerable where T : Customer { } Notation umständlicher als bei Java!? Notation erscheint umständlich

46 Übersetzung (I) Sprachen VB .NET C# .. Java# Übersetzung (MIL)
Implementierung von Generizitäts-Erweiterungen auf Ebene der Ausführung. Ausführung (CLR) (Linux) Windows .. Mobile Plattformen

47 Übersetzung (II) Typabhängige Übersetzung:
Für ReferenceTypes (Klassen) wird einmal generierter gemeinsamer Code wiederverwendet (homogener Vorgang). Für ValueTypes (primitive Typen) wird bei jeder ersten Benutzung spezieller Code generiert (heterogener Vorgang). Trotzdem kein casting!?

48 Legacy-Code (I) .NET API erhält zusätzliche generische Klassen.
Ausmass abgesehen von Collections Namespace noch unbekannt. „Rückwärts-Kompabilität“ wird durch Beibehaltung der alten Klassen gewährleistet. Mischung von generischem und ungenerischem Code nur schwer.

49 System.Collections.Generics
Legacy-Code (II) System.Collections System.Collections.Generics Comparer Comparer<T> HashTable Dictionary<K,T> ArrayList List<T> Queue Queue<T> SortedList SortedDictionary<K,T> Stack Stack<T> ICollection ICollection<T> System.Comparable IComparable<T> IComparer IComparer<T> Idictionary IDictionary<K,T> Ienumerable IEnumerable<T> IEnumerator IEnumerator<T> IKeyComparer IKeyComparer<T> IList IList<T>

50 Typenvarianz Nur Invariante Rückgabetypen Keine Wildcard-Syntax.
Rückgabetyp einer Methode muss identisch sein mit der überschriebenen Methode. Keine Wildcard-Syntax. Keine Kontravarianz.

51 Exceptions Vollständige Unterstützung.
Generics dürfen von System.Exception ableiten. Typvariablen sind erlaubt in throws – Anweisung. erlaubt in catch – Anweisung, wenn sie vom Typ System.Exception ableiten.

52 Instanziieren von Parametertypen
Parametertypen können instanziiert werden, wenn sie einen Konstruktor ohne Argumente bieten. Garantie muss als zusätzliches Constraint „new()“ angegeben werden. Beispiel: class Singleton<T> where T : new() { private T instance; public T getInstance() { if (instance == null) instance = new T(); return instance; } }

53 Reflection Volle Reflectionunterstützung von generischen Typen. Type type = typeof(List<int>); Type-Klasse wird erweitert mit speziellen Eigenschaften von generischen Typen: int GenericParameterPosition{virtual get;} bool HasGenericParameters{get;} bool HasUnboundGenericParameters{virtual get;} bool IsGenericParameter{virtual get;} bool IsGenericTypeDefinition{virtual get;} virtual Type BindGenericParameters(Type[] typeArgs); virtual Type[] GetGenericParameters(); virtual Type GetGenericTypeDefinition(); Erlaubt auch Zugriff auf aktuelle Typparameter. HasGenericParameters liefert aktuelle Typparameter

54 Zusammenfassung Vorteil Nachteil
Intuitive und vollständige Umsetzung von generischen Typen. Effizienz. Vollständige Typkenntnis zur Laufzeit (Reflection). Nachteil Absolute Trennung zwischen generischen und nicht generischem Code. API kann nicht rückwärtskompatibel umgeschrieben werden. Keine Kontravarianz. Umständlichere Notation. todo.: übersetzung von c# generics Nachteil: erst später verfügbar?

55 Konklusion

56 Fazit Generizität Implementationen Sinnvoll und allgemein anerkannt.
Birgt aber auch zusätzliche Komplexität. Nicht immer klar, wann angebracht. Implementationen Java Rückwärts-Kompabilität positiv, allerdings grosse Einschränkungen bei Nutzung von generischen Typen. C# Gute Unterstützung für generische Typen, aber unklare Konsequenz für .NET Framework.

57 Referenzen Adding Generics to the Java Programming Language: Public Draft Specification, Version 2.0 Bracha, Cohen, Kemper, Odersky, Stoutamire, Thorup, Wadler Variant Generic Types Sun Microsystems Design an Implementation of Generics for the .NET Common Language Runtime Andrew Kennedy, Don Syme MSDN Article: Introduction to C# Generics Juval Lowy


Herunterladen ppt "Generizität in Java und C#"

Ähnliche Präsentationen


Google-Anzeigen