1 / 35

Programmierkurs Java

Programmierkurs Java. Teil Objektorientierte Programmierung Unterrichtseinheit 38 Generics. Dr. Dietrich Boles. Gliederung. Generics Motivation Generische Klassen Klassendefinition Objekte / Objektvariablen Übersetzung Typ-Kompatibilität Generische JDK-Klassen Iterator Vector

vian
Download Presentation

Programmierkurs Java

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Programmierkurs Java Teil Objektorientierte Programmierung Unterrichtseinheit 38 Generics Dr. Dietrich Boles

  2. Gliederung • Generics • Motivation • Generische Klassen • Klassendefinition • Objekte / Objektvariablen • Übersetzung • Typ-Kompatibilität • Generische JDK-Klassen • Iterator • Vector • Beispiel • Typ-Parameter mit Einschränkungen • Vererbung • Interfaces • Arrays • Wildcards • new • static • Generische Methoden • Motivation • Beispiele • Zusammenfassung

  3. Motivation / Problem • Simulation eines Getränkehandels • Quelle: J. Nowak. Fortgeschrittene Programmierung mit Java 5,dpunkt. • Gegeben: vielerlei Getränke • Gewünscht: typisierte Flaschen, die nur mit Bier, Rotwein oder Weißwein gefüllt werden können Drink Wine Beer RedWine WhiteWine

  4. Motivation / Ausgangslage abstract class Drink { } class Beer extends Drink { private String brewery; public Beer(String brewery) { this.brewery = brewery; } public String getBrewery() { return this.brewery; } public String toString() { return this.getClass().getName() + "[" + this.brewery + "]“; } } abstract class Wine extends Drink { private String region; public Wine(String region) { this. region = region; } public String getRegion() { return this.region; } public String toString() { return this.getClass().getName() + "[" + this.region + "]"; } } class WhiteWine extends Wine { public WhiteWine(String region) { super(region); } } class RedWine extends Wine { public RedWine(String region) { super(region); } }

  5. Motivation / erste Lösung class Bottle { private Drink content; public boolean isEmpty() { return this.content == null; } public void fill(Drink content) { this.content = content; } public Drink empty() { Drink content = this.content; this.content = null; return content; } } ... Bottle beerBottle = new Bottle(); beerBottle.fill(new WhiteWine("Burgunder")); ... Beer beer = (Beer)beerBottle.empty(); // ClassCastException! Lösung: polymorphe Klasse Probleme: - keine korrekte Lösung - Typ-Unsicherheit

  6. Motivation / zweite Lösung abstract class DrinkBottle {} class BeerBottle extends DrinkBottle { private Beer cont; public void fill(Beer content) { this.cont = content; } public Beer empty() { Beer c=this.cont; this.cont=null; return c; } } abstract class WineBottle extends DrinkBottle {} class WhiteWineBottle extends WineBottle { private WhiteWine cont; public void fill(WhiteWine content) { this.cont = content; } public WhiteWine empty() { WhiteWine c=this.cont; this.cont=null; return c; } } class RedWineBottle extends WineBottle { private RedWine cont; public void fill(RedWine content) { this.cont = content; } public RedWine empty() { RedWine c = this.cont; this.cont = null; return c; } } Lösung: Getränk-spezifische Flaschen Problem: Keine Vererbung, keine wirkliche Polymorphie!

  7. Motivation / dritte Lösung (1) class Bottle<T> { private T content; public boolean isEmpty() { return this.content == null; } public void fill (T content) { this.content = content; } public T empty() { T content = this.content; this.content = null; return content; } } Lösung: - Generische (parametrisierte) Klasse - T ist formaler Typ-Parameter (Typ-Variable) der Klasse Bottle

  8. Motivation / dritte Lösung (2) Bottle<Beer> beerBottle = new Bottle<Beer>(); Bottle<WhiteWine> whiteWineBottle = new Bottle<WhiteWine>(); beerBottle.fill(new Beer("Veltins")); beerBottle.fill(new WhiteWine("Burgunder")); // Fehlermeldung durch Compiler! whiteWineBottle.fill(new WhiteWine("Burgunder")); Beer beer = beerBottle.empty (); System.out.println (beer); WhiteWine whiteWine = whiteWineBottle.empty (); System.out.println (whiteWine); Aktueller Typ-Parameter (Klasse)

  9. Generische Klassen / Klassendefinition class C<T> { ... } class D<T> extends T { } class E<T> { T obj; } interface I<T1, T2> { public void setze(T1 obj1, T2 obj2); } class F<T4, T5, T6> implements I<T4, T6> { public T5 liefere() { ...} public void setze(T4 obj1, T6 obj2) { ... } } T kann im weiteren Klassenkopf und im Klassenrumpf (fast) überall da verwendet werden, wo Klassennamen stehen können

  10. Generische Klassen / Objekte und Objektvariablen class C<T> { public T f(T t) {...} } class A { } class B { } C<A> obj = new C<A>(); C<B> obj2 = new C<B>(); A a = obj.f(new A()); B b = obj2.f(new B()); A a2 = obj.f(new B()); // Fehlermeldung durch Compiler Formaler Typ-Parameter Parametrisierte Klasse / Typ Aktueller Typ-Parameter (Klasse, kein Standarddatentyp)

  11. Generische Klassen / Übersetzung class C<T> { T t; T f(T t) { T t1 = t; this.t = t1; String str = t.toString(); return this.t; } } class C { Object t; Object f(Object t) { Object t1 = t; this.t = t1; String str = t.toString(); return this.t; } } Compiler Raw-Type Daher erlaubt: C obj = new C(); + Meta-Informationen!

  12. Generische Klassen / Typ-Kompatibilität class C<T> { ... } class A { } class B { } class D extends A { } C<B>  C<A> // C<A> obj = new C<B>(); Fehler C<D>  C<A> // C<A> obj = new C<D>(); Fehler C<A>  C<Object> // C<Object> = new C<A>(); Fehler C<A>  Object // Object obj = new C<A>(); ok

  13. Generische JDK-Klassen / java.util.Iterator public interface Iterator<T> { public boolean hasNext(); public T next(); } public interface Iterable<T> { // in java.lang public java.util.Iterator<T> iterator(); }

  14. Generische JDK-Klassen / java.util.Vector public class Vector<T> extends java.util.AbstractList<T> implements Iterable<T>, ... { public Vector(); public Vector(int initCapacity); public boolean add(T obj); public boolean contains(Object obj); public T elementAt(int index); public T get(int index); public void insertElementAt(T o,int i); public boolean remove(Object obj); public int size(); public java.util.Iterator<T> iterator(); ... }

  15. Generische JDK-Klassen / Beispiel import java.util.Vector; import java.util.Iterator; public class IteratorBspMitCast { public static void main(String[] args) { Vector speicher = new Vector(); speicher.add(4711); speicher.add(46); speicher.add(33); int summe = 0; Iterator iter = speicher.iterator(); while (iter.hasNext()) { summe += (Integer)iter.next(); } System.out.println(summe); } } Raw-Type Cast notwendig! Compiler-Warnung: ... uses unsafe operations

  16. Generische JDK-Klassen / Beispiel import java.util.Vector; import java.util.Iterator; public class IteratorBsp { public static void main(String[] args) { Vector<Integer> speicher = new Vector<Integer>(); speicher.add(4711); speicher.add(46); speicher.add(33); int summe = 0; Iterator<Integer> iter = speicher.iterator(); while (iter.hasNext()) { summe += iter.next(); } System.out.println(summe); } } Kein Cast notwendig!

  17. Generische JDK-Klassen / Beispiel import java.util.Vector; public class IteratorBspFor { public static void main(String[] args) { Vector<Integer> speicher = new Vector<Integer>(); speicher.add(4711); speicher.add(46); speicher.add(33); int summe = 0; for (Integer i : speicher) { summe += i; } System.out.println(summe); } } neue for-Schleife

  18. Typ-Parameter mit Einschränkungen • Motivationsproblem: Bottle<Object> ist keine Getränkeflasche! • Lösung: Einschränkung des Typ-Parameters class Bottle<T extends Drink> { /* wie auf Folie 7 */ } class Petrol { } class Stout extends Beer { ... } Bottle<Drink> drinkBottle = new Bottle<Drink>(); Bottle<Beer> beerBottle = new Bottle<Beer>(); Bottle<Object> objectBottle = new Bottle<Object>(); // Fehlermeldung durch Compiler Bottle<Petrol> petrolBottle = new Bottle<Petrol>(); // Fehlermeldung durch Compiler Bottle<Stout> stoutBottle = new Bottle<Stout>();

  19. Typ-Parameter mit Einschränkungen / Übersetzung class A { public void doIt() {...} } class C<T extends A> { T t; T f(T t) { T t1 = t; this.t = t1; this.t.doIt(); return this.t; } } class C { A t; A f(A t) { A t1 = t; this.t = t1; this.t.doIt(); return this.t; } } Compiler

  20. Vererbung class A { } class B<T extends A> { public void f(T t) { ... } } class C<T> extends A { } class D<T extends A> extends B<T> { } class E extends B<A> { public void f(A obj) { ... } // Überschreiben public void f(Object obj) { ... } // Überladen }

  21. Interfaces class A { } class B { } interface I<T1 extends A, T2 extends B> { public void f1(T1 t); public void f2(T2 t); } class C implements I<A, B> { public void f1(A t) { ... } public void f2(B t) { ... } } class D implements I<A, A>, I<B, B> { ... } // Fehler: dasselbe Interface nicht zweimal implementieren

  22. Arrays mit parametrisierten Klassen (1) • Motivationsproblem: Klasse für Getränke-spezifische Getränkekästen • Problem: Arrays mit parametrisierten Klassen sind nicht erlaubt • Lösung: class BottleBox<T extends Drink> { private Object[] bottles; private int count = 0; public BottleBox(int number) { // this.bottles = new T[number]; nicht erlaubt this.bottles = new Object[number]; } public void add(Bottle<T> bottle) { this.bottles[this.count] = bottle; this.count++; } public Bottle<T> getBottle(int index) { return (Bottle<T>)this.bottles[index]; } } Internes sicheres (!) Cast

  23. Arrays mit parametrisierten Klassen (2) BottleBox<Beer> beerBottleBox = new BottleBox<Beer>(6); // Bierkasten füllen for (int i = 0; i < 6; i++) { Bottle<Beer> beerBottle = new Bottle<Beer>(); beerBottle.fill(new Beer("Jever")); beerBottleBox.add(beerBottle); } Bottle<RedWine> wineBottle = new Bottle<RedWine>(); beerBottleBox.add(wineBottle); // Fehlermeldung ... // Bierkasten leeren for (int i = 0; i < 6; i++) { Bottle<Beer> beerBottle = beerBottleBox.getBottle(i); Beer beer = beerBottle.empty (); System.out.println(beer); }

  24. Wildcards (1) • Motivationsproblem: Klasse für Getränkekästen mit beliebigen Flaschen • Lösung: „Wildcards“ class BottleBox { private Object[] bottles; private int count = 0; public BottleBox(int number) { this.bottles = new Object[number]; } public void add(Bottle<? extends Drink> bottle) { this.bottles[this.count] = bottle; this.count++; } public Bottle<? extends Drink> getBottle(int index) { return (Bottle<? extends Drink>)this.bottles[index]; } }

  25. Wildcards (2) BottleBox box = new BottleBox(6); // Füllen Bottle<Beer> beerBottle = new Bottle<Beer>(); beerBottle.fill(new Beer("Veltins")); box.add (beerBottle); Bottle<WhiteWine> whiteWineBottle = new Bottle<WhiteWine>(); whiteWineBottle.fill (new WhiteWine("Burgunder")); box.add (whiteWineBottle); // Leeren for (int i = 0; i < 6; i++) { Bottle<? extends Drink> bottle = box.getBottle (i); Drink drink = bottle.empty (); System.out.println(drink); }

  26. Wildcards (3) class A { } class B { } class C<T> { } C<A> ca = new C<A>(); // ok C<Object> cobj = new C<A>(); // Fehler C obj = new C<A>(); // ok, aber möglichst vermeiden C<?> c1 = new C<A>(); // ok C<?> c2 = new C<B>(); // ok ? steht für irgendeinen Typ

  27. Wildcards (4) • Motivationsproblem: Klasse für Getränke-spezifische Getränkekästen • Problem der Lösung auf Folie 22: BottleBox<Beer> • Lösung: class BottleBox<T extends Bottle<? extends Drink>> { private Object[] bottles; private int count = 0; public BottleBox(int number) { this.bottles = new Object[number]; } public void add(T bottle) { this.bottles[this.count] = bottle; this.count++; } public T getBottle(int index) { return (T)this.bottles[index]; } } Semantische Ungereimtheit

  28. Wildcards (5) BottleBox<Bottle<Beer>> beerBottleBox = new BottleBox<Bottle<Beer>>(6); // Bierkasten füllen for (int i = 0; i < 6; i++) { Bottle<Beer> beerBottle = new Bottle<Beer>(); beerBottle.fill(new Beer("Jever")); beerBottleBox.add(beerBottle); } ... // Bierkasten leeren for (int i = 0; i < 6; i++) { Bottle<Beer> beerBottle = beerBottleBox.getBottle(i); Beer beer = beerBottle.empty (); System.out.println(beer); }

  29. new class A { } class C<T> { T t = new T(); // Fehlermeldung; Grund: Übersetzung // von T nach Object }

  30. static class A { } Class B { } class C<T> { static T t; // Fehlermeldung static C<T> c; // Fehlermeldung } C<A> ca = new C<A>(); C<B> cb = new C<B>(); Grund: Der Compiler generiert nur eine (!) Klasse. Beide Objekte würden sich die statischen Attribute teilen.

  31. Generische Methoden / Motivation (1) • Motivationsproblem: Umfüllen von Flaschen • Mögliche Lösung: class BottleTransfuser<T extends Drink> { void transfuse(Bottle<T> fromBottle, Bottle<T> toBottle) { T drink = fromBottle.empty(); toBottle.fill(drink); } } BottleTransfuser<Beer> beerTransfuser = new BottleTransfuser<Beer>(); ... • Problem: beerTransfuser kann nur Bierflaschen umfüllen!

  32. Generische Methoden / Motivation (2) • allgemeiner Lösung: Generische Methoden class BottleTransfuser { <T extends Drink> void transfuse (Bottle<T> fromBottle, Bottle<T> toBottle) { T drink = fromBottle.empty(); toBottle.fill(drink); } } BottleTransfuser transfuser = new BottleTransfuser (); Bottle<Beer> b1 = new Bottle<Beer>(); b1.fill(new Beer("Jever")); Bottle<Beer> b2 = new Bottle<Beer>(); transfuser.transfuse(b1, b2); Bottle<WhiteWine> b3 = new Bottle<WhiteWine>(); b3.fill(new WhiteWine("Burgunder")); Bottle<WhiteWine> b4 = new Bottle<WhiteWine>(); transfuser.transfuse(b3, b4); transfuser.transfuse(b1, b4); // Fehlermeldung

  33. Generische Methoden / Beispiele (1) class A { public void f() {} } class B extends A { } class C { public <T> void f1(T t) { String str = t.toString(); } public static <T extends A> void f2(T t) { t.f(); } } C obj = new C(); C.f2(new A()); obj.f1("Hallo"); C.f2(new B()); obj.f1(4711); C.f2("Hallo"); // Fehlermeldung

  34. Generische Methoden / Beispiele (2) class C { public static <T> void f3(T t1, T t2) { } public static <T> T f4(T t1, T t2) { return Math.random() < 0.5 ? t1 : t2; } } C.f3(11, "Hallo"); // Supertyp Object C.f3("Hallo", 11); // Supertyp Object String s2 = C.f4("Hallo", "World"); // Supertyp String String s1 = C.f4(11, "Hallo"); // Fehlermeldung Comparable c1 = C.f4(11, "World"); // Supertyp Comparable Die "T" müssen einen gemeinsamen Supertyp haben

  35. Zusammenfassung • Generics: Parametrisierte Klassen • Sinn und Zweck: • Semantische Korrektheit • Vermeidung von Type-Casts • Vermeidung von ClassCast-Exceptions

More Related