- Forward


Polymorphism through Inheritance
With Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu

Print

Review - The Syntax of Specialization
Back SMYC Forward
  • Suppose we have the following:
    • public class Chirp {...}
    • public class ExpandedChirp extends Chirp {...}
    • public void addChirp(Chirp ch) {...}
  • Will the compiler allow us to:
    • pass a Chirp object to the addChirp() method?
    • pass an ExpandedChirp object to the addChirp() method?
Review (cont.)
Back SMYC Forward
  • What is the compiler concerned about in these cases?
    • Whether the right-side operand of the membership operator will be recognized for the parameter ch
  • Obviously, this isn't a problem when we:
    • pass a Chirp object to the addChirp() method (since the formal parameter is declared to be a Chirp)
  • It also isn't a problem when we:
    • pass an ExpandedChirp object to the addChirp() method (since the ExpandedChirp class inherits the accessible attributes from the Chirp class)
Review (cont.)
Back SMYC Forward
  • Suppose we have the following:
    • public class Chirp {...}
    • public class ExpandedChirp extends Chirp {...}
  • Will the following compile?
    • Chirp c; c = new Chirp("JMU");
    • Chirp c; c = new ExpandedChirp("JMU");
    • ExpandedChirp e; e = new ExpandedChirp("JMU");
    • ExpandedChirp e; e = new Chirp("JMU");
Motivation of this Lecture
Back SMYC Forward
  • Suppose in the previous example:
    • Chirp has a getText() method
    • ExpandedChirp overrides the getText() method
  • What happens at run-time if:
    • addChirp() is passed a Chirp object and calls the getText() method?
    • addChirp() is passed an ExpandedChirp object and calls the getText() method?
Polymorphism
Back SMYC Forward
  • Etymology:
    • From the Greek - "having many forms"
  • Some Uses of the Term:
    • Coercion of one type to another can be thought of as polymorphism
    • Method overloading can be thought of as polymorphism
  • Our Concern Here:
    • Polymorphism that results from specialization (which is often called subclass polymorphism)
    • The related concept called dynamic binding
A Simple Example
Back SMYC Forward

Recall the Instant Messaging Example

javaexamples/oopbasics/im2/Chirp.java
 
A Simple Example (cont.)
Back SMYC Forward

Recall the Instant Messaging Example

javaexamples/oopbasics/im2/ExpandedChirp.java
 
A Simple Example (cont.)
Back SMYC Forward

Since an ExpandedChirp "is a" Chirp, we know that a Chirp[] (i.e., an array of references to Chirp objects) can contain both.

javaexamples/oopbasics/im2/ChirpRecorder.java
 
A Simple Example (cont.)
Back SMYC Forward

What we need to know is what happens when an element's getText() method is called.

javaexamples/oopbasics/im2/Driver.java
 
A Simple Example (cont.)
Back SMYC Forward

What Memory Might Look Like Before The Calls To recorder.showChirp()

images/JavaMemoryModel_ChirpExample.png
New Terminology
Back SMYC Forward
  • An Observation:
    • It is not really clear what we mean when we say that the getText() method of the Chirp object is called
  • An Alternative:
    • In OOP we often say that a getText() message is sent to the Chirp object
    • We can then talk about which particular method is executed when the message is received
Polymorphism in Java
Back SMYC Forward
  • Class Membership
    • The compiler uses the declared class
    • At run-time an object knows its class (i.e., the class that it is a member of is determined by the constructor that was used to instantiate it)
  • Search Order:
    • If the "message" is sent to an object of the derived class then the derived class is searched (for the existence of such a method) first and the base class is searched second. (Note: The search will move up the class hierarchy as needed.)
    • If the "message" is sent to an object of the base class then only the base class is searched.
A More Complicated Example
Back SMYC Forward
javaexamples/oopbasics/banking/Account.java
 
A More Complicated Example (cont.)
Back SMYC Forward
javaexamples/oopbasics/banking/OverdraftAccount.java
 
A More Complicated Example (cont.)
Back SMYC Forward
javaexamples/oopbasics/banking/Driver.java
 
A More Complicated Example (cont.)
Back SMYC Forward

