0% found this document useful (0 votes)
18 views73 pages

6 - OOD4 Object, Type Conversion, and Polymorphism

Here is an example of overriding toString() in a custom class: public class Person { private String name; public Person(String name) { this.name = name; } public String toString() { return "Person: " + name; } } System.out.println(new Person("John")); // Prints "Person: John" So toString() can be overridden to return a custom string representation of the object.

Uploaded by

dahloul86
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views73 pages

6 - OOD4 Object, Type Conversion, and Polymorphism

Here is an example of overriding toString() in a custom class: public class Person { private String name; public Person(String name) { this.name = name; } public String toString() { return "Person: " + name; } } System.out.println(new Person("John")); // Prints "Person: John" So toString() can be overridden to return a custom string representation of the object.

Uploaded by

dahloul86
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 73

COMP 250

INTRODUCTION TO COMPUTER SCIENCE


6 – OOD4 Object, type conversion, and polymorphism

Giulia Alberini, Winter 2024


QUICK REVIEW

Monster
+ eat()
+ reduceHealth() Hero
+ spook() + reduceHealth()  Which method(s) has/have
+ useFire(w : Weapon) been overridden?
 Which method(s) has/have
Orc Dragon been overloaded?
+ eat(heroes : Hero[]) + spook()
+ useFire()
QUICK REVIEW
The following code contains a compile time error. What can we
change so that an orc of health 10 with an axe can be correctly
created?

public class Orc extends Monster {


private String weapon;
public class Monster {
private double hp;
public Orc(String w) {
this.weapon = w;
public Monster (double hp) {
}
this.hp = hp;
public static void main(String[] args) {
}
Orc o = new Orc("Axe");
}
}
}
QUICK REVIEW
Monster Consider the two classes on the left. Which of the following
+ eat() implementations of the method spook() from the Dragon class
+ reduceHealth()
+ spook() contains an error:

A. public void spook() { B. public void spook() {


Dragon spook(); this.spook();
+ spook() useFire(); this.useFire();
+ useFire() } }

C. public void spook() { D. public void spook() {


super.spook(); super.spook();
super.useFire(); this.useFire();
} }
WARM UP

To the two previous classes, let's add a class Triangle and a


void method displayInfo() to all three classes.

Shape Circle Triangle


- color: String - radius: double - base: double
+ getColor(): String + getRadius(): double - height: double
+ setColor(c:String) + getArea(): double + getArea(): double
+ displayInfo() + displayInfo() + displayInfo()
WHAT ARE WE GOING TO DO TODAY?

OOD4
 The Object class
 Type Conversion
 instanceof
 Intro to Polymorphism
 Abstract Classes and Methods
MODIFIERS
and
INHERITANCE
ACCESS CONTROL MODIFIERS

 Recall that a class can be declared to be either public or package-private (no


keyword).
 A class can extend another class if and only if the latter is visible from where the
former is located.
ACCESS CONTROL MODIFIERS

 Recall that a class can be declared to be either public or package-private (no


keyword).
 A class can extend another class if and only if the latter is visible from where the
former is located.

package lectures;
package assignments.a1;
import assignments.a1.A;
public class A {
public class B extends A{
: All public classes
:
} can be extended
}
(even across
packages)
ACCESS CONTROL MODIFIERS

 Recall that a class can be declared to be either public or package-private (no


keyword).
 A class can extend another class if and only if the latter is visible from where the
former is located.

package assignments.a1; package lectures;

class A { public class B extends A{


: : Not allowed,
} } since A is not
visible from B.
WHICH MEMBERS ARE INHERITED?

 Every superclass’ member visible from where the subclass is located


is inherited by the subclass. (with the exception of constructors)

 Members include: fields, methods, inner/ static nested classes.

 Note that a subclass cannot reduce the visibility of an inherited


method. The visibility can only be increased. (we’ll understand
better why in the next few classes)
ASIDE: NESTED CLASSES

 Note that a nested class is not a subclass.

 Outer and inner classes have access to all fields and methods of each
other. Details are out of the scope of this course.
final KEYWORD

 A class that has been declared final cannot be extended.

public final class Dog { public class Beagle extends Dog {


: :
} }

compile-time error!
final KEYWORD

 A method that has been declared final cannot be overridden.

public class Dog { public class Beagle extends Dog {


public final void bark() { public void bark() {
: :
} }
} }

compile-time error!
Object CLASS
THE Object CLASS

 Object is the only class in java without a superclass. All other classes have
one and only one direct superclass.
 In the absence of any other specific superclass, every class is implicitly a
subclass of Object.

https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html
METHODS FROM Object

Here are some of the methods from the Object class:

https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html
HIERARCHY FOR OUR EXAMPLES
Object
+ hashCode(): int
+ toString(): String
+ equals(o: Object): boolean

