Home | Résumé | Courses | Contact | Useful Links | Favorite Links | USC - Homepage


Computer Science 1 - (CPTR151) - Lectures  


 Return to Courses | Course Content  



Computer Science 1 - (CPTR151)

by David Siguelnitzky, MIS; MTE

Lecture 10 - Version 1.2.1

Object-Oriented Programming: Polymorphism



Lecture Outline

    10.1 Introduction
    10.2 Relationships Among Objects in an Inheritance Hierarchy
    10.2.1 Invoking Superclass Methods from Subclass Objects
    10.2.2 Using Superclass References with Subclass-Type Variables
    10.2.3 Subclass Method Calls via Superclass-Type Variables
    10.3 Polymorphism Examples
    10.4 Case Study: Payroll System Using Polymorphism

 


10.1 Introduction


    •Polymorphism
        – Treat objects in same class hierarchy as if all superclass
        – Abstract class
            • Common functionality
        – Makes programs extensible
            • New classes added easily, can still be processed
    • In our examples
        – Use abstract superclass Shape
               • Defines common interface (functionality)
                • Point, Circle and Cylinder inherit from Shape
        – Class Employee for a natural example


10.2 Relationships Among Objects in an Inheritance Hierarchy


•Previously (Lecture 9),
– Circle inherited from Point
– Manipulated Point and Circle objects using references to invoke methods
• This section
– Invoking superclass methods from subclass objects
– Using superclass references with subclass-type variables
– Subclass method calls via superclass-type variables
• Key concept
– subclass object can be treated as superclass object
•“ is-a” relationship
• superclass is not a subclass object


10.2.1 Invoking Superclass Methods from Subclass Objects


    •Store references to superclass and subclass objects
        – Assign a superclass reference to superclass-type variable
        – Assign a subclass reference to a subclass-type variable
        – Assign a subclass reference to a superclass variable
                •“ is a” relationship


1 // Fig. 10.1: HierarchyRelationshipTest1.java
2 // Assigning superclass and subclass references to superclass- and
3 // subclass-type variables.
4 import javax.swing.JOptionPane;
5
6 public class HierarchyRelationshipTest1 {
7
8     public static void main( String[ ] args )
9     {
10             // assign superclass reference to superclass-type variable
11             Point3 point = new Point3( 30, 50 );
12
13             // assign subclass reference to subclass-type variable
14             Circle4 circle = new Circle4( 120, 89, 2.7 );
15
16             // invoke toString on superclass object using superclass variable
17             String output = "Call Point3's toString with superclass" +
18             " reference to superclass object: \n" + point.toString();
19
20             // invoke toString on subclass object using subclass variable
21             output += "\n\nCall Circle4's toString with subclass" +
22             " reference to subclass object: \n" + circle.toString();
23
24             // invoke toString on subclass object using superclass variable
25             Point3 pointRef = circle;
26             output += "\n\nCall Circle4's toString with superclass" +
27             " reference to subclass object: \n" + pointRef.toString();
28
29             JOptionPane.showMessageDialog( null, output ); // display output
30
31             System.exit( 0 );
32
33    } // end main
34
35 } // end class HierarchyRelationshipTest1



    Line 11 Assign superclass reference to superclass-type variable
    Line 14 Assign subclass reference to subclass-type variable
    Line 17 Invoke toString on superclass object using superclass variable
    Line 22 Invoke toString on subclass object using subclass variable
    Line 25 Assign subclass reference to superclass-type variable.
    Line 27 Invoke toString on subclass object using superclass variable.

 


 

10.2.2 Using Superclass References with Subclass-Type Variables
    •Previous example
        – Assigned subclass reference to superclass-type variable
            • Circle “is a” Point
    • Assign superclass reference to subclass-type variable
        – Compiler error
            • No “is a” relationship
            • Point is not a Circle
            • Circle has data/methods that Point does not
                – setRadius (declared in Circle) not declared in Point


