Home > Articles > Programming > Java

This chapter is from the book

This chapter is from the book

10.5 Case Study: Payroll System Using Polymorphism

This section reexamines the CommissionEmployee-BasePlusCommissionEmployee hierarchy that we explored throughout Section 9.4. Now we use an abstract method and polymorphism to perform payroll calculations based on the type of employee. We create an enhanced employee hierarchy to solve the following problem:

  • A company pays its employees on a weekly basis. The employees are of four types: Salaried employees are paid a fixed weekly salary regardless of the number of hours worked, hourly employees are paid by the hour and receive overtime pay for all hours worked in excess of 40 hours, commission employees are paid a percentage of their sales and salaried-commission employees receive a base salary plus a percentage of their sales. For the current pay period, the company has decided to reward salaried-commission employees by adding 10% to their base salaries. The company wants to implement a Java application that performs its payroll calculations polymorphically.

We use abstract class Employee to represent the general concept of an employee. The classes that extend Employee are SalariedEmployee, CommissionEmployee and HourlyEmployee. Class BasePlusCommissionEmployee—which extends CommissionEmployee—represents the last employee type. The UML class diagram in Fig. 10.2 shows the inheritance hierarchy for our polymorphic employee-payroll application. Note that abstract class Employee is italicized, as per the convention of the UML.

Figure 10.2

Fig. 10.2 Employee hierarchy UML class diagram.

Abstract superclass Employee declares the “interface” to the hierarchy—that is, the set of methods that a program can invoke on all Employee objects. We use the term “interface” here in a general sense to refer to the various ways programs can communicate with objects of any Employee subclass. Be careful not to confuse the general notion of an “interface” to something with the formal notion of a Java interface, the subject of Section 10.7. Each employee, regardless of the way his or her earnings are calculated, has a first name, a last name and a social security number, so private instance variables firstName, lastName and socialSecurityNumber appear in abstract superclass Employee.

The following sections implement the Employee class hierarchy. Each of the first four sections implements one of the concrete classes. The last section implements a test program that builds objects of all these classes and processes those objects polymorphically.

10.5.1 Creating Abstract Superclass Employee

Class Employee (Fig. 10.4) provides methods earnings and toString, in addition to the get and set methods that manipulate Employee’s instance variables. An earnings method certainly applies generically to all employees. But each earnings calculation depends on the employee’s class. So we declare earnings as abstract in superclass Employee because a default implementation does not make sense for that method—there is not enough information to determine what amount earnings should return. Each subclass overrides earnings with an appropriate implementation. To calculate an employee’s earnings, the program assigns a reference to the employee’s object to a superclass Employee variable, then invokes the earnings method on that variable. We maintain an array of Employee variables, each of which holds a reference to an Employee object (of course, there cannot be Employee objects because Employee is an abstract class—because of inheritance, however, all objects of all subclasses of Employee may nevertheless be thought of as Employee objects). The program iterates through the array and calls method earnings for each Employee object. Java processes these method calls polymorphically. Including earnings as an abstract method in Employee forces every direct subclass of Employee to override earnings in order to become a concrete class. This enables the designer of the class hierarchy to demand that each concrete subclass provide an appropriate pay calculation.

Method toString in class Employee returns a String containing the first name, last name and social security number of the employee. As we’ll see, each subclass of Employee overrides method toString to create a string representation of an object of that class that contains the employee’s type (e.g., "salaried employee:") followed by the rest of the employee’s information.

The diagram in Fig. 10.3 shows each of the five classes in the hierarchy down the left side and methods earnings and toString across the top. For each class, the diagram shows the desired results of each method. [Note: We do not list superclass Employee’s get and set methods because they are not overridden in any of the subclasses—each of these methods is inherited and used “as is” by each of the subclasses.]

Figure 10.3

Fig. 10.3 Polymorphic interface for the Employee hierarchy classes.

