Polymorphism & Methods COMP206 Geoff Holmes & Bernhard Pfahringer (these slides: lots of input from Mark Hall) poly + morphos (greek) “many forms”
Overriding Subclass redefines a method: –different behaviour –or maybe modified behaviour class Rectangle { public String toString() { return “ ”; }
Inheritance Subclasses inherit everything from superclasses, but cannot directly access private fields or methods, only public and protected ones. Can still access overridden methods: public void roam() { super.roam(); // some additional local stuff }
Inheritance: Is-A (not Has-A) B should extend A if “B is-A A” –Triangle Is-A Shape –Surgeon Is-A Medical Doctor Bathroom Has-A Tub –Tub is an instance variable of Bathroom (Composition)
Code Inheritance Use inheritance to implement shared behaviour (code) only once! Always avoid code duplication! –easier to change (only one place), especially when debugging
Polymorphism what happens when one declares and initializes a reference variable: Dog myDog = new Dog(); allocate space for reference variable of type Dog allocate space for a new Dog object on the heap (and initialize it) point the reference to the new object
Polymorphism Reference type can be any super class or Interface implemented by actual type: Animal myDog = new Dog(); As generic as possible => more flexible code: Map myMap = new HashMap ();
Polymorphism Animal[] animals = new Animal[]{new Dog(), new Lion(), new Cat(), new Wolf(), new Hippo()}; for(Animal a: animals) { a.eat(); a.roam(); }
Polymorphism Parameters/Arguments and return values can be polymorphic too: class Vet { public void giveShot(Animal a) { a.makeNoise(); } class PetOwner { public void start() { Vet v = new Vet(); Dog d = new Dog(); Hippo h = new Hippo(); v.giveShot(d); v.giveShot(h); }
How to stop overriding: final declaration: –class: cannot extend/subclass any further final public class String {.. } –method: cannot be overridden in subclasses class Cat { final public void makeNoise() {…} –field: cannot change value final int count = animals.length;
Overriding rules Argument and return type must be the same: class Appliance { public boolean turnOn(); } class Toaster extends Appliance { public boolean turnOn(int level); // OVERLOADING }
Overriding rules May NOT be less accessible: class Appliance { public boolean turnOn(); } class Toaster extends Appliance { protected boolean turnOn(); // illegal }
Overloading Two (or more) methods with the same name but different argument lists (see code example) Usually best avoided, can be very confusing and counter-intuitive
Which method is executed Compile time: compiler ensures that method with appropriate signature (compile-time type info for arguments) exists in “compile-time” receiver class Runtime: given the actual runtime-type of the receiver, the most specific method of appropriate signature is located and executed ==> runtime types of arguments do NOT matter (again, see code examples)
Java Generics (with input from Robi Malik)
Generic types for collections Old Java (1.4 and older): List strings = new ArrayList(); strings.add(“hello”); String word = (String) strings.get(0); New (since 1.5): List strings = new ArrayList (); strings.add(“hello”); String word = strings.get(0);
Advantages Better readability Better type-safety: no casts (runtime checks), compiler can already catch problems
Writing your own generic code public class Stack { public void push(E element) { contents.add(element); } public E pop() { int top = contents.size()-1; E result = contents.get(top); contents.remove(top); return result; } private List contents = new ArrayList (); }
Formal type parameter public class Stack { … } –convention: Short (single-char) uppercase –can be used wherever a Type is needed –will be replaced with actual Type
Problems with sub-types class Student extends Person {.. } List students = new ArrayList (); List people = students; // should this be possible? -> no
No, because Person sam = new Person(); people.add(sam); // if this was legal, we would have just sneaked a non- student onto the students list on the other hand, how do you write generic code then accepting lists of sub-types of Persons ???
Wildcards void printCollection(Collection c) { for(Object o: c) { System.out.println(o); } // only read access (everything is an Object), but cannot add, because do not know correct type (except null, which is any type)
Bounded wildcards public void drawAll(Collection c) { for(Shape shape: c) { shape.draw(); } // again, only read access, allows collections of Shape or any sub type of Shape