1 // Fig. 10.2: HierarchyRelationshipTest2.java
2 // Attempt to assign a superclass reference to a subclass-type variable.
3
4 public class HierarchyRelationshipTest2 {
5
6     public static void main( String[ ] args )
7     {
8             Point3 point = new Point3( 30, 50 );
9             Circle4 circle; // subclass-type variable
10
11         // assign superclass reference to subclass-type variable
12         circle = point; // Error: a Point3 is not a Circle4
13     }
14
15 } // end class HierarchyRelationshipTest2



    Line 12 Assigning superclass reference to subclass-type variable causes compiler error.

 


 

10.2.3 Subclass Method Calls via Superclass-Type variables


    •Call a subclass method with superclass reference
        – Compiler error
            • Subclass methods are not superclass methods



1 // Fig. 10.3: HierarchyRelationshipTest3.java
2 // Attempting to invoke subclass-only member methods through
3 // a superclass reference.
4
5 public class HierarchyRelationshipTest3 {
6
7     public static void main( String[] args )
8     {
9             Point3 point;
10             Circle4 circle = new Circle4( 120, 89, 2.7 );
11
12             point = circle; // aim superclass reference at subclass object
13
14             // invoke superclass (Point3) methods on subclass
15             // (Circle4) object through superclass reference
16             int x = point.getX();
17             int y = point.getY();
18             point.setX( 10 );
19             point.setY( 20 );
20             point.toString();
21
22             // attempt to invoke subclass-only (Circle4) methods on
23             // subclass object through superclass (Point3) reference
24             double radius = point.getRadius();
25             point.setRadius( 33.33 );
26             double diameter = point.getDiameter();
27             double circumference = point.getCircumference();
28             double area = point.getArea();
29
30     } // end main
31
32 } // end class HierarchyRelationshipTest3



    Lines 24-28 Attempt to invoke subclass-only (Circle4) methods on subclass object through superclass (Point3) reference.

 


10.3 Polymorphism Examples


    • Example
        – Suppose Rectangle derives from Quadrilateral
            • Rectangle more specific than Quadrilateral
            • Any operation on Quadrilateral can be done on Rectangle (i.e., perimeter, area)



10.3 Inheriting Interface and Implementation


Shape hierarchy class diagram.


 

1 // Fig. 10.4: Point.java
2 // Point class declaration inherits from Shape.
3
4 public class Point extends Shape {
5         private int x; // x part of coordinate pair
6         private int y; // y part of coordinate pair
7
8         // no-argument constructor; x and y default to 0
9         public Point()
10         {
11                 // implicit call to Object constructor occurs here
12         }
13
14         // constructor
15         public Point( int xValue, int yValue )
16         {
17                 // implicit call to Object constructor occurs here
18                 x = xValue;
19                 y = yValue;
20         }
21
22         // set x in coordinate pair
23         public void setX( int xValue )
24         {
25                 x = xValue;
26         }
27
28         // return x from coordinate pair
29         public int getX()
30         {
31                 return x;
32        }
33
34         // set y in coordinate pair
35         public void setY( int yValue )
36         {
37                 y = yValue;
38         }
39
40         // return y from coordinate pair
41         public int getY()
42         {
43                 return y;
44        }
45
46         // override abstract method getName to return "Point"
47         public String getName()
48         {
49                 return "Point";
50         }
51
52         // override toString to return String representation of Point
53         public String toString()
54         {
55                 return "[" + getX() + ", " + getY() + "]";
56         }
57
58 } // end class Point



    Lines 47-50 Override abstract method getName.