Let us consider class Employee’s declaration (Fig. 10.4). The class includes a constructor that takes the first name, last name and social security number as arguments (lines 11–16); get methods that return the first name, last name and social security number (lines 25–28, 37–40 and 49–52, respectively); set methods that set the first name, last name and social security number (lines 19–22, 31–34 and 43–46, respectively); method toString (lines 55–59), which returns the string representation of Employee; and abstract method earnings (line 62), which will be implemented by subclasses. Note that the Employee constructor does not validate the social security number in this example. Normally, such validation should be provided.

Fig. 10.4. Employee abstract superclass.

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

Why did we decide to declare earnings as an abstract method? It simply does not make sense to provide an implementation of this method in class Employee. We cannot calculate the earnings for a general Employee—we first must know the specific Employee type to determine the appropriate earnings calculation. By declaring this method abstract, we indicate that each concrete subclass must provide an appropriate earnings implementation and that a program will be able to use superclass Employee variables to invoke method earnings polymorphically for any type of Employee.

10.5.2 Creating Concrete Subclass SalariedEmployee

Class SalariedEmployee (Fig. 10.5) extends class Employee (line 4) and overrides earnings (lines 29–32), which makes SalariedEmployee a concrete class. The class includes a constructor (lines 9–14) that takes a first name, a last name, a social security number and a weekly salary as arguments; a set method to assign a new nonnegative value to instance variable weeklySalary (lines 17–20); a get method to return weeklySalary’s value (lines 23–26); a method earnings (lines 29–32) to calculate a SalariedEmployee’s earnings; and a method toString (lines 35–39), which returns a String including the employee’s type, namely, "salaried employee: " followed by employee-specific information produced by superclass Employee’s toString method and SalariedEmployee’s getWeeklySalary method. Class SalariedEmployee’s constructor passes the first name, last name and social security number to the Employee constructor (line 12) to initialize the private instance variables not inherited from the superclass. Method earnings overrides abstract method earnings in Employee to provide a concrete implementation that returns the SalariedEmployee’s weekly salary. If we do not implement earnings, class SalariedEmployee must be declared abstract—otherwise, a compilation error occurs (and, of course, we want SalariedEmployee here to be a concrete class).

Fig. 10.5. SalariedEmployee class derived from Employee.

 1  // Fig. 10.5: SalariedEmployee.java
 2  // SalariedEmployee class extends Employee.
 4  public class SalariedEmployee extends Employee
 5  {
 6     private double weeklySalary;
 8     // four-argument constructor
 9     public SalariedEmployee( String first, String last, String ssn,
10        double salary )
11     {
12        super( first, last, ssn ); // pass to Employee constructor
13        setWeeklySalary( salary ); // validate and store salary
14     } // end four-argument SalariedEmployee constructor
16     // set salary
17     public void setWeeklySalary( double salary )
18     {
19        weeklySalary = salary < 0.0 ? 0.0 : salary;
20     } // end method setWeeklySalary
22     // return salary
23     public double getWeeklySalary()
24     {
25        return weeklySalary;
26     } // end method getWeeklySalary
28     // calculate earnings; override abstract method earnings in Employee
29     public double earnings()
30     {
31        return getWeeklySalary();
32     } // end method earnings
34     // return String representation of SalariedEmployee object
35     public String toString()
36     {
37        return String.format( "salaried employee: %s\n%s: $%,.2f",
38           super.toString(), "weekly salary", getWeeklySalary() );
39     } // end method toString
40  } // end class SalariedEmployee

Method toString (lines 35–39) of class SalariedEmployee overrides Employee method toString. If class SalariedEmployee did not override toString, SalariedEmployee would have inherited the Employee version of toString. In that case, SalariedEmployee’s toString method would simply return the employee’s full name and social security number, which does not adequately represent a SalariedEmployee. To produce a complete string representation of a SalariedEmployee, the subclass’s toString method returns "salaried employee: " followed by the superclass Employee-specific information (i.e., first name, last name and social security number) obtained by invoking the superclass’s toString method (line 38)—this is a nice example of code reuse. The string representation of a SalariedEmployee also contains the employee’s weekly salary obtained by invoking the class’s getWeeklySalary method.