extends (automatic)

Animal

extends

Dog

extends extends extends

Poodle Beagle Doberman


Object
+ hashCode(): int
+ toString(): String
+ equals(o: Object): boolean
hashCode()- RETURN VALUE

 It returns a 32 bit integer associated to this object.

 “typically implemented by converting the internal address of the object


into an integer, but this implementation technique is not required by the
Java™ programming language”.

 Use of hashCode() method : Returns a hash value that is used to search


object in a collection.
hashCode()- REQUIREMENTS

 “Whenever it is invoked on the same object more than once during an


execution of a Java application, the hashCode method must consistently
return the same integer.”

 If o1.equals(o2) is true, then o1.hashCode()==o2.hashCode()


should also be true.

Note that the converse does not need to hold!

https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--
EXAMPLE

Object
+ hashCode(): int
+ toString(): String
+ equals(o: Object): boolean

extends (automatic)

String
The class String
+ hashCode(): int overrides hashCode()
+ toString(): String
+ equals(s: Object): boolean
EXAMPLE

The method hashCode() from the class String

https://docs.oracle.com/javase/7/docs/api/java/lang/String.html
Object
+ hashCode(): int
+ toString(): String
+ equals(o: Object): boolean
toString()

 Returns a string representation of the object.

 It is recommended that all subclasses override this method.

 The toString() method for class Object returns a string consisting of the
name of the class of which the object is an instance, the at-sign character
‘@’, and the unsigned hexadecimal representation of the hash code of the
object.
EXAMPLE

System.out.println( new Object() );

What does this print?

java.lang.Object@7852e922

package + class name 32 bit integer represented in hexadecimal


EXAMPLE

Object
+ hashCode(): int Returns the following:
className + “@” +
+ toString(): String Integer.toHexString(hashCode())
+ equals(o: Object): boolean

extends (automatic)
toString() is overridden
String
in the class String
+ hashCode(): int
+ toString(): String
Returns the object itself
+ equals(s: Object): boolean
EXAMPLE

Object
+ hashCode(): int Returns the following:
className + “@” +
+ toString(): String Integer.toHexString(hashCode())
+ equals(o: Object): boolean

extends (automatic)
toString() is overridden
Animal
in the class Animal
- birth: Date
+ eat()
Returns… depends on your
+ toString(): String implementation!
Object
+ hashCode(): int
+ toString(): String
+ equals(o: Object): boolean
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html

equals()

see MATH 240


equals() FROM Object– IMPLEMENTATION

For any non-null reference values obj1 and obj2,

obj1.equals(obj2) returns true


if and only if
obj1 == obj2 has value true
EXAMPLES

Object
+ hashCode(): int
+ toString(): String
+ equals(o: Object): boolean

extends (automatic)

Animal
Animal overrides the
- birth: Date
equals() method
+ eat()
+ equals(o: Object): boolean
EXAMPLES

Object
+ hashCode(): int
+ toString(): String
+ equals(o: Object): boolean

extends (automatic)

Animal
Animal overloads the
- birth: Date
equals() method
+ eat()
+ equals(a: Animal): boolean
EXAMPLES

Object
+ hashCode(): int
+ toString(): String
+ equals(o: Object): boolean

extends (automatic)

String
String overrides the
+ hashCode(): int
equals() method
+ toString(): String
+ equals(s: Object): boolean
equals() FROM String
TYPE CONVERSION
FROM LAST TIME…
class Dog public class Test {
Person owner
public void bark() { public static void main(String[] args) {
print(“woof!”);
Dog snoopy = new Beagle();
}
: snoopy.bark();
extends }
}
class Beagle Is this
void hunt () allowed??
public void bark() {
print(“aowwwuuu”);
}
:
OBJECTS TYPE

 We have seen that an object is of the type of the class from which it was
instantiated.

 For example, if we write

Dog myDog = new Dog();

then myDog points to an object of type Dog.


OBJECT TYPES

 But Dog is a subclass of Animal which is a subclass of Object.

 Thus, a Dog is an Animal and is also an Object. We can use an object of


type Dog wherever objects of type Animal or Object are called for.

 Note that the reverse is not necessarily true: an Animal could be a Dog,
but not necessarily. Similarly, an Object could be an Animal or a Dog,
but it isn’t necessarily.
TYPE CASTING – REFERENCE TYPES

 Casting allows us to use an object of one type in place of another type, if


permitted.

 For example we can write

Animal myPet = new Dog();

This will not cause a compile-time error because there is an implicit


upcasting since a Dog is for sure also an Animal.
TYPE CASTING – REFERENCE TYPES
On the other hand, consider the following

Animal myPet = new Dog();


Dog myDog = myPet;

The second line will cause a compile-time error. From the compiler point of view,
myPet is of type Animal and an Animal might not be a Dog.
However, we can tell the compiler that myPet is of the correct type, by explicitly
downcasting:
Dog myDog = (Dog) myPet;

