Page 558 - Introduction to Programming with Java: A Problem Solving Approach
P. 558
524 Chapter 13 Inheritance and Polymorphism
As with primitives, if there is compatibility, you can go the other way by using a cast. In other words, you can use a cast to force an object referred to by a more generic reference variable into a more specific type—a type that’s below it in the same inheritance hierarchy. For example, if p is a Person reference variable, and Student inherits from Person, the compiler will accept this:
Student s = (Student) p;
Although the compiler will accept this statement, that does not necessarily mean the program will run suc- cessfully. For successful execution, when dynamic binding occurs, the object actually referred to by the p reference variable must be at least as specific as a Student. That is, the referenced object must be either an instance of the Student class or an instance of a descendant of the Student class. Why? Because after the assignment of the reference to a Student reference variable, the object will be expected to have all of the members that a Student has, which is generally more than all the members a Person has.
13.7 Polymorphism with Arrays
So far, you’ve seen polymorphism in the context of code fragments and a simple Pets program. Those ex- amples served their purpose—they illustrated the basics. But they didn’t illustrate the real usefulness of polymorphism. The real usefulness of polymorphism comes when you have an array or ArrayList of generic reference variables and assign different types of objects to different elements. That allows you to step through the array or ArrayList and call a polymorphic method for each element. At runtime, the JVM uses dynamic binding to pick out the particular method that applies to each type of object found.
Apago PDF Enhancer
Polymorphism in an Explicit Inheritance Hierarchy
The Pets program used polymorphic toString methods for the Dog and Cat classes. The compiler ac- cepted the Object reference variable with the toString method calls because the Object class defines its own toString method. Recall that polymorphism did not work for Dog and Cat display methods because the Object classs does not define its own display method. Suppose the method you want to make polymorphic is not defined in the Object classs. How can you have polymorphism and still satisfy the compiler? Actually, there are several related ways. One way is to create a superclass for the classes that define the different versions of the polymorphic method, and define the method within the superclass. Then use that superclass name when declaring the polymorphic reference variable(s). Another way to satisfy the compiler is to declare the method (specify the method heading only) in an abstract ancestor class and then use that ancestor class name for the reference variable type. Still another way to satisfy the compiler is to implement an interface that declares the method and then use that interface name for the reference variable type. We’ll illustrate the first way in this section and the other two ways in subsequent sections.
Payroll Example
To illustrate polymorphism in an explicit inheritance hierarchy, we’ll develop a payroll program that uses dynamic binding to select the appropriate method for calculating an employee’s pay. Employees that happen to be salaried get dynamically bound to a Salaried class’s getPay method. Employees that happen to be hourly get dynamically bound to an Hourly class’s getPay method.
Let’s start with the UML class diagram in Figure 13.8. It describes the Payroll program’s class struc- ture. As you can see, Employee is a superclass and Salaried and Hourly are subclasses. The fourth class, Payroll, is the program driver. Its main method drives the Salaried and Hourly classes by instantiating them and then calling their methods. What is the association between Payroll and the