10.5.3 Creating Concrete Subclass HourlyEmployee

Class HourlyEmployee (Fig. 10.6) also extends Employee (line 4). The class includes a constructor (lines 10–16) that takes as arguments a first name, a last name, a social security number, an hourly wage and the number of hours worked. Lines 19–22 and 31–35 declare set methods that assign new values to instance variables wage and hours, respectively. Method setWage (lines 19–22) ensures that wage is nonnegative, and method setHours (lines 31–35) ensures that hours is between 0 and 168 (the total number of hours in a week) inclusive. Class HourlyEmployee also includes get methods (lines 25–28 and 38–41) to return the values of wage and hours, respectively; a method earnings (lines 44–50) to calculate an HourlyEmployee’s earnings; and a method toString (lines 53–58), which returns the employee’s type, namely, "hourly employee: " and Employee-specific information. Note that the HourlyEmployee constructor, like the SalariedEmployee constructor, passes the first name, last name and social security number to the superclass Employee constructor (line 13) to initialize the private instance variables. In addition, method toString calls superclass method toString (line 56) to obtain the Employee-specific information (i.e., first name, last name and social security number)—this is another nice example of code reuse.

Fig. 10.6. HourlyEmployee class derived from Employee.

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

10.5.4 Creating Concrete Subclass CommissionEmployee

Class CommissionEmployee (Fig. 10.7) extends class Employee (line 4). The class includes a constructor (lines 10–16) that takes a first name, a last name, a social security number, a sales amount and a commission rate; set methods (lines 19–22 and 31–34) to assign new values to instance variables commissionRate and grossSales, respectively; get methods (lines 25–28 and 37–40) that retrieve the values of these instance variables; method earnings (lines 43–46) to calculate a CommissionEmployee’s earnings; and method toString (lines 49–55), which returns the employee’s type, namely, "commission employee: " and Employee-specific information. The constructor also passes the first name, last name and social security number to Employee’s constructor (line 13) to initialize Employee’s private instance variables. Method toString calls superclass method toString (line 52) to obtain the Employee-specific information (i.e., first name, last name and social security number).

Fig. 10.7. CommissionEmployee class derived from Employee.

 1  // Fig. 10.7: CommissionEmployee.java
 2  // CommissionEmployee class extends Employee.
 4  public class CommissionEmployee extends Employee
 5  {
 6     private double grossSales; // gross weekly sales
 7     private double commissionRate; // commission percentage
 9     // five-argument constructor
10     public CommissionEmployee( String first, String last, String ssn,
11        double sales, double rate )
12     {
13        super( first, last, ssn );
14        setGrossSales( sales );
15        setCommissionRate( rate );
16     } // end five-argument CommissionEmployee constructor
18     // set commission rate
19     public void setCommissionRate( double rate )
20     {
21        commissionRate = ( rate > 0.0 && rate < 1.0 ) ? rate : 0.0;
22     } // end method setCommissionRate
24     // return commission rate
25     public double getCommissionRate()
26     {
27        return commissionRate;
28     } // end method getCommissionRate
30     // set gross sales amount
31     public void setGrossSales( double sales )
32     {
33        grossSales = ( sales < 0.0 ) ? 0.0 : sales;
34     } // end method setGrossSales
36     // return gross sales amount
37     public double getGrossSales()
38     {
39        return grossSales;
40     } // end method getGrossSales
42     // calculate earnings; override abstract method earnings in Employee
43     public double earnings()
44     {
45        return getCommissionRate() * getGrossSales();
46     } // end method earnings
48     // return String representation of CommissionEmployee object
49     public String toString()
50     {
51        return String.format( "%s: %s\n%s: $%,.2f; %s: %.2f",
52           "commission employee", super.toString(),
53           "gross sales", getGrossSales(),
54           "commission rate", getCommissionRate() );
55     } // end method toString
56  } // end class CommissionEmployee