1 // Fig. 10.5: Circle.java
2 // Circle class inherits from Point.
3
4 public class Circle extends Point {
5     private double radius; // Circle's radius
6
7     // no-argument constructor; radius defaults to 0.0
8     public Circle()
9       {
10         // implicit call to Point constructor occurs here
11     }
12
13     // constructor
14     public Circle( int x, int y, double radiusValue )
15     {
16             super( x, y ); // call Point constructor
17             setRadius( radiusValue );
18     }
19
20     // set radius
21     public void setRadius( double radiusValue )
22     {
23             radius = ( radiusValue < 0.0 ? 0.0 : radiusValue );
24     }
25
26     // return radius
27     public double getRadius()
28     {
29             return radius;
30     }
31
32     // calculate and return diameter
33     public double getDiameter()
34     {
35             return 2 * getRadius();
36     }
37
38     // calculate and return circumference
39     public double getCircumference()
40     {
41             return Math.PI * getDiameter();
42     }
43
44     // override method getArea to return Circle area
45     public double getArea()
46     {
47             return Math.PI * getRadius() * getRadius();
48     }
49
50     // override abstract method getName to return "Circle"
51     public String getName()
52     {
53             return "Circle";
54     }
55
56     // override toString to return String representation of Circle
57     public String toString()
58     {
59             return "Center = " + super.toString() + "; Radius = " + getRadius();
60     }
61
62 } // end class Circle

 


    Lines 45-48 Override method getArea to return circle area.
    Lines 51-54 Override abstract method getName.

 

1 // Fig. 10.6: Cylinder.java
2 // Cylinder class inherits from Circle.
3
4 public class Cylinder extends Circle {
5     private double height; // Cylinder's height
6
7     // no-argument constructor; height defaults to 0.0
8     public Cylinder()
9     {
10         // implicit call to Circle constructor occurs here
11     }
12
13     // constructor
14     public Cylinder( int x, int y, double radius, double heightValue )
15     {
16         super( x, y, radius ); // call Circle constructor
17         setHeight( heightValue );
18     }
19
20     // set Cylinder's height
21     public void setHeight( double heightValue )
22     {
23         height = ( heightValue < 0.0 ? 0.0 : heightValue );
24     }
25
26     // get Cylinder's height
27     public double getHeight()
28     {
29         return height;
30     }
31
32     // override abstract method getArea to return Cylinder area
33     public double getArea()
34     {
35         return 2 * super.getArea() + getCircumference() * getHeight();
36     }
37
38     // override abstract method getVolume to return Cylinder volume
39     public double getVolume()
40     {
41         return super.getArea() * getHeight();
42     }

43
44     // override abstract method getName to return "Cylinder"
45     public String getName()
46     {
47         return "Cylinder";
48     }
49
50     // override toString to return String representation of Cylinder
51     public String toString()
52     {
53         return super.toString() + "; Height = " + getHeight();
54     }
55
56 } // end class Cylinder

 


    Lines 33-36 Override method getArea to return cylinder area
    Lines 39-42 Override method getVolume to return cylinder volume
    Lines 45-48 Override abstract method getName

 


1 // Fig. 10.7: AbstractInheritanceTest.java
2 // Driver for shape, point, circle, cylinder hierarchy.
3 import java.text.DecimalFormat;
4 import javax.swing.JOptionPane;
5
6 public class AbstractInheritanceTest {
7
8     public static void main( String args[] )
9     {
10         // set floating-point number format
11         DecimalFormat twoDigits = new DecimalFormat( "0.00" );
12
13         // create Point, Circle and Cylinder objects
14         Point point = new Point( 7, 11 );
15         Circle circle = new Circle( 22, 8, 3.5 );
16         Cylinder cylinder = new Cylinder( 20, 30, 3.3, 10.75 );
17
18         // obtain name and string representation of each object
19         String output = point.getName() + ": " + point + "\n" +
20         circle.getName() + ": " + circle + "\n" + cylinder.getName() + ": " + cylinder + "\n";
21     
22
23         Shape arrayOfShapes[ ] = new Shape[ 3 ]; // create Shape array
24
25         // aim arrayOfShapes[ 0 ] at subclass Point object
26         arrayOfShapes[ 0 ] = point;
27
28         // aim arrayOfShapes[ 1 ] at subclass Circle object
29         arrayOfShapes[ 1 ] = circle;
30
31         // aim arrayOfShapes[ 2 ] at subclass Cylinder object
32         arrayOfShapes[ 2 ] = cylinder;
33
34         // loop through arrayOfShapes to get name, string
35         // representation, area and volume of every Shape in array
36         for ( int i = 0; i < arrayOfShapes.length; i++ ) {
37                 output += "\n\n" + arrayOfShapes[ i ].getName() + ": " +
38                 arrayOfShapes[ i ].toString() + "\nArea = " +
39                 twoDigits.format( arrayOfShapes[ i ].getArea() ) + "\nVolume = " +
40                 twoDigits.format( arrayOfShapes[ i ].getVolume() );
41         }
42    
43
44         JOptionPane.showMessageDialog( null, output ); // display output
45
46         System.exit( 0 );
47
48     } // end main
49
50 } // end class AbstractInheritanceTest



    Lines 26-32 Create an array of generic Shape objects
    Lines 36-42 Loop through arrayOfShapes to get name, string representation, area and volume of every shape in array

 


