1 / 37

241-423 Advanced Data Structures and Algorithms

241-423 Advanced Data Structures and Algorithms. Objective explain how subtyping/subclassing and generics are combined in Java introduce covariance and contravariance. Semester 2, 2013-2014. 7 . Subtypes/subclassing and Generics. Contents. The Substitution Principle

ady
Download Presentation

241-423 Advanced Data Structures and Algorithms

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. 241-423 Advanced Data Structures and Algorithms Objective explain how subtyping/subclassing and generics are combined in Java introduce covariance and contravariance Semester 2, 2013-2014 7. Subtypes/subclassing and Generics

  2. Contents • The Substitution Principle • Subtyping of An Entire Collection • Subtyping/subclassing Terminology • Covariance: ? extends • Contravariance: ? super • The Get and Put Principle (PECS) • No Instance Creation with ?

  3. 1. The Substitution Principle • You can assign an object of any subclass to a class reference (variable). Integer i = new Integer(6); Number n = i; Number extends Float Integer n Integer object Number reference i

  4. Apple a = new Apple(); Fruit f = a; Fruit extends Apple Strawberry f Apple object Fruit reference a

  5. Subtyping of Collection Elements • We can add an integer or a double to a collection of Numbers, because Integer and Double are subclasses of Number. List<Number> nums = new ArrayList<Number>(); nums.add(2); nums.add(3.14); // OK

  6. Number references nums . . . List<Number> reference List<Number> object 3.14 2 Integer object Double object

  7. 2. Subtyping of An Entire Collection • You might think that since Integer is a subclass of Number, then List<Integer> is a subclass of List<Number>. NO!!! List<Integer> ints = Arrays.asList(2, 3); List<Number> nums = ints; // compile-time err

  8. Integer references ints nums . . . List<Number> reference List<Integer> object 3 2 Integer object Double object

  9. Why? • It's to prevent run-time errors such as the following: List<Integer> ints = new Integer[] {1,2}; List<Number> nums = ints; // compile-time error nums.add(3.12); // run-time error (not reached)

  10. Another Example List<Apple> apples = ...; List<Fruit> fruits = apples; // compile-time error

  11. Arrays are Different • Just to confuse matters, Integer[] isa subclass of Number[]. Integer[] ints = new Integer[] {1,2,3}; Number[] nums = ints; // OK nums[2] = 3.12; // run-time error (will be reached)

  12. 3. Subtyping/subclassing Terminology • Covariance: a class reference (variable) can point to a 'narrower' subclass object • e.g. Fruit f = new Apple(); • narrower means "more specific" • Contravariance: a class reference (variable) can point to a 'wider' superclass object • e.g from Integer to Number • not common in Java • Invariant: not able to convert

  13. Arrays are covariant: • Integer[] is also a Number[] • Basic Generic classes are not covariant and not contravariant: they are invariant • For example: • List<Integer> is not a subclass List<Number> • Also List<Number> is not a subclass of List<Integer>

  14. Adding Covariance and Contravariance • It is useful to allow covariance and contravariance in collections, so the Java designers added: • ? extends (extends wildcard) for covariance • ? super (super wildcard) for contravariance

  15. 4. Covariance: ? extends List<Integer> ints = Arrays.asList(1,2); List<? extends Number> nums = ints; // OK • "? extends Number" means that it is OK to assign a subclass collection of Number to nums • in this case, a collection of Integers

  16. But we cannot put elements into the collection... List<Integer> ints = Arrays.asList(1,2); List<? extends Number> nums = ints; // OK nums.add(3.12); // compile-time error • This is the array situation, but with one big difference • the error is caught at compile-time

  17. Another ? Extends Example List<Apple> apples = new ArrayList<Apple>(); List<? extends Fruit> fs = apples; // OK fs.add(new Strawberry()); //compile-time err • The code won't compile even if we try to add an Apple or a Fruit instance fs.add(new Apple()); //compile-time err fs.add(new Fruit()); //compile-time err

  18. The restriction is because the compiler only knows that fsrefers to a collection subclass of Fruit, but not which one.

  19. The only thing we can add is null: fruits.add(null); // ok • We can get data out of the structure but only as a Fruit instance (the ? extends class): Fruit get = fruits.get(0);

  20. Summary of ? extends • It allows the assignment of a subclass collection to a superclass collection reference, but no element assignments are possible • quite restrictive • Values can be removed, as instances of the superclass • useful Good for 'getting'

  21. 5. Contravariance: ? super List<Object> objs = Arrays.<Object>asList(1,"two"); List<? super Integer> vals = objs; vats.add(3); // ok • ? super allows a superclasscollection of Integer to be assigned to vals • in this case, a list of Objects • Andyou can add subclasselements to the collection later.

  22. Another ? super example List<Fruit> fruits = new ArrayList<Fruit>(); List<? super Apple> apps = fruits; apps.add(new Apple()); // OK apps.add(new GreenApple()); // OK apps.add(new Fruit()); // compile-time error apps.add(new Object()); // compile-time error • Only subclass elements of Apple can be added.

  23. Why? • The compiler knows that appsrefers to a superclass collection of Apple. • It does not know which class, but all superclasses of Apple can store subclasses of Apple as new elements.

  24. Get Restriction with ? Super • You can only get elements out of a ? super object as values of class Object: Object ob1 = fruits.get(0); Object ob2 = fruits.get(1); Fruit f = (Fruit) fruits.get(0); // compile-time err

  25. Another Example List<Object> objs = Arrays.<Object>asList(1,"two"); List<? super Integer> ints = objs; String str = ""; for (Object obj : ints) str += obj.toString(); // Object method // str is "1two"

  26. Summary of ? super • It allows the assignment of a superclass collection to a subclass reference, and further subclass additions are possible • useful • Values can only be removed as Object instances • quite restrictive Good for 'putting'

  27. 6. The Get and Put Principle (PECS) • use ? extends when you only getvalues out of a collection; i.e. is a producer • use ? super when you only putvalues into a collection; i.e. is a consumer • don't use a wildcard when you both get and put • PECS comes from "Producer Extends, Consumer Super"

  28. ? extends Function example PECS public static double sum( Collection<? extends Number> nums) { double s = 0.0; for (Number num : nums) s += num.doubleValue(); return s; } producer (a Number method)

  29. The following calls are legal: List<Integer> ints = Arrays.asList(1, 2, 3); double d = sum(ints); // == 6.0; List<Double> doubles = Arrays.asList(2.78, 3.14); double d = sum(doubles); // == 5.92; List<Number> nums = Arrays.<Number>asList(1, 2, 2.78, 3.14); double d = sum(nums); // == 8.92; • The first two calls would not be legal if ? extends was not used.

  30. ? super function example PECS public static void count( Collection<? super Integer> ints, int n) { for (int i = 0; i < n; i++) ints.add(i); } consumer

  31. The following calls are legal: List<Integer> ints = new ArrayList<Integer>(); count(ints, 5); // ints.toString().equals("[0, 1, 2, 3, 4]"); List<Number> nums = new ArrayList<Number>(); count(nums, 5); nums.add(5.0); // nums.toString().equals("[0, 1, 2, 3, 4, 5.0]"); List<Object> objs = new ArrayList<Object>(); count(objs, 5); objs.add("five"); // objs.toString().equals("[0, 1, 2, 3, 4, five]"); • The last two calls need ? super in count()

  32. ? super No wildcard example Number public static double sumCount( Collection<Number> nums, int n) { count(nums, n); return sum(nums); } • The nums collection is passed to both sum() and count(), so its element class must both extend Number (as sum() requires) and be super to Integer (as count() requires). Integer ? extend

  33. ? super Number • The only two classes that satisfy both of these constraints are Number and Integer, and I picked the first. • A sample call: List<Number> nums = new ArrayList<Number>(); double sum = sumCount(nums,5); Integer ? extend

  34. Using both ? extends and ? super PECS public static <T> void copy( List<? super Integer> dst, List<? extends Integer> src) { for (int i = 0; i < src.size(); i++) dst.set(i, src.get(i)); } • the destination list may already contains elements of any class that is a superclass of Integer • the source list will have elements of any class that is a subclass of Integer.

  35. A sample call: List<Object> objs = Arrays.<Object>asList(2, 3.14, "four"); List<Integer> ints = Arrays.asList(5, 6); Collections.copy(objs, ints); // objs is "[5, 6, four]"

  36. 7. No Instance Creation with ? • For example, the following are illegal: List<?> list = newArrayList<?>(); // compile-time error Map<String, ? extends Number> map = newHashMap<String, ? extends Number>(); // compile-time error

  37. Usually we create a concrete collection first, even if we use wildcards later: List<Number> nums = new ArrayList<Number>(); List<? super Number> sink = nums; // OK for (int i=0; i<10; i++) sink.add(i);

More Related