10.5.5 Creating Indirect Concrete Subclass BasePlusCommissionEmployee

Class BasePlusCommissionEmployee (Fig. 10.8) extends class CommissionEmployee (line 4) and therefore is an indirect subclass of class Employee. Class BasePlusCommissionEmployee has a constructor (lines 9–14) that takes as arguments a first name, a last name, a social security number, a sales amount, a commission rate and a base salary. It then passes the first name, last name, social security number, sales amount and commission rate to the CommissionEmployee constructor (line 12) to initialize the inherited members. BasePlusCommissionEmployee also contains a set method (lines 17–20) to assign a new value to instance variable baseSalary and a get method (lines 23–26) to return baseSalary’s value. Method earnings (lines 29–32) calculates a BasePlusCommissionEmployee’s earnings. Note that line 31 in method earnings calls superclass CommissionEmployee’s earnings method to calculate the commission-based portion of the employee’s earnings. This is a nice example of code reuse. BasePlusCommissionEmployee’s toString method (lines 35–40) creates a string representation of a BasePlusCommissionEmployee that contains "base-salaried", followed by the String obtained by invoking superclass CommissionEmployee’s toString method (another example of code reuse), then the base salary. The result is a String beginning with "base-salaried commission employee" followed by the rest of the BasePlusCommissionEmployee’s information. Recall that CommissionEmployee’s toString obtains the employee’s first name, last name and social security number by invoking the toString method of its superclass (i.e., Employee)—yet another example of code reuse. Note that BasePlusCommissionEmployee’s toString initiates a chain of method calls that span all three levels of the Employee hierarchy.

Fig. 10.8. BasePlusCommissionEmployee derives from CommissionEmployee.

 1  // Fig. 10.8: BasePlusCommissionEmployee.java
 2  // BasePlusCommissionEmployee class extends CommissionEmployee.
 4  public class BasePlusCommissionEmployee extends CommissionEmployee
 5  {
 6     private double baseSalary; // base salary per week
 8     // six-argument constructor
 9     public BasePlusCommissionEmployee( String first, String last,
10        String ssn, double sales, double rate, double salary )
11     {
12        super( first, last, ssn, sales, rate );
13        setBaseSalary( salary ); // validate and store base salary
14     } // end six-argument BasePlusCommissionEmployee constructor
16        // set base salary
17     public void setBaseSalary( double salary )
18     {
19        baseSalary = ( salary < 0.0 ) ? 0.0 : salary; // non-negative
20     } // end method setBaseSalary
22     // return base salary
23     public double getBaseSalary()
24     {
25        return baseSalary;
26     } // end method getBaseSalary
28     // calculate earnings; override method earnings in CommissionEmployee
29     public double earnings()
30     {
31        return getBaseSalary() + super.earnings();
32     } // end method earnings
34     // return String representation of BasePlusCommissionEmployee object
35     public String toString()
36     {
37        return String.format( "%s %s; %s: $%,.2f",
38           "base-salaried", super.toString(),
39           "base salary", getBaseSalary() );
40     } // end method toString
41  } // end class BasePlusCommissionEmployee

10.5.6 Demonstrating Polymorphic Processing, Operator instanceof and Downcasting

To test our Employee hierarchy, the application in Fig. 10.9 creates an object of each of the four concrete classes SalariedEmployee, HourlyEmployee, CommissionEmployee and BasePlusCommissionEmployee. The program manipulates these objects, first via variables of each object’s own type, then polymorphically, using an array of Employee variables. While processing the objects polymorphically, the program increases the base salary of each BasePlusCommissionEmployee by 10% (this, of course, requires determining the object’s type at execution time). Finally, the program polymorphically determines and outputs the type of each object in the Employee array. Lines 9–18 create objects of each of the four concrete Employee subclasses. Lines 22–30 output the string representation and earnings of each of these objects. Note that each object’s toString method is called implicitly by printf when the object is output as a String with the %s format specifier.

