Chapter 9 Polymorphism Polymorphism Polymorphism is an objectoriented
Chapter 9 Polymorphism
Polymorphism • Polymorphism is an object-oriented concept that allows us to create versatile software designs • Chapter 9 focuses on: § defining polymorphism and its benefits § using inheritance to create polymorphic references § using interfaces to create polymorphic references © 2004 Pearson Addison-Wesley. All rights reserved 27 2
Outline Polymorphic References Polymorphism via Inheritance Polymorphism via Interfaces To understand polymorphism, one must understand the term, ‘binding. ’ © 2004 Pearson Addison-Wesley. All rights reserved 27 3
Binding – Very Important!! • Consider the following method invocation: obj. do. It(); • At some point, this object invocation (reference) is bound to the definition of the method that it invokes. • If this binding occurred at compile time (and this is what we are used to…), then that line of code would call the same method in object, obj, every time. • However, Java defers method binding until run time -this is called dynamic binding or late binding. This is an extremely important feature!!! • Late binding provides flexibility in program design • Discussion ahead… © 2004 Pearson Addison-Wesley. All rights reserved 27 4
Polymorphism • The term polymorphism literally means "having many forms" • A polymorphic reference is a reference that can refer to different types of objects (that is, objects of different classes) at different points in time – despite what the source code looks like! • A method invoked via a polymorphic reference can change from one invocation to the next, that is the reference can invoke a ‘different’ object’s method (with same name) at different points in time! • Restated: Consider obj. doit(); With dynamic binding, this may refer to different methods in different objects at different points during execution! All methods will have the name, doit(), but the objects that they are in may change during the execution of the program. ) • All object references in Java are potentially polymorphic due to late binding (dynamic binding) © 2004 Pearson Addison-Wesley. All rights reserved 27 5
Polymorphism • Suppose we create the following reference variable: Occupation job; • As written, this creates a ‘reference’ to an object (not yet created) of type Occupation. • Java allows this reference to point to an Occupation object (which we know), or to any object of any ‘compatible’ type (like derived types of Occupation!) This is new! So the reference can refer to the job object or any objects inheriting from Occupation. • This “compatibility” can be established using inheritance or using interfaces • Careful use of polymorphic references can lead to elegant, © 2004 Pearson Addison-Wesley. All rights reserved 27 robust software designs 6
Outline Polymorphic References Polymorphism via Inheritance Polymorphism via Interfaces © 2004 Pearson Addison-Wesley. All rights reserved 27 7
References and Inheritance • As stated, an object reference can refer to an object of its class, or to an object of any class related to it by inheritance • For example, if the Holiday class is used to derive a class called Christmas (that is, Christmas is derived from Holiday), then a Holiday reference (‘day’, in this case) could be used to point to a Christmas object. This means that day could point to an object of type Holiday or an object of any derived type! Holiday Christmas Holiday day; // day is a ref to Holiday object (Holiday object not yet created) day = new Christmas(); // Here, day is an object of type Christmas, a derived class of Holiday. day is a reference to the base class, but it points to Christmas here. 8
References and Inheritance • Assigning a child object to a parent reference is considered to be a widening conversion, and can be performed by simple assignment § this is exactly what we did in the last slide. § (a pointer (reference) to the base class is actually pointing to an object of a derived type. ) § The opposite: Assigning an parent object to a child reference can be done also, but it is considered a narrowing conversion and must be done with a cast § The widening conversion is the more useful 9
Polymorphism via Inheritance • In polymorphism: It is the type of the object being referenced, not the reference type, that determines which method is invoked. • In previous slides, day is pointing to an object of type Christmas! § Object being referenced was of type Christmas; • Recall: day = new Christmas; § Reference type was of type Holiday. • It is very common to have a pointer to a base class (Holiday here) pointing to a derived object (day, of type Christmas here). © 2004 Pearson Addison-Wesley. All rights reserved 27 10
• So, we could have the Holiday day; … § Says, day is a reference to objects of type Holiday • And later in code, § day = new Christmas; § day = new Easter; § day = new Thanksgiving; These can appear at various places in the code…. • And then, these references are each bound during run time depending on the program logic; that is, depending on what path in the program is taken binding will take place at the time the new object is referenced. • Further, all three references can be used at various places in the code and – at that time – will point to the correct object. © 2004 Pearson Addison-Wesley. All rights reserved 27 11
More • Suppose the Holiday class has a method called celebrate(), and the Christmas class overrides it; that is, Christmas also has a method called celebrate(). • Now consider the following invocation: day. celebrate(); • If (during execution) day refers to (points to) a Holiday object, it invokes the Holiday version of celebrate(); if it refers to a Christmas object, it invokes the Christmas version • The program logic will determine this during the execution of the program. © 2004 Pearson Addison-Wesley. All rights reserved 27 12
• Let’s consider a practical example from your book. • Be sure to go through this to understand it. • We will go slowly… © 2004 Pearson Addison-Wesley. All rights reserved 27 13
Polymorphism via Inheritance • Consider the following class hierarchy: (Discuss) Staff. Member Volunteer Employee Executive © 2004 Pearson Addison-Wesley. All rights reserved Hourly 27 14
/********************************** // Firm. java Author: Lewis/Loftus // // Demonstrates polymorphism via inheritance. //********************************** public class Firm //--------------------------------// Creates a staff of employees for a firm and pays them. //--------------------------------public static void main (String[] args) // Here is the driver!!! { Staff personnel = new Staff(); //creates an object personnel of type Staff. personnel. payday(); // This appears to invoke the payday method found in personnel. }// end main() Let’s look at personnel… © 2004 Pearson Addison-Wesley. All rights reserved 27 15 }
// Staff. java Author: Lewis/Loftus Represents the personnel staff of a particular business. We have just created an object of type Staff public class Staff called ‘personnel’ on previous slide… { private Staff. Member[] staff. List; 1 of 2 // we are creating a reference to array of Staff. Member references. // This is merely a nulll pointer at this time. Array of null pointers has not yet been allocated. public Staff () // Constructor: Sets up the list of staff members when ‘personnel’ was declared: { staff. List = new Staff. Member[6]; //Creates array of six null pointers. Code below initializes objects. staff. List[0] = new Executive ("Sam", "123 Main Line", "555 -0469", "123 -45 -6789", 2423. 07); // sets pointer to point to an Executive object and this object is initialized. // staff. List[0] points to this new object. Constructor of Executive is invoked. // (seven slides down) Note: an Executive object is_a Staff. Member object too…. staff. List[1] = new Employee ("Carla", "456 Off Line", "555 -0101", "987 -65 -4321", 1246. 15); // invokes Employee Constructor (six slides down) staff. List[2] = new Employee ("Woody", "789 Off Rocker", "555 -0000", "010 -20 -3040", 1169. 23); staff. List[3] = new Hourly ("Diane", "678 Fifth Ave. ", "555 -0690", "958 -47 -3625", 10. 55); staff. List[4] = new Volunteer ("Norm", "987 Suds Blvd. ", "555 -8374"); // Uses Constructor of specified type. staff. List[5] = new Volunteer ("Cliff", "321 Duds Lane", "555 -7282"); // Array of references in Staff (personnel actually) points to a many different Staff. Member objs. ((Executive)staff. List[0]). award. Bonus (500. 00); // narrowing…via cast operator ((Hourly)staff. List[3]). add. Hours (40); } // end staff method. . © 2004 Pearson Addison-Wesley. All rights reserved 27 16
• So, what did we do? • We created six pointers to objects of the base class but declared six objects of derived classes. • So, we have pointers to the base class (remember Holiday ) with objects of the derived classes (remember day = new Christmas) • So staff. List[i] are pointers to the base class but can / will point to derived objects… © 2004 Pearson Addison-Wesley. All rights reserved 27 17
// Staff. java Author: Lewis/Loftus Represents the personnel staff of a particular business. public class Staff CLASS DEFINITION: CONTINUING FROM PREVIOUS SLIDE…. { 2 of 2 private Staff. Member[] staff. List; // we are creating a reference to array of Staff. Member references. // This is merely a nulll pointer at this time. Array of null pointers has not yet been allocated. …. . <DID THIS ON PREVIOUS SLIDE; STILL SAME CLASS> public void payday () { double amount; for (int count=0; count < staff. List. length; count++) { System. out. println (staff. List[count]); amount = staff. List[count]. pay(); // polymorphic reference to pay() in the object to which staff. List[count] points to…. if (amount == 0. 0) // Notice that each class object has its own pay() method!!! // Reference will invoke proper method! System. out. println ("Thanks!"); else System. out. println ("Paid: " + amount); System. out. println ("------------------"); } // endfor } // end payday() }// end Staff class © 2004 Pearson Addison-Wesley. All rights reserved 27 18
// Staff. Member. java Author: Lewis/Loftus // Represents a generic staff member. //********************************** abstract public class Staff. Member // NOTE: ABSTRACT CLASS – NO OBJECTS! { // CAN HAVE REFERENCES, THOUGH! protected String name; // UNLIKE AN <<interface>>, can have attributes and method bodies // which may be overridden or used via inheritance protected String address; // CAN ALSO HAVE abstract METHODS, WHICH MUST BE // EXPANDED BY DERIVED CLASS, UNLESS IT IS ALSO ABSTRACT. protected String phone; //--------------------------------// Sets up a staff member using the specified information. //--------------------------------public Staff. Member (String e. Name, String e. Address, String e. Phone) // NOTICE: HAS CONSTRUCTOR { // BUT SINCE NO INSTANTIATION, WILL BE USED BY DERIVED CLASSES. name = e. Name; address = e. Address; phone = e. Phone; } // Returns a string including the basic employee information. public String to. String() // HAS to. String ALSO – FOR USE BY INHERITANCE… { String result = "Name: " + name + "n"; result += "Address: " + address + "n"; result += "Phone: " + phone; return result; }// end to. String() // Derived classes must define the pay method for each type of employee. public abstract double pay(); // NO PARAMS; RETURNS DOUBLE. BY DEFINING pay() © 2004 Pearson Addison-Wesley. HERE All rights reserved 27 ABSTRACTLY IN STAFFMEMBER, THE payday METHOD OF STAFF 19 must be implemented in the derived classes. WE will POLYMORPHICALLY PAY EACH EMPLOYEE. }
More on Polymorphism and Abstract Classes The Staff. Member class (previous slide) is abstract because it is not intended to be instantiated. It serves as a placeholder in the inheritance hierarchy to help organize and manage objects polymorphically. Notice it also contains both concrete and abstract members!! But notice in the previous slide: public class Staff { private Staff. Member[] staff. List; // At this point we are creating a single null reference, staff. List, which appears as if it will point to an array of Staff. Members objects. But Staff. Member is an abstract class, so it cannot be instantiated. But we can create both abstract and concrete methods and an array of references which can be inherited by all of its derived classes/objects. But note when we create the objects the references point to, they cannot be Staff. Member objects because we cannot have objects of an abstract class. And, indeed (below), the objects are not Staff. Member objects; they are Executive objects, Volunteer objects, etc. public Staff () // Constructor: { staff. List = new Staff. Member[6]; // actually creates an array of six null pointers. © 2004 Pearson Addison-Wesley. All rights reserved 27 staff. List[0] = new Executive ("Sam", "123 Main Line", "555 -0469", "123 -45 -6789", 2423. 07); // sets pointer to point to an Executive object, etc. 20
More on Polymorphism and Abstract Classes - 2 The pay method has no meaning at the Staff. Member level, so it is declared to be abstract. But by declaring it there, we guarantee that every object of its children will have a pay method! (All derived classes must ‘implement’ the pay method for their respective objects. This allows us to create an array of Staff. Member objects, which is actually filled with various types of staff members, and pay each one. The details of being paid are determined by each class as appropriate. © 2004 Pearson Addison-Wesley. All rights reserved 27 21
//********************************** // Volunteer. java Author: Lewis/Loftus // // Represents a staff member that works as a volunteer. //********************************** public class Volunteer extends Staff. Member INHERITANCE { // GETS NO COMPENSATION. //--------------------------------// Sets up a volunteer using the specified information. //--------------------------------public Volunteer (String e. Name, String e. Address, String e. Phone) { super (e. Name, e. Address, e. Phone); // USES SUPER TO INSTANTIATE }// end Constructor // OBJECT ATTRIBUTES. //--------------------------------// Returns a zero pay value for this volunteer. //--------------------------------public double pay() { return 0. 0; }// end double pay() } // end Volunteer class © 2004 Pearson Addison-Wesley. All rights reserved 27 22
//********************************** // Employee. java Author: Lewis/Loftus// // Represents a general paid employee. //********************************** public class Employee extends Staff. Member INHERITANCE AGAIN. { protected String social. Security. Number; NOTE: BASE CLASS ALSO! protected double pay. Rate; // INFERRED FROM protected ATTRIBUTES. //--------------------------------// Sets up an employee with the specified information. // CONSTRUCTOR public Employee (String e. Name, String e. Address, String e. Phone, String soc. Sec. Number, double rate) { super (e. Name, e. Address, e. Phone); //USES ITS BASE CLASS VIA super REFERENCE. social. Security. Number = soc. Sec. Number; // THEN TAKES CARE OF ITS OWN ATTRIBUTES. pay. Rate = rate; //THESE WILL BE ACCESSIBLE TO ITS DERIVED CLASSES } //--------------------------------// Returns information about an employee as a string. public String to. String() { // OVERRIDES STAFFMEMBER’S to. String… String result = super. to. String(); //NOTE USES super FOR ‘SOME’ AND APPENDS THE REST result += "n. Social Security Number: " + social. Security. Number; return result; } // Returns the pay rate for this employee. public double pay() // MERELY RETURNS ATTRIBUTE VALUE. { return pay. Rate; } © 2004 Pearson Addison-Wesley. All rights reserved 27 } // end Employee class 23
// Executive. java Author: Lewis/Loftus // Represents an executive staff member, who can earn a bonus NB. //********************************** public class Executive extends Employee INHERITANCE AGAIN. { private double bonus; // INHERITS FROM BOTH STAFFMEMBER AND EMPLOYEE public Executive (String e. Name, String e. Address, String e. Phone, String soc. Sec. Number, double rate) { super (e. Name, e. Address, e. Phone, soc. Sec. Number, rate); //REFERENCES EMPLOYEE CONSTRUCTOR bonus = 0; // bonus has yet to be awarded // AND SETS instance variable ‘BONUS’ = 0 }// end Constructor // Awards the specified bonus to this executive. public void award. Bonus (double exec. Bonus) // INVOKED BY THE payday METHOD IN ‘STAFF’. { bonus = exec. Bonus; }// end award. Bonus //--------------------------------// Computes and returns the pay for an executive, which is the // regular employee payment plus a one-time bonus. //--------------------------------public double pay() // OVERRIDES THE PAY METHOD OF EMPLOYEE TO ADD A BONUS, IF ANY. { double payment = super. pay() + bonus; bonus = 0; return payment; }// end double pay() © 2004 Pearson Addison-Wesley. All rights reserved }// end class 27 24
// Hourly. java Author: Lewis/Loftus // Represents an employee that gets paid by the hour. //********************************** public class Hourly extends Employee INHERITANCE… { private int hours. Worked; // Sets up this hourly employee using the specified information. public Hourly (String e. Name, String e. Address, String e. Phone, // CONSTRUCTOR String soc. Sec. Number, double rate) { super (e. Name, e. Address, e. Phone, soc. Sec. Number, rate); // USES EMPLOYEE REF. hours. Worked = 0; }// end Constructor // Adds the specified number of hours to this employee's accumulated hours. public void add. Hours (int more. Hours) { hours. Worked += more. Hours; }. // end add. Hours() public double pay() // Computes and returns the pay for this hourly employee { double payment = pay. Rate * hours. Worked; hours. Worked = 0; return payment; }// end double pay() public String to. String() { String result = super. to. String(); result += "n. Current hours: " + hours. Worked; return result; © 2004 Pearson Addison-Wesley. All rights reserved 27 }// end to. String() } // end Hourly class 25
Outline Polymorphic References Polymorphism via Inheritance Polymorphism via Interfaces © 2004 Pearson Addison-Wesley. All rights reserved 27 26
Polymorphism via Interfaces • An interface name can be used as the type of an object reference variable § Assume we have: public interface Speaker()… reference: Speaker current; and the • The current reference can be used to point to any object of any class that implements the Speaker interface (Recall, there can be no objects of the interface itself) § Then, given: current. speak(); • The version of speak that the following line invokes depends on the object that current is referencing. • Recognizing that a number of classes can implement an interface, this binding is done during run time. © 2004 Pearson Addison-Wesley. All rights reserved 27 27
Polymorphism via Interfaces • Suppose two classes, Philosopher and Dog, both implement the Speaker interface, providing distinct versions of the speak method • In the following code, the first call to speak invokes one version and the second invokes another: Speaker guest = new Philospher(); guest. speak(); guest = new Dog(); guest. speak(); © 2004 Pearson Addison-Wesley. All rights reserved 27 28
- Slides: 28