Lecture IV - Polymor..

advertisement
Inheritance - Polymorphism
ITI 1121
Nour El Kadri
Polymorphism
 From the Greek words polus = many and
morphˆe = forms, literally means has
many forms.
 In Java, a variable or a method is
polymorphic if it refers to objects of more
than one “class/type”.
Method overloading
 Method overloading means that two
methods can have the same name but
different signatures (the signature
consists of the name and formal
parameters of a method but not the
return value).
 Constructors are often overloaded, this
occurs for the class Shape:
Shape () {
x = 0.0;
y = 0.0;
}
Shape (int x, int y) {
this.x = x;
this.y = y;
}
method overloading is sometimes referred to as
ad hoc polymorphism.
Overloading (cont’d)
 In Java certain operators are overloaded,
consider the “+” which adds two numbers or
concatenates two strings, a user can
overload a method but not an operator.
 Since the signatures are different, Java has
no problem finding the right method:
static int sum(int a, int b, int c) {
return a + b + c;
}
static int sum(int a, int b) {
return a + b;
}
static double sum(double a, double b) {
return a + b;
}
Motivation
 We need to write a new method that compares
two Shapes. In particular, a shape will be
considered smaller than another if its area is
smaller than the area of that shape.
 Since there are more than one kind of Shapes,
we could write methods with the same name
and all four possible signatures (method
overloading):

(Circle, Circle), (Circle, Rectangle), (Rectangle,
Circle) and (Rectangle, Rectangle).
public class Test extends Object {
public static int compare(Circle c, Circle d) {
return compare(c.area(), d.area());
}
public static int compare(Circle c, Rectangle r) {
return compare(c.area(),r.area());
}
public static int compare(Rectangle r, Circle c) {
return compare(r.area(),c.area());
}
public static int compare(Rectangle r, Rectangle s) {
return compare(r.area(),s.area());
}
private static int compare(double a, double b) {
int result;
if (a < b)
result = -1;
else if (a == b)
result = 0;
else
result = 1;
return result;
}
public static void main(String args[]) {
Circle c = new Circle(100, 100, 5);
Rectangle r = new Rectangle(0, 0, 10, 15);
int result = compare(c, r);
}
}
What do you think?
What are the problems with this proposal?



the bodies of all the methods are identical;
if there were 3 kinds of shapes there would
be 9 methods!
each time a new shape is defined new
methods must be created.
Clearly there has to be a better way to
implement such a method!
How does it work?
 What would be necessary for such a
method to work?
 The arguments can be any objects that
implement the method area.
static int compare(‘‘Any shape’’ a, ‘‘Any shape’’ b) {
return compare(a.area(), b.area());
}
Polymorphic variables
 A polymorphic variable refers to objects
of more than one class.
 Consider the following statement, s is a
polymorphic variable,
Shape s = new Circle();
 It declares a reference variable to an
object of the class Shape or any of its
subclasses,
Shape s;
in other words, this variable refers to any object
that implements all the methods of the public
interface of the class Shape and has all the
same public variables
 (of course, there could be more methods and
variables but at least those of the interface of
Shape must be defined).
 In particular, since Circle is a subclass of Shape
it inherits all the characteristics of a shape.
s = new Circle();
Key elements
1. The class of an object never changes
during the execution of a program;
2. A reference can be used to designate
successively more than one object
during the execution of a program;
3. It’s the object’s class that determine the
characteristics of the object (variables +
methods) and not the type of the
reference.
class A {
public void a() {
System.out.println("method ‘‘a’’ was called!");
}
}
class B extends A {
public void b() {
System.out.println("method ‘‘b’’ was called!");
}
}
class Test {
public static void main(String args[]) {
A a = new A();
B b = new B();
A c = new B();
// B d = new A(); does not work, why?
}
}
A a = new A(); // ok
a.a();
// ok
a.b();
// doesn’t work, a is an object
// of class A and A does not
// have a method b()
B b = new B(); // ok
b.a();
// ok
b.b();
// ok
A c = new B(); // ok
c.a();
// ok
B d = new A();
// doesn’t work why?
 We can now define compare as follows:
public static int compare(Shape a, Shape b) {
return compare(a.area(), b.area());
}
and it would work for any pair of shapes.
Circle c = new Circle(100, 100, 5);
Rectangle r = new Rectangle(0, 0, 10, 15);
int result = compare(c, r);
 this would work for any subclass of
shape; even the ones that are not yet
defined.
 Since a is a parameter and a refers to
objects of more than one class we say
that a is a polymorphic parameter
(similarly for b).
 Since “compare” has polymorphic