Fig. 10.9. Employee class hierarchy test program.

 1  // Fig. 10.9: PayrollSystemTest.java
 2  // Employee hierarchy test program.
 4  public class PayrollSystemTest
 5  {
 6     public static void main( String args[] )
 7     {
 8        // create subclass objects
 9        SalariedEmployee salariedEmployee =
10           new SalariedEmployee( "John", "Smith", "111-11-1111", 800.00 );
11        HourlyEmployee hourlyEmployee =
12           new HourlyEmployee( "Karen", "Price", "222-22-2222", 16.75, 40 );
13        CommissionEmployee commissionEmployee =
14           new CommissionEmployee(
15           "Sue", "Jones", "333-33-3333", 10000, .06 );
16        BasePlusCommissionEmployee basePlusCommissionEmployee =
17           new BasePlusCommissionEmployee(
18           "Bob", "Lewis", "444-44-4444", 5000, .04, 300 );
20        System.out.println( "Employees processed individually:\n" );
22        System.out.printf( "%s\n%s: $%,.2f\n\n",
23           salariedEmployee, "earned", salariedEmployee.earnings() );
24        System.out.printf( "%s\n%s: $%,.2f\n\n",
25           hourlyEmployee, "earned", hourlyEmployee.earnings() );
26        System.out.printf( "%s\n%s: $%,.2f\n\n",
27           commissionEmployee, "earned", commissionEmployee.earnings() );
28        System.out.printf( "%s\n%s: $%,.2f\n\n",
29           basePlusCommissionEmployee,
30           "earned", basePlusCommissionEmployee.earnings() );
32        // create four-element Employee array
33        Employee employees[] = new Employee[ 4 ];
35        // initialize array with Employees
36        employees[ 0 ] = salariedEmployee;
37        employees[ 1 ] = hourlyEmployee;
38        employees[ 2 ] = commissionEmployee;
39        employees[ 3 ] = basePlusCommissionEmployee;
41        System.out.println( "Employees processed polymorphically:\n" );
43        // generically process each element in array employees
44        for ( Employee currentEmployee : employees )
45        {
46           System.out.println( currentEmployee ); // invokes toString
48           // determine whether element is a BasePlusCommissionEmployee
49           if ( currentEmployee instanceof BasePlusCommissionEmployee )
50           {
51              // downcast Employee reference to
52              // BasePlusCommissionEmployee reference
53              BasePlusCommissionEmployee employee =
54                 ( BasePlusCommissionEmployee ) currentEmployee;
56              double oldBaseSalary = employee.getBaseSalary();
57              employee.setBaseSalary( 1.10  * oldBaseSalary );
58              System.out.printf(
59                 "new base salary with 10%% increase is: $%,.2f\n",
60                 employee.getBaseSalary() );
61           } // end if
63           System.out.printf(
64              "earned $%,.2f\n\n", currentEmployee.earnings() );
65        } // end for
67        // get type name of each object in employees array
68        for ( int j = 0; j < employees.length; j++ )
69           System.out.printf( "Employee %d is a %s\n", j,
70              employees[ j ].getClass().getName() );
71     } // end main
72  } // end class PayrollSystemTest
Employees processed individually:

salaried employee: John Smith
social security number: 111-11-1111
weekly salary: $800.00
earned: $800.00

hourly employee: Karen Price
social security number: 222-22-2222
hourly wage: $16.75; hours worked: 40.00
earned: $670.00

commission employee: Sue Jones
social security number: 333-33-3333
gross sales: $10,000.00; commission rate: 0.06
earned: $600.00

base-salaried commission employee: Bob Lewis
social security number: 444-44-4444
gross sales: $5,000.00; commission rate: 0.04; base salary: $300.00
earned: $500.00

Employees processed polymorphically:

salaried employee: John Smith
social security number: 111-11-1111
weekly salary: $800.00
earned $800.00

hourly employee: Karen Price
social security number: 222-22-2222
hourly wage: $16.75; hours worked: 40.00
earned $670.00

commission employee: Sue Jones
social security number: 333-33-3333
gross sales: $10,000.00; commission rate: 0.06
earned $600.00

base-salaried commission employee: Bob Lewis
social security number: 444-44-4444
gross sales: $5,000.00; commission rate: 0.04; base salary: $300.00
new base salary with 10% increase is: $330.00
earned $530.00

Employee 0 is a SalariedEmployee
Employee 1 is a HourlyEmployee
Employee 2 is a CommissionEmployee
Employee 3 is a BasePlusCommissionEmployee

Line 33 declares employees and assigns it an array of four Employee variables. Line 36 assigns the reference to a SalariedEmployee object to employees[ 0 ]. Line 37 assigns the reference to an HourlyEmployee object to employees[ 1 ]. Line 38 assigns the reference to a CommissionEmployee object to employees[ 2 ]. Line 39 assigns the reference to a BasePlusCommissionEmployee object to employee[ 3 ]. Each assignment is allowed, because a SalariedEmployee is an Employee, an HourlyEmployee is an Employee, a CommissionEmployee is an Employee and a BasePlusCommissionEmployee is an Employee. Therefore, we can assign the references of SalariedEmployee, HourlyEmployee, CommissionEmployee and BasePlusCommissionEmployee objects to superclass Employee variables, even though Employee is an abstract class.

Lines 44–65 iterate through array employees and invoke methods toString and earnings with Employee control variable currentEmployee. The output illustrates that the appropriate methods for each class are indeed invoked. All calls to method toString and earnings are resolved at execution time, based on the type of the object to which currentEmployee refers. This process is known as dynamic binding or late binding. For example, line 46 implicitly invokes method toString of the object to which currentEmployee refers. As a result of dynamic binding, Java decides which class’s toString method to call at execution time rather than at compile time. Note that only the methods of class Employee can be called via an Employee variable (and Employee, of course, includes the methods of class Object). (Section 9.7 discusses the set of methods that all classes inherit from class Object.) A superclass reference can be used to invoke only methods of the superclass (and the superclass can invoke overridden versions of these in the subclass).

We perform special processing on BasePlusCommissionEmployee objects—as we encounter these objects, we increase their base salary by 10%. When processing objects polymorphically, we typically do not need to worry about the “specifics,” but to adjust the base salary, we do have to determine the specific type of Employee object at execution time. Line 49 uses the instanceof operator to determine whether a particular Employee object’s type is BasePlusCommissionEmployee. The condition in line 49 is true if the object referenced by currentEmployee is a BasePlusCommissionEmployee. This would also be true for any object of a BasePlusCommissionEmployee subclass because of the is-a relationship a subclass has with its superclass. Lines 53–54 downcast currentEmployee from type Employee to type BasePlusCommissionEmployee—this cast is allowed only if the object has an is-a relationship with BasePlusCommissionEmployee. The condition at line 49 ensures that this is the case. This cast is required if we are to invoke subclass BasePlusCommissionEmployee methods getBaseSalary and setBaseSalary on the current Employee object—as you’ll see momentarily, attempting to invoke a subclass-only method directly on a superclass reference is a compilation error.

If the instanceof expression in line 49 is true, the body of the if statement (lines 49–61) performs the special processing required for the BasePlusCommissionEmployee object. Using BasePlusCommissionEmployee variable employee, lines 56 and 57 invoke subclass-only methods getBaseSalary and setBaseSalary to retrieve and update the employee’s base salary with the 10% raise.

Lines 63–64 invoke method earnings on currentEmployee, which calls the appropriate subclass object’s earnings method polymorphically. As you can see, obtaining the earnings of the SalariedEmployee, HourlyEmployee and CommissionEmployee polymorphically in lines 63–64 produces the same result as obtaining these employees’ earnings individually in lines 22–27. However, the earnings amount obtained for the BasePlusCommissionEmployee in lines 63–64 is higher than that obtained in lines 28–30, due to the 10% increase in its base salary.