What Memory Might Look Like After Constructing The OverdraftAccount

images/JavaMemoryModel_AccountExample_AfterConstruction.png
A More Complicated Example (cont.)
Back SMYC Forward

What Memory Might Look Like After The Deposit

images/JavaMemoryModel_AccountExample_AfterDeposit.png
A More Complicated Example (cont.)
Back SMYC Forward

What Memory Might Look Like After The Withdrawal

images/JavaMemoryModel_AccountExample_AfterWithdrawal.png
Gaining Experience with More Complicated Situations
Back SMYC Forward
  • In the Current Chirp Class:
    • The getNumberOfWords() method uses the protected String attribute named text
  • Suppose:
    • It used the getText() method instead
  • What Happens at Run-Time When:
    • A getNumberOfWords() message is sent to a Chirp() object?
    • A getNumberOfWords() message is sent to an ExpandedChirp() object?
Static and Dynamic Binding
Back SMYC Forward
  • Sending a Message to an Object (that is Polymorphic):
    • The Issue - Because the object is polymorphic, the method can be anywhere in the class tree
    • In Java - Dynamic binding (at run-time) is used to determine the code that is executed
  • Passing an Object (that is Polymorphic) as a Parameter:
    • The Issue - Because the object is polymorphic and methods can be overloaded, there can be more than one method that could be invoked
    • In Java - Static binding is used (at compile-time) to determine which method to invoke
Polymorphism, Overloading, and Objects as Parameters
Back SMYC Forward
  • Suppose we have the following classes:
    • public class Chirp {...}
    • public class ExpandedChirp extends Chirp {...}
  • And the following methods in another class:
    • public void add(Chirp ch) {...}
    • public void add(ExpandedChirp ch) {...}
  • What happens at run-time when:
    • add() is passed a Chirp that is declared to be a Chirp?
      add(Chirp ch) is executed -- there is no other option
      Expand
    • add() is passed an ExpandedChirp that is declared to be an ExpandedChirp?
      add(ExpandedChirp ch) is executed -- this is not a situation in which dynamic/late binding is used at run-time, the declared type is used at compile-time to determine which method will be executed
      Expand
    • add() is passed an ExpandedChirp that is declared to be a Chirp?
      add(Chirp ch) is executed -- again, the declared type is used at compile-time to determine which method is executed
      Expand
Polymorphism, Overloading, and Objects as Parameters (cont.)
Back SMYC Forward
  • Suppose we have the following classes:
    • public class Chirp {...}
    • public class ExpandedChirp extends Chirp {...}
  • And the following methods in another class:
    • public void add(Chirp ch) {...}
  • What happens at compile-time and run-time when:
    • add() is passed an ExpandedChirp that is declared to be an ExpandedChirp?
      Compile-Time: The call to add() compiles because an ExpandedChirp is a Chirp
      Expand
      Run-Time: add(Chirp ch) is executed -- there is no other option
      Expand
    • add() is passed an ExpandedChirp that is declared to be a Chirp?
      Compile-Time: The call to add() compiles because the actual parameter is declared to be the same type as the formal parameter
      Expand
      Run-Time: add(Chirp ch) is executed -- there is no other option
      Expand
Polymorphism, Overloading, and Objects as Parameters (cont.)
Back SMYC Forward
  • Suppose we have the following classes:
    • public class Animal {...}
    • public class Mammal extends Animal {...}
    • public class Sheep extends Mammal {...}
  • And the following methods in another class:
    • public void add(Animal item) {...}
    • public void add(Mammal item) {...}
  • What happens at run-time when:
    • add() is passed an Animal that is declared to be an Animal?
      add(Animal item) is executed -- there is no other option
      Expand
    • add() is passed a Mammal that is declared to be a Mammal?
      add(Mammal item) is executed -- the declared type is used
      Expand
    • add() is passed a Sheep that is declared to be a Sheep?
      add(Mammal item) is executed -- there is no method matching the declared type but a Sheep "is a" Mammal and a Sheep "is a" Animal so both methods could be executed; the most specific/specialized version is executed
      Expand
There's Always More to Learn
Back -