10.4 Case Study: Payroll System Using Polymorphism


    • Create a payroll program
        – Use abstract methods and polymorphism
    • Problem statement
        – 4 types of employees, paid weekly
            • Salaried (fixed salary, no matter the hours)
            • Hourly (overtime [>40 hours] pays time and a half)
            • Commission (paid percentage of sales)
            • Base-plus-commission (base salary + percentage of sales)
                – Boss wants to raise pay by 10%

    • Superclass Employee
        – Abstract method earnings (returns pay)
            • abstract because need to know employee type
            • Cannot calculate for generic employee
        – Other classes extend Employee

 



1 // Fig. 10.8: Employee.java
2 // Employee abstract superclass.
3
4 public abstract class Employee {
5     private String firstName;
6     private String lastName;
7     private String socialSecurityNumber;
8
9       // constructor
10     public Employee( String first, String last, String ssn )
11     {
12             firstName = first;
13             lastName = last;
14             socialSecurityNumber = ssn;
15     }
16
17     // set first name
18     public void setFirstName( String first )
19     {
20             firstName = first;
21     }
22
23     // return first name
24     public String getFirstName()
25     {
26             return firstName;
27     }
28
29     // set last name
30     public void setLastName( String last )
31    {
32             lastName = last;
33     }
34
35     // return last name
36     public String getLastName()
37     {
38             return lastName;
39     }
40
41     // set social security number
42     public void setSocialSecurityNumber( String number )
43     {
44             socialSecurityNumber = number;
45     }
46
47     // return social security number
48     public String getSocialSecurityNumber()
49     {
50             return socialSecurityNumber;
51     }
52
53    // return String representation of Employee object
54     public String toString()
55     {
56             return getFirstName() + " " + getLastName() +
57             "\nsocial security number: " + getSocialSecurityNumber();
58     }
59
60     // abstract method overridden by subclasses
61     public abstract double earnings();
62
63 } // end abstract class Employee



    Line 4 Declares class Employee as abstract class.
    Line 61 Abstract method overridden by subclasses.
 


1 // Fig. 10.9: SalariedEmployee.java
2 // SalariedEmployee class extends Employee.
3
4 public class SalariedEmployee extends Employee {
5     private double weeklySalary;
6
7     // constructor
8     public SalariedEmployee( String first, String last,
9     String socialSecurityNumber, double salary )
10     {
11             super( first, last, socialSecurityNumber );
12             setWeeklySalary( salary );
13     }
14
15     // set salaried employee's salary
16     public void setWeeklySalary( double salary )
17     {
18             weeklySalary = salary < 0.0 ? 0.0 : salary;
19     }
20
21     // return salaried employee's salary
22     public double getWeeklySalary()
23     {
24             return weeklySalary;
25     }
26
27     // calculate salaried employee's pay;
28     // override abstract method earnings in Employee
29     public double earnings()
30     {
31             return getWeeklySalary();
32     }
33
34     // return String representation of SalariedEmployee object
35     public String toString()
36     {
37             return "\nsalaried employee: " + super.toString();
38     }
39
40 } // end class SalariedEmployee



    Line 11 Use superclass constructor for basic fields.
    Lines 29-32 Must implement abstract method earnings.
 