If myPet turns out to be of the wrong type we’ll get a run-time error.
42

HIERARCHY FROM LAST CLASS


Object
Upcasting
Happens automatically
extends

Animal
IMPORTANT!
extends Note that casting does NOT
change the object itself, it just
labels it differently!
Dog

extends extends extends

Poodle Beagle Doberman Downcasting


+ show() + hunt():Rabbit + fight() The programmer has to manually do it.
EXAMPLES

Dog myDog = new Beagle();

Is this allowed?
 Yes, it is an example of upcasting which happens automatically.
EXAMPLES

Dog myDog = new Beagle();


Poodle myPoodle = myDog;

Is this allowed?
 Compile-time error! The variable myDog is of type Dog, and it might not be
pointing to a Poodle. It requires explicit downcasting to compile.
EXAMPLES

Dog myDog = new Beagle();


Poodle myPoodle = (Poodle) myDog;

Is this allowed?
 The code compiles, but there will be a run-time error because myDog is not
pointing to a Poodle after all.
EXAMPLES

Dog myDog = new Beagle();


myDog.hunt();

Is this allowed?
 Compile-time error! The variable myDog is of type Dog, and there is no method
called hunt inside the Dog class.
EXAMPLES

Dog myDog = new Beagle();


((Beagle) myDog).hunt();

Is this allowed?
 Yes, this code will compile and run.
A LITTLE ABOUT instanceof

 The instanceof operator is used to test whether an object is an instance of


the specified type.
 It returns either true or false. If we apply the instanceof operator with any
variable that has null value, it returns false.

Dog myDog = new Dog();


Beagle snoopy = new Beagle();
Dog aDog = null;
System.out.println(myDog instanceof Dog); // true
System.out.println(snoopy instanceof Dog); // true
System.out.println(aDog instanceof Dog); // false
instanceof AND DOWNCASTING

 When can use instanceof to make sure that downcasting to a subclass will
not cause a run time error.

public static void myMethod(Dog myDog) {


if(myDog instanceof Beagle) {
Beagle b = (Beagle) myDog; // downcasting
b.hunt();
}
}
instanceof AND equals()

 Note that in general we want to use instanceof as a last resort. We’ll see why
shortly.
 That said, we have to use instanceof when overriding equals()

public class Dog {


Person owner;
:
public boolean equals(Object obj) {
if(obj instanceof Dog) {
...
}
}
}
WHAT'S LEFT?
class Dog public class Test {
Person owner
public void bark() { public static void main(String[] args) {
print(“woof!”);
Dog snoopy = new Beagle();
}
: snoopy.bark();
extends }
}
class Beagle Is this
void hunt () allowed??
public void bark() {
Which Yes, it’s an
print(“aowwwuuu”);
} bark() will example of
: execute??? upcasting!
POLYMORPHISM
POLYMORPHISM

 Each object can have different “forms”.

 One important aspect of polymorphism in Java: “the Java virtual machine


(JVM) calls the appropriate method for the object that is referred to in each
variable. It does not call the method that is defined by the variable's type”.

 More general discussion about polymorphism in higher level courses.


(e.g. COMP 302)
RECALL HIERARCHY FROM OUR EXAMPLES

Animal

extends

Dog
public void bark() {
print(“woof!”);
}

extends extends extends

Poodle Beagle Doberman


public void bark() { public void bark() { public void bark() {
print(“arw”); print(“aowwwuuu”); print(“Arh! Arh! Arh!”);
} } }
EXAMPLE

Dog myDog = new Dog(); The compiler sees bark() in the Dog class
(myDog is of type Dog) at compile time, the
myDog.bark(); JVM invokes bark() from the Dog class at run
Dog snoopy = new Beagle(); time (myDog points to an object of type Dog).

snoopy.bark();
At compile time, the compiler uses bark() in
OUTPUT
the Dog class to validate the statement. At run
time, however, the JVM invokes bark() from
the Beagle class. (snoopy is actually
woof!
referring to a Beagle object)
aowwwuuu
THE “OO WAY”

 Favor polymorphism and dynamic binding to downcasting and


instanceOf.

 From Effective C++, by Scott Meyers:

"Anytime you find yourself writing code of the form ‘if the object
is of type T1, then do something, but if it's of type T2, then do
something else’, slap yourself”.
TRY IT!

 Let’s go back to our Shape classes. Let’s now create an array of


Shapes and see how we can exploit polymorphism when
displaying the info of the elements in the array.
QUICK REVIEW
Which of the following snippets of code
raise an error?
A. Nut n = new Walnut();
Nut n.taste();
+ peel()
+ taste() B. Walnut w = new Walnut();
w.peel();
C. Peanut p = new Nut();
p.taste();
Peanut Walnut
+ makeButter() + taste() D. Nut n = new Walnut();
+ taste() ((Peanut) n).makeButter();
E. Peanut p = new Peanut();
Walnut w = new Walnut();
Nut[] nuts = {p, w};
QUICK REVIEW
prints "just a nut" Consider the following snippet of code

