Prof. Dr. A. Poetzsch-Heffter Dipl.-Inform. N. Rauch Technische Universität Kaiserslautern Fachbereich Informatik AG Softwaretechnik Lösungsvorschläge zum Übungsblatt 11: Fortgeschrittene Aspekte objektorientierter Programmierung (SS 2007) Aufgabe 1 Generics und Comparable import java.util.Arrays; import java.util.Collections; import java.util.List; abstract class TischA implements Comparable<TischA> { private int numCorners; private int numLegs; private int tableSize; public TischA( int numCorners, int numLegs, int tableSize ){ this.numCorners = numCorners; this.numLegs = numLegs; this.tableSize = tableSize; } public int compareTo(TischA that) { return this.tableSize < that.tableSize ? -1 : this.tableSize == that.tableSize ? 0 : 1; } } class RunderTischA extends TischA { public RunderTischA( int numLegs, int tableSize ){ super( 0, numLegs, tableSize ); } } class EckigerTischA extends TischA { public EckigerTischA( int numCorners, int numLegs, int tableSize ){ super(numCorners, numLegs, tableSize ); } } class TestA { public static void main( String[] s ){ RunderTischA rt1 = new RunderTischA( 4, 100 ); RunderTischA rt2 = new RunderTischA( 1, 120 ); EckigerTischA et1 = new EckigerTischA( 3, 3, 70 ); EckigerTischA et2 = new EckigerTischA( 4, 1, 110 ); List<EckigerTischA> eckig = Arrays.asList(et1, et2); assert Collections.max(eckig) == et2; List<RunderTischA> rund = Arrays.asList(rt1, rt2); assert Collections.max(rund) == rt2; List<TischA> gemischt = Arrays.asList(et1, rt2); assert Collections.max(gemischt) == rt2; System.out.println("Alles ok."); } } import java.util.Arrays; import java.util.Collections; import java.util.List; abstract class TischB { private int numCorners; private int numLegs; private int tableSize; public int getCorners(){ return numCorners; } public int getLegs(){ return numLegs; } public TischB( int numCorners, int numLegs, int tableSize ){ this.numCorners = numCorners; this.numLegs = numLegs; this.tableSize = tableSize; } } class RunderTischB extends TischB implements Comparable<RunderTischB> { public RunderTischB( int numLegs, int tableSize ){ super( 0, numLegs, tableSize ); } public int compareTo(RunderTischB that) { return this.getLegs() < that.getLegs() ? -1 : this.getLegs() == that.getLegs() ? 0 : 1; } } class EckigerTischB extends TischB implements Comparable<EckigerTischB> { public EckigerTischB( int numCorners, int numLegs, int tableSize ){ super(numCorners, numLegs, tableSize ); } public int compareTo(EckigerTischB that) { return this.getCorners() < that.getCorners() ? -1 : this.getCorners() == that.getCorners() ? 0 : 1; } } class TestB { public static void main( String[] s ){ RunderTischB rt1 = new RunderTischB( 4, 100 ); RunderTischB rt2 = new RunderTischB( 1, 120 ); EckigerTischB et1 = new EckigerTischB( 3, 3, 70 ); EckigerTischB et2 = new EckigerTischB( 4, 1, 110 ); List<EckigerTischB> eckig = Arrays.asList(et1, et2); assert Collections.max(eckig) == et2; 2 List<RunderTischB> rund = Arrays.asList(rt1, rt2); assert Collections.max(rund) == rt2; List<TischB> gemischt = Arrays.<TischB>asList(et1, rt2); // assert Collections.max(gemischt) == rt2; // compile-time error System.out.println("Alles ok."); } } Aufgabe 2 Wildcards This is a long, complex generic method signature. Let’s walk through it: The method has a type variable T with complicated bounds that we’ll return to later. The method returns a value of type T. The name of the method is max( ). The method’s argument is a Collection. The element type of the collection is specified with a bounded wildcard. We don’t know the exact type of the collection’s elements, but we know that they have an upper bound of T. That is, we know that the elements of the collection are type T or a subclass of T. Any element of the collection could therefore be used as the return value of the method. That much is relatively straightforward. We’ve seen upper-bounded wildcards elsewhere in this section. Now let’s look again at the type variable declaration used by the max( ) method: <T extends Comparable<? super T> > This says first that the type T must implement Comparable. (Generics syntax uses the keyword extends for all type variable bounds, whether classes or interfaces.) This is expected since the purpose of the method is to find the “maximum” object in a collection. But look at the parameterization of the Comparable interface. This is a wildcard, but it is bounded with the keyword super instead of the keyword extends. This is a lowerbounded wildcard. ? extends T is the familiar upper bound: it means T or a subclass. ? super T is less commonly used: it means T or a superclass. To summarize, then, the type variable declaration states “T is a type that is comparable to itself or to some superclass of itself.” Aufgabe 3 Wildcards package blatt11.lsg; import java.util.List; public class Aufgabe3<T> { private T value; public List<? super T> addValue(List<? super T> l) { l.add(value); return l; } public List<? extends T> extractValue(List<? extends T> l) { value = l.remove(0); return l; } public List<T> replaceValue(List<T> l) { l.add(value); value = l.remove(0); return l; } 3 } Aufgabe 4 Generics und Typauslöschung a) Eine nicht-generische Variante der Klasse StringList könnte so aussehen: package blatt11.lsg; import java.util.ArrayList; public class StringList extends ArrayList { private static final long serialVersionUID = 1L; @Override public boolean add(Object s){ return add((String)s); } public boolean add(String s){ return super.add("String # " + (size()+1) + ": " + s ); } @Override public String get(int index) { return "At pos " + index + ": " + super.get(index); } } b) Methoden der generischen Klasse StringList: public public public public java.lang.String blatt11.StringList.get(int) volatile java.lang.Object blatt11.StringList.get(int) boolean blatt11.StringList.add(java.lang.String) volatile boolean blatt11.StringList.add(java.lang.Object) (Es sollte eigentlich bridge heißen statt volatile, dies ist ein Fehler in Java 5.) c) In diesem Fall werden keine Methoden in die Klasse StringListLeer hineingeneriert. Die generierten Methoden decken ja den Fall ab, dass ein Typparameter in einer Methodensignatur durch einen konkreten Typ ungleich Object ersetzt wurde und bei der Typauslöschung damit keine Überschreibungsbeziehung mehr vorhanden ist, da die Methodensignatur den Typparameter durch Object ersetzt. Da in StringListLeer jedoch keine Methode überschrieben wurde, tritt der Fall gar nicht auf. 4