parameters we say that “compare” is a
polymorphic method, it’ll compare the
areas of the objects that are instances of
any subclasses of Shape.
public class Test {
public static void main(String args[]) {
Shape[ ] shapes = new Shape[4];
shapes[0] = new Circle();
shapes[1] = new Circle(100, 200, 10);
shapes[2] = new Rectangle();
shapes[3] = new Rectangle(50, 50, 10, 15);
for (int i=0; i<shapes.length; i++) {
System.out.println (shapes[i].area());
if (shapes[i] instanceof Rectangle) {
Rectangle r = (Rectangle) shapes[i];
r.flip();
System.out.println ("flip: " + r);
}
}
}
}
Late binding
also called dynamic binding.


Shape s = new Circle();
System.out.println(s);
 Remember that we overrode toString() within
the class Circle. There is a method toString() in
both classes Shape and Circle, s is of type
Shape but currently refers to an object of the
class Circle.
 Which method toString() will be called?
Dynamic binding (cont’d)
 The closest method to the object in the
hierarchy is used/called.


Shape s = new Circle(10, 10);
System.out.println(s);
 Which method toString will be called?
The one which is defined in Shape or the
one defined in Circle?
 The following example illustrates the fact that
the actual class of the object referenced by c is
known at runtime:
Shape s;
Circle c;
if (Math.Random() >= 0.5)
s = new Circle();
else
s = new Rectangle();
c = s; // would not be allowed by the compiler
instanceof
 Sometimes we need to know if the object designed by a
reference variable is of a given type.
Shape s;
if (Math.Random() >= 0.5)
s = new Circle();
else
s = new Rectangle();
if (s instanceof Circle) {
Circle c = (Circle) s; // type casting
int r = c.getRadius(); // and this would work
}
instanceof (cont’d)
 The type casting and the method call can be combined:
Shape s;
if (Math.Random() >= 0.5)
s = new Circle();
else
s = new Rectangle();
if (s instanceof Circle) {
// tells the compiler to consider s as an instance of the
//class Circle
int r = ((Circle) s).getRadius();
}
 Caution! Use type casting with
parsimony. It is sometimes an indication
of a bad design. Try to see if the method
could be implemented elsewhere in the
hierarchy.
 Finally, remember that Java would not
allow the following statement since
Shape is an abstract class and there can
be no instance of an abstract class.

Shape s = new Shape();
Summary — definitions
This section summarizes the main definitions related to
object-oriented programming.
encapsulation:
 the implementation details of a concept are concentrated
in one place. In object oriented programming, the data
(variables) and the methods that act on the data are
encapsulated into a single entity called the object. An
object has an interface, which consists of the public
methods and variables of the object. This allows to
clearly separate the implementation of a class from its
usage. The (client) programmer using the class doesn’t
need to know about the implementation of the class. The
information that’s hidden inside the class can be changed
without affecting the programs using it.
information hiding:
 the details of the implementation of a concept are
not visible to the user of the class or the method.
inheritance:
 most object-oriented programming languages
organize classes as a hierarchy such that a class
has only one parent but can have many
descendants. The descendants of a class inherit
the characteristics (variables and methods) of the
parent. The relationship is transitive, which means
that a class inherits all the characteristics of its
ancestors.
polymorphism:
 polymorphism is the ability of a method
or a variable (parameter) to refer to
objects of different classes.
superclass:
 also called parent or base class, is the
class immediately above in the
hierarchy; every class except Object has
one.
subclass:
 also called child or derived class, this the class
immediately below; every class except Object is
the subclass of another class. In Java, a
subclass is declared with the keyword extends
followed by the name of the superclass. A class
can have no subclass or many subclasses but it
only has one superclass. The relationship
between the subclass and its superclass is
sometimes referred to as “is-a” relationship.
abstract class:
 An abstract is a class that’s never instantiated.
Other classes are called concrete classes. An
abstract class is declared by prefixing the
keyword class by abstract in the class
definition.
abstract method:
 is a method which is defined in an abstract
class and has no implementation. The
implementation for the method will be provided
by the subclass(es). It is placed in the
superclass to ensure that every class derived
from the superclass will have it; it’s a “place
holder”.
overloading:
 overloading consist in declaring two or
more methods with the same name but
different signatures. In the class Shape
two constructors were defined, one with
no arguments the other with three.
overriding:
 method overriding consists of providing a new
implementation for a method that was defined in the
superclass. The two methods have the same name and
the same signature (i.e. same list of formal parameters).
In an instance of the subclass, the definition of the
method in the superclass would be shadowed by that of
the subclass.
 The keyword final in the declaration of a method prevents
overriding by the subclass. Since Object has a method
toString, any class that supplies its own version is
overriding the definition of toString in Object. The method
that’s closest to the object is always used (follow the
arrows).
Download