Download Tirgul 8

Document related concepts
no text concepts found
Transcript
Tirgul 8
Inheritance and Polymorphism
1
Inheritance and Polymorphism



An important part of Object Oriented Programming.
Very often misused by beginners.
Inheritance: If the parent can do something, so can
the child.


Allows for code re-use (not as important as other traits –
there are other ways we’ve seen to re-use code)
Polymorphism: The ability to write code that works
for many types.


Inheritance enables this. This is the main benefit.
Examples will follow…
2
Class hierarchy example
Car
PrivateCar
Toyota
Mazda
CommercialCar
…
Subaru
…
Mazda121
Mazda323
…
Mazda626
PrivateCar is a type of Car. It does anything Car does,
and more.
We say that PrivateCar extends Car.
3
Extending a class
public class Car {…}
public class PrivateCar extends Car{…}



You can only extend one class.
The extended class is often called: Parent
Class, Super Class, Ancestor, Base Class.
The extending class is called: Child, SubClass, Descendent, Derived Class.
4
Inheritance
When a class extends another class it automatically
inherits all of its members (Both methods and
fields). However, it can access only the public and
protected members.
 Implication: Child class can handle any method call
that Parent class can.
 There is no way to “hide” any of the inherited
methods.
Car car = new Car();
PrivateCar privCar = new PrivateCar();
 If you can do
car.honk();
 You can also do
privCar.honk();

5
Constructors and the keyword
super

The parent class has fields that must be initialized
during creation of the child class.



Therefore: any time a constructor of the child is
called, the constructor of the parent is also called.
Accomplished with: super()


They may even be private and not accessible to the child.
Must be the first statement in the constructor.
If you do not use super() Java calls the default
constructor of the parent.

If there is no default, the code will not compile!
6
Extending a class
Other Classes
Public
Public
Protected
Protected
Private
Private
Parent Class
Child Class
7
Example
No one except the
class Person can
initialize the field
_name.
public class Person{
private final String _name;
public Person(String name){
_name = name;
}
public String getName(){ return _name;}
}
because it is final,
initialization of
_name must occur
at creation time.
public class CSStudent extends Person{
private String _login;
public CSStudent(String name, String login){
super(name);
_login = login;
}
}
8
Upcasting


We can always treat a child object as if it were a
parent object
Upcasting is converting from child type to parent
type (always safe)
PrivateCar prvCar = new PrivateCar();
explicit upcasting
Car car1 = (Car) prvCar;
Car car2 = prvCar;
implicit upcasting
car1.honk(); car2.honk();
9
Downcasting


Downcasting is converting from parent type
to child type (not always safe!)
Downcasting must always be explicit
Car car1 =
PrivateCar
PrivateCar
Car car2 =
PrivateCar
new PrivateCar();
implicit upcasting
prvCar = car1;
implicit downcasting: compile error
prvCar1 = (PrivateCar) car1;
new Car();
downcasting - OK
prvCar2 = (PrivateCar) car2;
This will cause a runtime ClassCastException: Car cannot be converted to PrivateCar
10
Why upcast?

Suppose you want to built a data structure
that could only hold Strings.



What if we want to hold something else?
Do we write a new structure for every type of
object we create?
Instead: write a structure that holds
java.lang.Object


use upcasting when putting in values,
and downcasting when extracting.
11
Upcasting and Downcasting
public class MyStructure{
private Object[] _data;
public Insert(Object element){…}
public Object Remove(){…}
…
}
Somewhere else in the code:
String str = “Hello”;
struct.insert(str); //upcasting
str = (String) struct.remove(); //downcasting
Is it safe to downcast here?
12
instanceof


What if we mix items of different types in the
structure and wish to downcast correctly?
We can check the exact type of the class
using the keyword “instanceof”
Object item = struct.remove();
if(item instanceof String){
String str = (String) item; //this is safe!
...
}
13
instanceof
(a instanceof B) is true iff a is an
instance of class B or any of its descendants
Car car = new Car();
System.out.print(car instanceof Object);
true
System.out.print(car instanceof Car);
true
System.out.print(car instanceof PrivateCar);
false
14
How not to use instanceof


