Polymorphism ============ * A function or operator is polymorphic if it has at least two possible types - It exhibits ad hoc polymorphism if it has at least two but only finitely many possible types - Overloading - Coercion - It exhibits universal polymorphism if it has infinitely many possible types. - Subtyping - Parametric 2) What is overloading? 2.1) Can anyone give me an example? public class Square { public static int square(int a) { System.out.println("Square of int: " + a); return a * a; } public static double square(double a) { System.out.println("Square of double: " + a); return a * a; } public static void main(String args[]) { square(1); square(1.0); } } 2.2) What if I change the signature of square(double) to public static double square(int a)? 3) What is a type coercion? 3.1) Can anyone give me one example? double sumX(double a, double b) { return a + b; } int main() { std::cout << "The sum is " << sumX(1, 2.0) << std::endl; } 4) Which calls are legal? public class Coercion { public static void f(double x) { System.out.println(x); } public static void main(String args[]) { f(3.1416); f((byte)1); f((short)2); f('a'); f(3); f(4L); f(5.6F); } } * Tricky iterations: - overloading uses the types to choose the definition. - Coercion uses the definition to choose a type conversion. 5) Which functions get called? public static void main(String args[]) { square(1); square(1.0); square('a'); } 5.1) And in this case? public class Conflict { public static void sum(int a, int b) { System.out.println("Sum of int: " + (a + b)); } public static void sum(double a, double b) { System.out.println("Sum of double: " + (a + b)); } public static void main(String args[]) { sum(1, 2); sum(1.1, 2.2); sum(1, 2.2); sum((int)1.1, (int)2.2); } } 6) Which type of polymorphism is happening here? public class Sub { public static void print(Object o) { System.out.println(o); } public static void main(String[] a) { print(new String("dcc024")); print(new Integer(42)); print(new Character('a')); } } 7) Does anyone remember Liskov's substitution principle? If S is subtype of T, then S can be used in any situation where T is expected. * Generics ---------- 8) What is the problem with this code? import java.util.List; import java.util.LinkedList; public class BadExample { public static void main(String args[]) { List myIntList = new LinkedList(); myIntList.add(new Integer(0)); Integer x = (Integer) myIntList.iterator().next(); } } 8.1) What is the meaning of the warning? Note: BadExample.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 9) How to improve it? List myIntList = new LinkedList(); myIntList.add(new Integer(0)); Integer x = myIntList.iterator().next(); 9.1) But, is there any different between moving the clutter from (Integer) to ? 10) How can we define a generic class? public interface Cont { E get(); void set(E e); } public class ContImpl implements Cont { private E e; public E get() { return e; } public void set(E e) { this.e = e; } public static void main(String args[]) { ContImpl c = new ContImpl(); c.set(2); System.out.println(c.get()); } } 11) Is this code legal? import java.util.List; import java.util.ArrayList; public class Gen1 { public static void main(String args[]) { List ls = new ArrayList(); List lo = ls; } } 11.1) What is the problem? lo.add(new Object()); String s = ls.get(0); * In general, if S is subtype of T, then it is not the case that G is subtype of G. 12) How to generalize the code below? import java.util.ArrayList; public class Gen2 { public static void printCollection(Collection c) { Iterator i = c.iterator(); while (i.hasNext()) { System.out.println(i.next()); } } public static void main(String args[]) { List ls = new ArrayList(); ls.add("Fernando"); ls.add("Magno"); printCollection(ls); } } 12.1) What about this attempt to improve it? void printCollectionObj(Collection c) { for (Object e : c) { System.out.println(e); } } ... public static void printCG(Collection c) { for (Object e : c) { System.out.println(e); } } 13) Is this safe? Collection c = new ArrayList(); 13.1) Why? c.add(new Integer()); 14) Can I do: public static void printCollection(Collection c) { c.add(new Object()); } 14.1) What about: void printCollectionObj(Collection c) { c.add(new Object()); } 14.2) And what about: public static void printCG(Collection c) { c.add(new Object()); } 15) How to make the program below more general: import java.util.List; import java.util.LinkedList; class Animal { public void eat() { System.out.println(this + " is eating"); } public String toString () { return "Animal"; } } class Mammal extends Animal { public void suckMilk() { System.out.println(this + " is sucking"); } public String toString () { return "Mammal"; } } class Dog extends Mammal { public void bark() { System.out.println(this + " is barking"); } public String toString () { return "Dog"; } } public class Zoo { public static void feedAll(List animals) { for (Animal a: animals) { a.eat(); } } public static void main(String a[]) { List dogs = new LinkedList(); dogs.add(new Dog()); feedAll(dogs); } } - Use a bounded wild-card: public static void feedAll(List animals) { for (Animal a: animals) { a.eat(); } } 16) But, can we do this? public static void feedAll(List animals) { animals.add(new Animal()); } Summary: - Overloading: each different type requires a separate definition. ad-hoc. - Coercion: all the conversions must be defined in the language spec. ad-hoc - Parametric: infinite as long as the universe over which type variables are instantiated is infinite. - Subtype: infinite, as long as there is no limit on the number of subtypes of a type. 17) Implement the generic stack: import java.util.ArrayList; public class Stack { ArrayList stack; public Stack(int capacity) { stack = new ArrayList(capacity); } public E pop() { E e = stack.remove(stack.size() - 1); return e; } public void push(E e) { stack.add(e); } public boolean empty() { return stack.size() == 0; } } 18) Implement a reduce method on top of this stack: T reduce(Combinator comb, T seed) { while (!empty()) { seed = comb.combine(seed, pop()); } return seed; } 19) Implement the Concatenator as a combinator: public class Concatenator implements Combinator { public String combine(String acc, String element) { return acc + element; } } 20) Implement the word counter as a combinator: public class WordCounter implements Combinator { public Integer combine(Integer acc, String element) { return new Integer(acc + element.length()); } }