1 // Fig. 10.10: HourlyEmployee.java
2 // HourlyEmployee class extends Employee.
3
4 public class HourlyEmployee extends Employee {
5     private double wage; // wage per hour
6     private double hours; // hours worked for week
7
8        // constructor
9        public HourlyEmployee( String first, String last,
10     String socialSecurityNumber, double hourlyWage, double hoursWorked )
11     {
12             super( first, last, socialSecurityNumber );
13             setWage( hourlyWage );
14             setHours( hoursWorked );
15     }
16
17     // set hourly employee's wage
18     public void setWage( double wageAmount )
19     {
20             wage = wageAmount < 0.0 ? 0.0 : wageAmount;
21     }
22
23     // return wage
24     public double getWage()
25     {
26             return wage;
27     }
28
29     // set hourly employee's hours worked
30     public void setHours( double hoursWorked )
31     {
32             hours = ( hoursWorked >= 0.0 && hoursWorked <= 168.0 ) ?
33             hoursWorked : 0.0;
34     }
35
36     // return hours worked
37     public double getHours()
38     {
39             return hours;
40     }
41
42     // calculate hourly employee's pay;
43     // override abstract method earnings in Employee
44     public double earnings()
45     {
46             if ( hours <= 40 ) // no overtime
47             return wage * hours;
48             else
49             return 40 * wage + ( hours - 40 ) * wage * 1.5;
50     }
51
52     // return String representation of HourlyEmployee object
53     public String toString()
54     {
55             return "\nhourly employee: " + super.toString();
56     }
57
58 } // end class HourlyEmployee



    Lines 44-50 Must implement abstract method earnings.




1 // Fig. 10.11: CommissionEmployee.java
2 // CommissionEmployee class extends Employee.
3
4 public class CommissionEmployee extends Employee {
5     private double grossSales; // gross weekly sales
6     private double commissionRate; // commission percentage
7
8     // constructor
9     public CommissionEmployee( String first, String last,
10     String socialSecurityNumber,
11     double grossWeeklySales, double percent )
12     {
13             super( first, last, socialSecurityNumber );
14             setGrossSales( grossWeeklySales );
15             setCommissionRate( percent );
16     }
17
18     // set commission employee's rate
19     public void setCommissionRate( double rate )
20     {
21             commissionRate = ( rate > 0.0 && rate < 1.0 ) ? rate : 0.0;
22     }
23
24     // return commission employee's rate
25     public double getCommissionRate()
26     {
27             return commissionRate;
28     }
29
30     // set commission employee's weekly base salary
31     public void setGrossSales( double sales )
32     {
33             grossSales = sales < 0.0 ? 0.0 : sales;
34     }
35
36     // return commission employee's gross sales amount
37     public double getGrossSales()
38     {
39             return grossSales;
40     }
41
42     // calculate commission employee's pay;
43     // override abstract method earnings in Employee
44     public double earnings()
45     {
46             return getCommissionRate() * getGrossSales();
47     }
48
49     // return String representation of CommissionEmployee object
50     public String toString()
51     {
52             return "\ncommission employee: " + super.toString();
53     }
54
55 } // end class CommissionEmployee



    Lines 44-47 Must implement abstract method earnings.