Lines 68–70 display each employee’s type as a string. Every object in Java knows its own class and can access this information through the getClass method, which all classes inherit from class Object. The getClass method returns an object of type Class (from package java.lang), which contains information about the object’s type, including its class name. Line 70 invokes the getClass method on the object to get its runtime class (i.e., a Class object that represents the object’s type). Then method getName is invoked on the object returned by getClass to get the class’s name. To learn more about class Class, see its online documentation at java.sun.com/javase/6/docs/api/java/lang/Class.html.

In the previous example, we avoided several compilation errors by downcasting an Employee variable to a BasePlusCommissionEmployee variable in lines 53–54. If you remove the cast operator ( BasePlusCommissionEmployee ) from line 54 and attempt to assign Employee variable currentEmployee directly to BasePlusCommissionEmployee variable employee, you’ll receive an “incompatible types” compilation error. This error indicates that the attempt to assign the reference of superclass object commissionEmployee to subclass variable basePlusCommissionEmployee is not allowed. The compiler prevents this assignment because a CommissionEmployee is not a BasePlusCommissionEmployee—the is-a relationship applies only between the subclass and its superclasses, not vice versa.

Similarly, if lines 56, 57 and 60 used superclass variable currentEmployee, rather than subclass variable employee, to invoke subclass-only methods getBaseSalary and setBaseSalary, we would receive a “cannot find symbol” compilation error on each of these lines. Attempting to invoke subclass-only methods on a superclass reference is not allowed. While lines 56, 57 and 60 execute only if instanceof in line 49 returns true to indicate that currentEmployee has been assigned a reference to a BasePlusCommissionEmployee object, we cannot attempt to invoke subclass BasePlusCommissionEmployee methods getBaseSalary and setBaseSalary on superclass Employee reference currentEmployee. The compiler would generate errors in lines 56, 57 and 60, because getBaseSalary and setBaseSalary are not superclass methods and cannot be invoked on a superclass variable. Although the actual method that is called depends on the object’s type at execution time, a variable can be used to invoke only those methods that are members of that variable’s type, which the compiler verifies. Using a superclass Employee variable, we can invoke only methods found in class Employeeearnings, toString and Employee’s get and set methods.

10.5.7 Summary of the Allowed Assignments Between Superclass and Subclass Variables

Now that you have seen a complete application that processes diverse subclass objects polymorphically, we summarize what you can and cannot do with superclass and subclass objects and variables. Although a subclass object also is a superclass object, the two objects are nevertheless different. As discussed previously, subclass objects can be treated as if they are superclass objects. But because the subclass can have additional subclass-only members, assigning a superclass reference to a subclass variable is not allowed without an explicit cast—such an assignment would leave the subclass members undefined for the superclass object.

In the current section and in Section 10.3 and Chapter 9, we have discussed four ways to assign superclass and subclass references to variables of superclass and subclass types:

  1. Assigning a superclass reference to a superclass variable is straightforward.
  2. Assigning a subclass reference to a subclass variable is straightforward.
  3. Assigning a subclass reference to a superclass variable is safe, because the subclass object is an object of its superclass. However, this reference can be used to refer only to superclass members. If this code refers to subclass-only members through the superclass variable, the compiler reports errors.
  4. Attempting to assign a superclass reference to a subclass variable is a compilation error. To avoid this error, the superclass reference must be cast to a subclass type explicitly. At execution time, if the object to which the reference refers is not a subclass object, an exception will occur. (For more on exception handling, see Chapter 13.) The instanceof operator can be used to ensure that such a cast is performed only if the object is a subclass object.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information

To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.


Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.


If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information

Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.


This site is not directed to children under the age of 13.


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information

If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information

Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents

California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure

Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact

Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice

We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020