Nut n1 = new Peanut();


Nut
Walnut w = new Walnut();
+ peel() Peanut p = new Peanut();
+ taste() Nut n2 = new Nut();
Nut n3 = (Nut) w;

Nut[] nuts = {n1, w, p, n2, n3};


Peanut Walnut
+ makeButter() + taste() for (Nut n : nuts)
n.taste();
+ taste()

What prints?
prints "walnut"
prints "more!!"
abstract
LET’S LOOK AT AN EXAMPLE

 Suppose we created the following two classes to work with Circles and
Triangles.

Circle Triangle
- color: String - color: String
- radius: double - base: double
+ getColor(): String - height: double
+ setColor(c:String) + getColor(): String
+ getRadius():double + setColor(c:String)
+ getArea(): double +getArea(): double
LET’S LOOK AT AN EXAMPLE

 Suppose we created the following two classes to work with Circles and
Triangles.

Observations:
Circle Triangle
- color: String - color: String • The two classes are
- radius: double - base: double closely related. They are
+ getColor(): String - height: double both used to represent
+ setColor(c:String) + getColor(): String geometrical shapes.
+ getRadius():double + setColor(c:String)
+ getArea(): double +getArea(): double
LET’S LOOK AT AN EXAMPLE

 Suppose we created the following two classes to work with Circles and
Triangles.

Observations:
Circle Triangle
- color: String - color: String • There’s code that is
- radius: double - base: double repeated: the two classes
+ getColor(): String - height: double share fields and methods
+ setColor(c:String) + getColor(): String that are implemented in
+ getRadius():double + setColor(c:String) the same way.
+ getArea(): double +getArea(): double
LET’S LOOK AT AN EXAMPLE

 Suppose we created the following two classes to work with Circles and
Triangles.

Observations:
Circle Triangle
- color: String - color: String • There’s a method that
- radius: double - base: double serves the same purpose
+ getColor(): String - height: double in both classes, but it’s
+ setColor(c:String) + getColor(): String implemented differently
+ getRadius():double + setColor(c:String) depending on the class.
+ getArea(): double +getArea(): double
LET’S LOOK AT AN EXAMPLE

 Suppose we created the following two classes to work with Circles and
Triangles.

Observations:
Circle Triangle
- color: String - color: String • There are fields and
- radius: double - base: double methods that are specific
+ getColor(): String - height: double to each class.
+ setColor(c:String) + getColor(): String
+ getRadius():double + setColor(c:String)
+ getArea(): double +getArea(): double
LET’S LOOK AT AN EXAMPLE

 Suppose we created the following two classes to work with Circles and
Triangles.

Observations:
Circle Triangle
- color: String - color: String • It is the perfect situation to
- radius: double - base: double create an abstract
+ getColor(): String - height: double superclass!
+ setColor(c:String) + getColor(): String
+ getRadius():double + setColor(c:String)
+ getArea(): double +getArea(): double
abstract METHODS

 If you want a class to contain a particular method, but you would like the
implementation of this method to be specified by the subclasses, then you can
declare the method to be abstract.

 An abstract method is a method that is declared without implementation:

public abstract double getArea();

The method has no body! Instead of the curly braces,


we use the semicolon at the end of the header.
abstract METHODS

Declaring a method as abstract has 2 consequences:

 The class containing it must be also declared abstract.

 Every subclass of the current class MUST either override the


abstract method or declare it itself as abstract.
abstract CLASSES

 An abstract class must be declared using the abstract keyword.

 It can have abstract and non-abstract methods.

 It cannot be instantiated.

 It can have constructors and static methods.

 It can have final methods which will force the subclass not to
change the body of the method
abstract CLASSES – OBSERVATIONS

 We can have abstract classes with no abstract methods. This


allow us to create classes that cannot be instantiated, but can
only be inherited.

 We cannot instantiate an abstract class, but we can define


constructors. These constructors are called when an instance
of a subclass is created.
BACK TO OUR EXAMPLE
Shape
- color: String
UML notations
Italics  abstract + getColor(): String
Implemented in Shape
+ setColor(c:String)
+ getArea(): double
extends extends

Circle Triangle
- radius: double - base: double
+ getRadius():double - height: double
+ getArea(): double + getArea(): double

Implemented in Circle and Triangle


TRY IT!

 Go back to the Shape class and modified it by adding an abstract


getArea() method.

 Add constructors to the three classes.

 Play around with the classes!


Next week:
 Linear data structures: array lists and linked lists!

You might also like