Polymorphism: Desired Learning Outcome
To understand the concept of polymorphism
To be familiar with the common superclass Object and its methods
Polym orphis m
Recall: inheritance allows for code reuse
Example: write a single program (QuestionDemo3) that could present both
Question and ChoiceQuestion with the same method.
We do not need to know the exact type of the question, but
We need to display the question
We need to check whether the user supplied the correct answer
The Question superclass has methods for displaying and checking.
The program simply declares the parameter variable of the presentQuestion
method to have the type Question:
public static void presentQuestion(Question q)
{
q.display();
System.out.print("Your
answer: ");
Scanner in = new Scanner(System.in);
String response = in.nextLine();
System.out.println(q.checkAnswer(re
sponse));
}
Polymorphism - continued
We can substitute a subclass object whenever a superclass object is expected:
ChoiceQuestion second = new ChoiceQuestion();
. . .
presentQuestion(second); // OK to pass a ChoiceQuestion
When the presentQuestion method executes -
The object references stored in second and q refer to the same object.
The object is of type ChoiceQuestion.
Variables of Different Types Referring to the Same Object
Polymorphism - continued
The variable q knows less than the full story about the object to which it refers
A Question Reference Can Refer to an Object of Any Subclass of
Question
In the same way that vehicles can differ in their method of
locomotion, polymorphic objects carry out tasks in different ways.
Polymorphism - continued
When the virtual machine calls an instance method -
It locates the method of the implicit parameter’s class.
This is called dynamic method lookup/dynamic method binding
Dynamic method lookup allows us to treat objects of different classes in a
uniform way.
This feature is called polymorphism.
We ask multiple objects to carry out a task, and each object does so in its own way.
Polymorphism means “having multiple forms”
It allows us to manipulate objects that share a set of tasks, even though the tasks are executed in
different ways.
section_4/QuestionDemo3.java
1 import java.util.Scanner;
2
3 /**
4 This program shows a simple quiz with two question types.
5 */
6 public class QuestionDemo3
7 {
8 public static void main(String[] args)
9 {
10 Question first = new Question();
11 first.setText("Who was the inventor of Java?");
12 first.setAnswer("James Gosling");
13
14
ChoiceQuestion second = new ChoiceQuestion();
15
second.setText("In which country was the inventor of Java
16
born?"); second.addChoice("Australia", false);
17
second.addChoice("Canada", true);
18
second.addChoice("Denmark", false);
19
second.addChoice("United States",
20
false);
21
22 presentQuestion(first);
23 presentQuestion(second);
24 }
25
26 /**
27 Presents a question to the user and checks the response.
28 @param q the question
29 */
30 public static void presentQuestion(Question q)
31 {
32 q.display();
33 System.out.print("Your answer: ");
34 Scanner in = new Scanner(System.in);
35 String response = in.nextLine();
System.out.println(q.checkAnswer(response));
Program Run:
Who was the inventor of Java?
Your answer: Bjarne Stroustrup
false
In which country was the inventor of Java born?
1: Australia
2: Canada
3: Denmark
4: United States
Your answer: 2
true
Why not using if-else Statements?
• Determine appropriate action for object based on
object’s type using if-else
• Error prone!
• Programmer can forget to make appropriate
type test
• Adding and deleting if-else statements
public class Animal {
//...
}
public class Dog extends Animal {
public void woof() { Example: using if-else
System.out.println("Woof!"); and instanceof
}
//...
}
public class Cat extends Animal {
public void meow() {
System.out.println("Meow!");
}
//...
}
public class Example {
public static void main(String[] args) {
makeItTalk(new Cat());
makeItTalk(new Dog());
}
public static void makeItTalk(Animal animal) {
if (animal instanceof Cat) {
Cat cat = (Cat) animal; type casting: the process
cat.meow(); of converting the value of one data
}
else if (animal instanceof Dog) {
type to another data type
Dog dog = (Dog) animal;
dog.woof();
}
}
}
Example with Polymorphism
Animal is the superclass with a
import java.util.Scanner;
method speak()
public class AnimalGame
{ Both Dog and Cat extend Animal
public static void main(String[] args) and override speak()
{
System.out.println("Choose one of three doors by entering
the number of the door you choose.");
Scanner input = new Scanner(System.in);
int doorNumber = input.nextInt();
Animal animal = null;
if (doorNumber == 1){
animal = new Cat();
}
else if (doorNumber == 2){
animal = new Dog();
}
else {
System.out.println("Not a valid door number");
System.exit(1);
}
System.out.println("The animal behind your door says: " +
animal.speak());
}
}
Late Binding vs. Early Binding
• Early Binding
• Overloaded methods/constructors
E.g., two constructors for BankAccount class
BankAccount() and BankAccount(double)
The compiler selects the correct constructor when
compiling the program by looking at the parameter
types.
account = new BankAccount(); //compiler selects BankAccount();
account = new BankAccount(1.00);//BankAccount(double)
• Early Binding – decisions are made at compilation time by
the compiler
• Late Binding – decisions are made at run time by the Java
virtual machine
Object: The Cosmic Superclass
Every class defined without an explicit extends clause automatically extend
Object
The class Object is the direct or indirect superclass of every class in Java.
Some methods defined in Object:
toString - which yields a string describing the object
equals - which compares objects with each other
hashCode - which yields a numerical code for storing the object in a set
Object: The Cosmic Superclass
Figure 9 The Object Class Is the Superclass of Every Java Class
Overriding the t o S t r i n g Method
Returns a string representation of the object
Useful for debugging:
Rectangle box = new Rectangle(5, 10, 20, 30);
String s = box.toString();
// Sets s to "java.awt.Rectangle[x=5,y=10,width=20,height=30]"
toString is called whenever you concatenate a string with an object:
"box=" + box;
// Result: "box=java.awt.Rectangle[x=5,y=10,width=20,height=30]"
The compiler can invoke the toString method, because it knows that every
object has a toString method:
Every class extends the Object class which declares toString
Overriding the t o S t r i n g Method
Object.toString prints class name and the hash code of the object:
BankAccount momsSavings = new BankAccount(5000);
String s = momsSavings.toString();
// Sets s to something like "BankAccount@d24606bf"
Override the toString method in your classes to yield a string that describes
the object’s state.
public String toString()
{
return "BankAccount[balance=" + balance + "]";
}
This works better:
BankAccount momsSavings = new BankAccount(5000);
String s = momsSavings.toString(); // Sets s to "BankAccount[balance=5000]"
Overriding the e q u a l s Method
equals method checks whether two objects have the same content:
if (stamp1.equals(stamp2)) . . .
// Contents are the same
== operator tests whether two references are identical - referring to the same
object:
if (stamp1 == stamp2) . . .
// Objects are the same
Overriding the e q u a l s Method
Figure 10 Two References to Equal Objects
Figure 11 Two References to the Same Object
Overriding the e q u a l s Method
To implement the equals method for a Stamp class -
Override the equals method of the Object class:
public class Stamp
{
private String color;
private int value;
. . .
public boolean equals(Object otherObject)
{
. . .
}
. . .
}
Cannot change parameter type of the equals method - it must be Object
Cast the parameter variable to the class Stamp instead:
Stamp other = (Stamp) otherObject;
Overriding the e q u al s Method
After casting, you can compare two Stamps
public boolean equals(Object otherObject)
{
Stamp other = (Stamp) otherObject;
return color.equals(other.color)
&& value == other.value;
}
The equals method can access the instance variables of any Stamp object.
The access other.color is legal.
The i n s t a n c e o f Operator
It is legal to store a subclass reference in a superclass variable:
ChoiceQuestion cq = new ChoiceQuestion();
Question q = cq; // OK
Object obj = cq; // OK
Sometimes you need to convert from a superclass reference to a subclass
reference.
If you know a variable of type Object actually holds a Question reference, you
can cast
Question q = (Question) obj
If obj refers to an object of an unrelated type, "class cast" exception is thrown.
The instanceof operator tests whether an object belongs to a particular type.
obj instanceof Question
Using the instanceof operator, a safe cast can be programmed as follows:
if (obj instanceof Question)
{
Question q = (Question) obj;
}