Our code should be designed so that adding new child
classes does not necessitate changes to the parent class
Do not do this:
public class PrivateCar {
public void print() {
if (this instanceof Mazda)
System.out.print(“Mazda”);
if (this instanceof Toyota)
System.out.print(“Toyota”);
}
}

Instead: use method overriding…
15
Overriding methods

Objects inherit methods from their parent, but may
change the methods they inherit.


Simply redefine them.
The keyword super can be used to call methods
from the parent class and thus reuse their code.
public class CSStudent extends Person{
private String _login;
...
public String getName(){
return super.getName() + “ “+ _login;
}
}
16
Polymorphism



The inheritance mechanisms we’ve seen
allow using objects that have a shared
ancestor interchangeably
We do not need to know the exact type of
the object we are holding
The “correct” implementation of overridden
methods will be called at runtime
17
Polymorphic use of objects


All the mechanisms we’ve just seen give us power
to use objects that have a shared ancestor
interchangeably.
We do not need to know the exact type of object
we are holding.
Example:
public class Animal(){
public void makeSound(){}
…
}
18
Subclasses of animal.
public class Dog extends Animal{
public void makeSound() {
System.out.println("Woof Woof");
}
}
public class Cat extends Animal{
public void makeSound() {
System.out.println("Meow");
}
}
public class Bird extends Animal{
public void makeSound() {
System.out.println(“Tweet Tweet");
}
}
19
public static void main(String[] args){
Animal[] animals = new Animal[3];
animals[0] = new Dog();
animals[1] = new Cat();
animals[2] = new Bird();
for(int i=0; i<animals.length; i++){
animals[i].makeSound();
}
}
This last bit of code can
treat all kinds of animals.
Even those that are not
written yet.
Output:
Woof Woof
Meow
Tweet Tweet

20
Abstract classes & methods

Abstract methods have no implementation.





They must reside inside abstract classes
If the child class is not abstract, it must
implement all abstract methods.
Abstract classes cannot be instantiated.
Useful for things we don’t want an instance
of.
They may still have constructors. (What for?)
21
Abstract Animal

We do not want anyone to create an object
out of the Animal class. We make it abstract:
public abstract class Animal(){
public abstract void makeSound();
…
}

We also turned makeSound() into an abstract
method


because we want all subclasses to implement it
But cannot offer a “default” implementation that
is inherited.
22
Abstract - Example
abstract class Shape {
Notice the abstract
abstract void draw() ;
method declaration
abstract void erase();
abstract double area();
}
class Circle extends Shape {
void draw() {
System.out.println("Circle.draw()");
}
void erase() {
System.out.println("Circle.erase()");
}
double area(){
System.out.println(“pi*r^2");
…
}
}
23
Abstract - Example (cont.)
class Square extends Shape {
void draw() {
System.out.println("Square.draw()");
}
void erase() {
System.out.println("Square.erase()");
}
double area(){
System.out.println(“base*height");
…
}
}
class Triangle extends Shape {
void draw() { System.out.println("Triangle.draw()");}
void erase() { System.out.println("Triangle.erase()“);}
double area() { System.out.println("Triangle area…");
…
}
}
24
Random shapes generator
// A "factory" that randomly creates shapes
class RandomShapeGenerator {
public Shape next() {
int randNum=(int) Math.random()*3;
switch(randNum) {
case 0: return new Circle();
break;
case 1: return new Square();
break;
case 2: return new Triangle();
break;
default: break;
}
}
}
25
Casting and arrays
public class Shapes {
private static RandomShapeGenerator gen =
new RandomShapeGenerator();
public static void main(String[] args) {
Shape[] s = new Shape[9];
We don’t know
what
shapes are
// Fill up the array with shapes:
created and
for(int i = 0; i < s.length; i++)
inserted to s
s[i] = gen.next();
// Make polymorphic method calls:
for(int i = 0; i < s.length; i++)
s[i].draw();
}
}
Polymorphism!
(No explicit casting and no ‘instance
of’ check are needed)
26
Polymorphism and arrays – typical run
>>
Square.draw()
Circle.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Circle.draw()
Square.draw()
Square.draw()
Square.draw()
27
Interfaces
Not the same interface we talk about when
we discuss API.
Rather: a java construct (similar to a class).
28
Interfaces



The most frequent use of polymorphism is
usually via interfaces.
They are like abstract classes with all
methods abstract.
The difference: An object can implement
several interfaces.
29
Interface syntax
public interface CanCopy {
public Object copy();
}
Place this in a file named
CanCopy.java
public interface Printable {
public void print();
}
Place this in a file named
Printable.java
public class Child extends Parent implements CanCopy,
Printable {
public Object copy() {…}
public void print() {…}
…
}
30
public Interface Closeable{
public void close();
}
Place this in Closeable.java.
Notice there is no
implementation of close()
public class Child extends Parent implements Closeable{
public void close(){}
This class must implement
}
all methods in the interface,
or be abstract.
Public class A extends B implements C,D,E{
…
Promises to implement
}
several interfaces.
31
Example: Comparable
This interface imposes an ordering on the
objects of each class that implements it
public interface Comparable {
/** Compares this object with the given
object.
Returns a negative integer, zero, or a
positive integer if this object is
smaller, equal, or larger than the
given object. */
public int compareTo(Object obj);
}
32
Implementing Comparable
We will compare people based on their weight
public class Person implements Comparable {
private int _weight;
private String _name;
What will happen if
public int compareTo(Object obj) {
someone tries to compare
Person other = (Person) obj;
a Person to an object
if (_weight == other._weight)
which is not a Person?
return 0;
return _weight < other._weight ? -1 : 1;
}
…
}
33
Using Comparable: findMax
We can use this method on an array of any type of
objects which implement the Comparable interface
/** Returns the maximal item in a given array */
public static Comparable findMax (Comparable[] items) {
Comparable max = items[0];
for (int i=1; i<items.length; i++) {
if (max.compareTo(items[i]) < 0) {
max = items[i];
}
What are this method’s assumptions?
}
return max;
}
34
Using findMax
public static void printFattest(Person[] people)
{
Person fattest = (Person) findMax(people);
System.out.print(“The fattest person is “ +
fattest.getName() + “, weighing “ +
fattest.getWeight() + “ kg!”);
}
What if we sometimes want to compare people based on different criteria?
35
Iterator
Similarly to DigitsParser (from Ex. 3), we
can define a general iterator. This
iterator can iterate over a collection
(and not only string).
public interface Iterator {
public Comparable next();
public boolean hasNext();
}
36
Implementing the interfaces:
Now, every class that would like to
implement iterator will have to “stick”
the Iterator interface description.
public class DigitsIterator implements Iterator{
public boolean hasNext() {...}
public Comparable next() {...}
...
}
37
Now we can write code that fits
any data structure:
public static boolean isInside(Iterator iter,
Comparable item){
while(iter.hasNext()){
if (iter.next().compareTo(item)==0){
return true;
}
}
return false;
}
This will work for any iterator, regardless of the data
structure it is linked to.
38
The Comparator interface
This interface will be implemented by objects
that know how to compare other objects
public interface Comparator {
/** Compares two objects.
Returns a negative integer, zero, or a
positive integer if obj1 is smaller,
equal, or larger than obj2. */
public int compare(Object obj1,
Object obj2);
}
39
Implementing Comparator (1)
This class compares people based on their weight
public class PersonWeightComparator implements
Comparator {
public int compare(Object obj1, Object obj2) {
Person person1 = (Person) obj1;
Person person2 = (Person) obj2;
int weight1 = person1.getWeight();
int weight2 = person2.getWeight();
if (weight1 == weight2)
return 0;
return weight1 < weight2 ? -1 : 1;
}
}
40
Implementing Comparator (2)
This class compares people based on their name
public class PersonNameComparator implements
Comparator {
public int compare(Object obj1, Object obj2) {
Person person1 = (Person) obj1;
Person person2 = (Person) obj2;
String name1 = person1.getName();
String name2 = person2.getName();
return name1.compareTo(name2);
}
Class String implements the java.lang.Comparable
}
interface, comparing strings lexicographically
41
findMax using Comparator
Now this method may give different results for the
same array, based on the given Comparator
/** Returns the maximal item in a given array */
public static Object findMax (Object[] items,
Comparator comp) {
Object max = items[0];
for (int i=1; i<items.length; i++) {
if (comp.compare(max, items[i]) < 0) {
max = items[i];
}
}
return max;
}
42
Using findMax with a Comparator
public static void printFattest(Person[] people)
{
Comparator comp = new PersonWeightComparator();
Person fattest = (Person) findMax(people,
comp);
System.out.print(“The fattest person is “ +
fattest.getName() + “, weighing “ +
fattest.getWeight() + “ kg!”);
}
43
Using findMax with a Comparator
public static void printFirst(Person[] people)
{
Comparator comp = new PersonNameComparator();
Person first = (Person) findMax(people,
comp);
System.out.print(“The person whose name “ +
“comes first alphabetically is “ +
first.getName());
}
44
Misc. Notes on Inheritance
45
Interfaces can extend interfaces

We can have inheritance within interfaces.
public interface A{ ... }
public interface B extends A{...}
public class C implements B{...}
Now, everyone that implements B, must also
implement all of A’s methods.
C obj = new C();
B obj2 = obj;
//upcasting
A obj3 = obj; //upcasting
46
Reminder: Casting and arrays

Arrays can be cast to parent types and back.
public static void main(String[] args){
Object[] objArr = new String[5];
Upcasting
objArr[0] = "Hi";
System.out.println(objArr instanceof String[]);
String[] strArr = (String[]) objArr;
System.out.println(strArr[0]);
Downcasting
}
47
final classes and methods



A final method cannot be overridden.
A final class cannot be extended.
For example, you may want to declare
methods that are called from a constructor
final, so they are not changed by accident by
extending classes.
48
Static methods are inherited but
aren’t polymorphic!
public class Parent {
public static void myMethod(){
System.out.println("Parent");
}
}
public class Child extends Parent {
public static void myMethod(){
System.out.println(“Child");
}
}
public static void main(String[] args){
Parent obj = new Child();
obj.myMethod();
}
Output:
Parent
49
When to extend and when to
reference?



Sometimes we have objects that use other
objects.
Sometimes we have objects that extend
other objects.
When do we use each method?
public class Person{
public Person(String name){…}
public String getName(){…}
public Person[] getListOfFriends(){…}
}
50
When to extend and when to
reference?
public class Car {
Car
_driver
private Person _driver;
public Car(Person driver, double topSpeed){
_driver = driver;
Person
}
public String getDriverName(){…}
Can both classes do the
public double getTopSpeed(){…}
same things? Yes!
}
Which is better?
public class Car extends Person{
public Car(String driverName, double topSpeed){
super(driverName);
_topSpeed = topSpeed;
}
public double getTopSpeed(){…}
}
Person
Car
51
When to extend and when to
reference?


Extend mostly when you want to use objects
interchangeably.
Otherwise you may inherit methods that are
not sensible


No way to hide methods…
Usually, you should reference.
52
Collection interface





Collection is an abstract representation of a …
collection/group of items/elements – an object
that holds other objects (also called container).
Typically, collections are iterable.
Elements in a collection have no specific order.
Queue, stack, arrays, sets and many other more
data structures (to be learnt in the next
semester/year) can be implemented using the
collection interface.
Check the interface for the Collection type in
Java. (http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collection.html )
53
Partial interface for collection
Public interface Collection {
public boolean add (Object o);
public boolean contains(Object o);
public boolean isEmpty();
public boolean remove(Object o);
public Iterator iterator();
public Object[] toArray();
There are no guarantees
}
concerning the order in which
Elements are returned in the
same order of the iterator
the elements are returned
(unless this collection is an
instance of some class that
provides a guarantee)
54
Call by Reference vs.
Call by Value – Test Yourselves
public void swap0(int a, int b){
int temp = a;
a = b;
b = temp;
}
public void swap1(int[] a, int[] b){
int[] temp =a;
a = b;
b = temp;
}

Which of these is useless?
55
Call by Reference vs.
Call by Value – Test Yourselves
public void swap2(int[] a, int[] b){
int[] temp =a.clone();
a = b.clone();
b = temp;
}
public void swap3(int[] a, int[] b){
for(int i=0; i<a.length; i++){
int temp = a[i];
a[i] = b[i];
b[i] = temp;
}
}

Which of these is useless?
56