1 // Fig. 10.12: BasePlusCommissionEmployee.java
2 // BasePlusCommissionEmployee class extends CommissionEmployee.
3
4 public class BasePlusCommissionEmployee extends CommissionEmployee {
5     private double baseSalary; // base salary per week
6
7     // constructor
8     public BasePlusCommissionEmployee( String first, String last,
9     String socialSecurityNumber, double grossSalesAmount,
10   double rate, double baseSalaryAmount )
11     {
12             super( first, last, socialSecurityNumber, grossSalesAmount, rate );
13             setBaseSalary( baseSalaryAmount );
14     }
15
16     // set base-salaried commission employee's base salary
17     public void setBaseSalary( double salary )
18     {
19             baseSalary = salary < 0.0 ? 0.0 : salary;
20     }
21
22     // return base-salaried commission employee's base salary
23     public double getBaseSalary()
24     {
25             return baseSalary;
26     }
27
28     // calculate base-salaried commission employee's earnings;
29     // override method earnings in CommissionEmployee
30     public double earnings()
31     {
32             return getBaseSalary() + super.earnings();
33     }
34
35     // return String representation of BasePlusCommissionEmployee
36     public String toString()
37     {
38             return "\nbase-salaried commission employee: " +
39             super.getFirstName() + " " + super.getLastName() +
40             "\nsocial security number: " + super.getSocialSecurityNumber();
41     }
42
43 } // end class BasePlusCommissionEmployee

 


   
Lines 30-33 Override method earnings in CommissionEmployee



1 // Fig. 10.13: PayrollSystemTest.java
2 // Employee hierarchy test program.
3 import java.text.DecimalFormat;
4 import javax.swing.JOptionPane;
5
6 public class PayrollSystemTest {
7
8     public static void main( String[] args )
9     {
10         DecimalFormat twoDigits = new DecimalFormat( "0.00" );
11
12         // create Employee array
13         Employee employees[] = new Employee[ 4 ];
14
15         // initialize array with Employees
16         employees[ 0 ] = new SalariedEmployee( "John", "Smith", "111-11-1111", 800.00 );
17        
18         employees[ 1 ] = new CommissionEmployee( "Sue", "Jones", "222-22-2222", 10000, .06 );
19        
20         employees[ 2 ] = new BasePlusCommissionEmployee( "Bob", "Lewis", "333-33-3333", 5000, .04, 300 );
21        
22         employees[ 3 ] = new HourlyEmployee( "Karen", "Price", "444-44-4444", 16.75, 40 );
23        
24
25         String output = "";
26
27         // generically process each element in array employees
28         for ( int i = 0; i < employees.length; i++ ) {
29                 output += employees[ i ].toString();
30
31                 // determine whether element is a BasePlusCommissionEmployee
32                 if ( employees[ i ] instanceof BasePlusCommissionEmployee ) {
33
34                         // downcast Employee reference to
35                         // BasePlusCommissionEmployee reference
36                         BasePlusCommissionEmployee currentEmployee =
37                         ( BasePlusCommissionEmployee ) employees[ i ];
38
39                         double oldBaseSalary = currentEmployee.getBaseSalary();
40                         output += "\nold base salary: $" + oldBaseSalary;
41
42                         currentEmployee.setBaseSalary( 1.10 * oldBaseSalary );
43                         output += "\nnew base salary with 10% increase is: $" + currentEmployee.getBaseSalary();
44                 } // end if           
45
46
47
48                 output += "\nearned $" + employees[ i ].earnings() + "\n";
49
50         } // end for
51
52         // get type name of each object in employees array
53         for ( int j = 0; j < employees.length; j++ )
54                 output += "\nEmployee " + j + " is a " + employees[ j ].getClass().getName();
55 
56
57         JOptionPane.showMessageDialog( null, output ); // display output
58         System.exit( 0 );
59
60     } // end main
61
62 } // end class PayrollSystemTest



    Line 32 Determine whether element is a BasePlusCommissionEmployee
    Line 37 Downcast Employee reference to BasePlusCommissionEmployee reference
    Lines 53-55 Get type name of each object in employees array

 



                    Source: Java How to Program – 5th Edition – Deitel & Deitel



 Return to Courses | Course Content  


 Home | Résumé | Courses | Contact | Useful Links | Favorite Links | USC - Homepage