18 Capstone
After reading lesson 18, you will be able to:
- Incorporate method overloading and method overriding in an application
- Understand how to use polymorphism in an application
- Implement the comparable interface to compare objects in an application
The capstone for this unit concentrates on the learning objectives from lessons 13-17 but also includes everything we have learned so far in this book. The lesson starts with a set of business requirements. Based on these requirements, I will walk through the steps to complete an application. The business problem we are going to address is providing a report of upcoming projects for a general contracting business. A general contractor is hired for various type of projects from building a house to minor repairs. For this application, the contractor wants to keep track of the employees working on a project, the project customer’s name and address, and the start and end date for the project.
The application must be able to:
- Create a project with a start date, end date, customer name, address of the project, description, estimated cost, overhead percentage for the contractor, and a list of workers
- Print out the list of projects including the project address location
- Compare two projects and determine which project must be done first based on the start date
This is a small company that hires the following types of workers:
- Electrician
- Plumber
- Carpenter
The workers are paid hourly, but they also each have additional expenses. It is also important to understand that the general contractor might not need all of these workers for every project. For example, if the contractor is building a new house, she needs all three types of workers. But if she is only adding an extra room onto an existing house, she might only need an electrician and a carpenter.
For this lesson, the application is designed with a minimal amount of information about each project, but it is used to demonstrate the concepts from this unit. It also provides the framework for a larger, more comprehensive application such as adding inventory tracking for the general contractor. The next section reviews the classes need for this application.
18.1 Creating Classes
Since the contractor might have one or many projects going on at the same time, the program is designed to allow multiple projects to be created. Each project might have one or more workers assigned to the project. Examples of projects include building a house, adding an addition, renovating a bathroom, or even just adding outdoor motion lights. Based on the business requirements for this application, I have determined we need the following classes:
- Project class represents the information needed for the project
- Address class is used any time an address is needed, for example, the location of the project or the address of the workers
- Worker class contains general information about all workers
- Electrician, Plumber, Carpenter classes extend the Worker class
The electrician, plumber and carpenter are types of workers, so each of these classes will extend the worker class. Figure 18.1 shows the initial UML diagram for these classes. More instance variables and additional methods might be needed later, but this is a good starting point.
Figure 18.1 contains a diagram of the initial UML diagrams for each class

Using this approach to create the classes for this project, I can create a list of workers who are associated with a specific project. This design creates a list of workers which can be a regular Worker, an Electrician, a Carpenter, or a Plumber. Notice that each subclass of the Worker class overrides these methods: doWork, calculatePay and toString. Using polymorphism I can invoke the overridden methods for each type of worker when calculating their total project cost which is made up of wages and expenses. Polymorphism is also used when each subclass overrides the toString method and the JVM decides which specific version of the toString method to invoke.
One of the requirements for this project is to have the ability to compare two projects and identify which projects should be started first. To provide this comparison, the Project class implements Comparable and then overrides the compareTo method.
18.1.1 The Project class
The project class in this application will do most of the heavy lifting. For this class, I have decided to include the following instance data:
- start date
- end date
- customer name
- project description
- address location of the project
- list of workers
The constructor for this class is setup to take in the project name, owner name, address of the project, and the start/end dates of the project. Since some projects might not have start and end dates assigned yet, there are two overloaded constructors for this class. Listing 18.1 shows the first part of the Project class, I have split it into pieces to better describe what is occurring in each section.
Listing 18.1 Project Class part 1
1 package lesson18_example; 2 import java.time.LocalDate; 3 import java.util.ArrayList; 4 5 public class Project implements Comparable { //#A 6 public ArrayList<Worker> workers = new ArrayList<>(); 7 private String projectName, customer; 8 private Address projectAddress; 9 private double overheadPercent = .10, overheadAmount; 10 private LocalDate startDate, endDate; //#B 11 12 public Project(String projectName, String customer, Address projectAddress, 13 LocalDate startDate, LocalDate endDate){ 14 this.projectAddress = projectAddress; 15 this.projectName = projectName; 16 this.startDate = startDate; 17 this.endDate = endDate; 18 this.customer = customer; 19 } 20 21 public Project(String projectName, String owner, Address projectAddress){ #C 22 this.projectAddress = projectAddress; 23 this.projectName = projectName; 24 customer = owner; 25 }
Note
When I first started writing the main method for this application, I started using the Date class, but quickly realized that parts of the Date class are deprecated (which means they are no longer supported). Instead, I switched to using the java.time package and the LocalDate class to store the dates used in this application. I recommend checking out the JavaDoc from Oracle on the java.time package which is part of the Java API located here: https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html
Next, I have included a method to add the workers to the project using an ArrayList so I can easily add/remove/update the workers assigned to this project. There is also a method to calculate the cost based on the workers payroll plus any overhead amount for the general contractor. This general contractor does not earn an hourly wage, instead she assigns an overhead percentage which is added to the total cost for the project. This covers her time and expenses. The overhead amount is normally 10%, but the application has the ability to change that value depending on the degree of difficulty of the project.
Listing 18.1 Project Class part 2
26 public String getName(){return projectName;} //#A 27 public double getOverhead(){return overheadAmount;} //#A 28 public double getTotalCost(){return calculateProjectCost();} //#B 29 public void setOverhead(double overhead){ //#C 30 this.overheadPercent = overhead; 31 } 32 public void addWorkers(ArrayList<Worker> workers){ //#D 33 this.workers = workers; 34 } 35 public double calculateProjectCost(){ 36 double totalCost = 0; 37 for(Worker w:workers) { //#E 38 totalCost += w.calculatePay() 39 } 40 overheadAmount = overheadPercent * totalCost; //#F 41 totalCost += overheadAmount; 42 return totalCost; //#G 43 }
Notice in the method to calculate the Project cost, I used an enhanced for loop to obtain the information about all the workers in the ArrayList. This is helpful if you are not sure how many workers are assigned to each project, the code loops through the ArrayList and stops when it reaches the last worker.
Listing 18.1 Project Class part 3
45 @Override 46 public int compareTo(Object o) { //#A 47 if(o instanceof Project) { //#B 48 if(((Project) o).startDate.isAfter(this.startDate)) //#B 49 return -1; //#B 50 } //#B 51 return 1; //#B 52 } 53 @Override 54 public String toString(){ //#C 55 String projectDetails; 56 projectDetails = "Project name: %s" + "\nStart Date: " + 57 startDate + "\nCustomer: " + 58 customer + "\nAddress: " + 59 projectAddress.toString() + "\n" + 60 "============================================\n"; 61 for(Worker w: workers) { 62 projectDetails += w.toString() + "\n\n"; 63 } 64 projectDetails += "Project Total: $%.2f\n"; 65 projectDetails += "Contractor Overhead: $%.2f\n"; 66 return projectDetails; 67 } 68 } 69 }
In the project class, notice that it contains two overridden methods. The first is the compareTo method, this is required when you implement the Comparable interface from the Java API. In this class, I have provided logic to compare the start date of any two projects. In the compareTo method, the project compares the start date of the project that is invoking the method and passing the other project as an argument to the compareTo method.
By implementing the compareTo method in the Project class, it allows me to easily compare two projects. For this example, I am comparing the start dates of each project, but this method can easily be updated to compare other components of the project. Just remember that the compareTo method returns and integer value with the following values:
- negative number if the first object comes before the second object
- zero if they are equal
- positive number if the first object comes after the second object
This gives the programmer control on what is compared and what determines the order. We could change our project to compare two projects and identify which client name comes first alphabetically for example.
The second overridden method is the toString method. Remember, every class automatically inherits from the Object class which has a toString method. If I did not provide an overridden method, any time I called the toString method it would simply return the reference address of the object. Instead, in the Project class, the overridden version of the toString method formats and returns all the information about a project for printing.
18.1.2 The Address Class
The Address class is used to create an address object for either the worker or the location of the project. It is designed to allow for two types of addresses, one with only one street line address, and a second constructor for addresses with a second street line. The second street line is often used for identifying an apartment number or even a PO Box.
Listing 18.2 Address Class
1 package lesson18_example; 2 public class Address { 3 private String street1, street2, city, state; 4 private String zip; 5 6 public Address(String street1, String city, String state, 7 String zip){ 8 this.street1 = street1; 9 this.city = city; 10 this.state = state; 11 this.zip = zip; 12 } 13 public Address(String street1, String street2, String city, String state, //#A 14 String zip) { 15 this.street1 = street1; 16 this.street2 = street2; 17 this.city = city; 18 this.state = state; 19 this.zip = zip; 20 } 21 @Override 22 public String toString(){ //#B 23 if(street2 == null) return street1 + "\n" + 24 city + ", " + state + " "+zip; 25 else return street1 + "\n" + street2 + "\n" + 26 city + ", " + state + " "+zip; 27 } 28 }
18.1.3 The Worker class
Now that we have the Project class created, the next class I will add is the Worker class and it contains all the general information about a worker. This class will act as a superclass to the electrician, plumber and carpenter classes. Both the doWork() and the toString methods will be overridden in each subclass, these are examples of polymorphism.
Listing 18.3 Worker Class
1 package lesson18_example; 2 public class Worker { 3 public String fName, lName; 4 public Address address; 5 public int idNumber; 6 public double hoursWorked; 7 public double hourlyRate; 8 public String doWork(){ //#A 9 return "Worker"; 10 } 11 public Worker(String fName, String lName, Address address, 12 int idNumber, double hours, double rate) { 13 this.fName = fName; 14 this.lName = lName; 15 this.address = address; 16 this.idNumber = idNumber; 17 this.hoursWorked = hours; 18 this.hourlyRate = rate; 19 } 20 public void setHoursWorked(double hours) { 21 hoursWorked = hours; 22 } 23 public void setHourlyRate(double rate) { 24 hourlyRate = rate; 25 } 26 public double calculatePay() { 27 return hoursWorked * hourlyRate; 28 } 29 @Override 30 public String toString() { //#B 31 return fName + " " + lName + " \nCompensation: $"+calculatePay(); 32 } 33 }
18.1.4 The Carpenter Class
The carpenter class extends the Worker class. One of the differences between the superclass worker and the carpenter class is that it allows for the additional cost for lumber materials. It also overrides the doWork() and toString() methods which is an example that enables polymorphism. This happens when a Worker object is assigned a reference type of a Carpenter object and then invokes any of the overridden methods. The JVM first attempts to invoke the method in the Carpenter class, if it is not found, then it looks for the method in the superclass.
Listing 18.4 Carpenter Class
1 package lesson18_example; 2 public class Carpenter extends Worker { //#A 3 private double lumberCosts; 4 public Carpenter(String fName, String lName, Address address, 5 int idNumber, double hours, double rate){ 6 super(fName, lName, address, idNumber, hours, rate); //#B 7 } 8 public void setLumberCosts(double amount){ 9 lumberCosts = amount; 10 } 11 public String doWork(){ //#C 12 return "Complete carpentry work"; 13 } 14 @Override 15 public String toString() { //#D 16 return "Carpenter: "+super.toString() + "\n" + doWork(); 17 } 18 public double calculatePay(){ //#E 19 return hoursWorked * hourlyRate + lumberCosts; 20 } 21 }
18.1.5 The Electrician Class
The Electrician class also extends the Worker class. For this activity, I’ve included a variable to allow for additional expenses such as associated wiring costs. Since the Electrician class extends the Worker class, the constructor takes in the values for name, address, id number, hours and rate and uses the keyword super to assign these values to the instance data. This can be helpful especially if we need data validation, for example, if we want to make sure the hours and rate are not negative. This logic can be included once in the Worker class and then each subclass benefits from this data validation.
Listing 18.5 Electrician Class
1 package lesson18_example; 2 public class Electrician extends Worker{ //#A 3 private double wiringCost = 0.0; 4 public Electrician(String fName, String lName, Address address, 5 int idNumber, double hours, double rate){ 6 super(fName, lName, address, idNumber, hours, rate); //#B 7 } 8 public void setWiringCosts(double amount){ 9 wiringCost = amount; 10 } 11 public String doWork(){ //#C 12 return "Install electrical components"; 13 } 14 @Override 15 public String toString() { //#D 16 return "Electrician: "+super.toString() + "\n" + doWork(); 17 } 18 public double calculatePay(){ //#E 19 return hoursWorked * hourlyRate + wiringCost; 20 } 21 }
18.1.6 The Plumber Class
The Plumber class also extends the Worker class. There are definitely more differences between these types of workers, but to keep the code to a minimum I’ve tried to keep it simple. So, the Plumber class is very similar to the Carpenter and Electrician classes. But I’ve added a variable for any additional costs associated with plumbing materials.
Listing 18.6 Plumber Class
1 package lesson18_example; 2 public class Plumber extends Worker{ //#A 3 private double plumbingMaterials = 0; 4 public Plumber(String fName, String lName, Address address, 5 int idNumber, double hours, double rate){ 6 super(fName, lName, address, idNumber, hours, rate); //#B 7 } 8 public void setPlumbingCost(double amount){ 9 plumbingMaterials = amount; 10 } 11 public String doWork(){ //#C 12 return "Install plumbing"; 13 } 14 @Override 15 public String toString() { //#D 16 return "Plumber: "+super.toString() + "\n" + doWork(); 17 } 18 public double calculatePay(){ //#E 19 return hoursWorked * hourlyRate + plumbingMaterials; 20 } 21 }
A future version of this application might include more information for each type of worker. There are definitely more differences between each type of worker, but this gives you an idea of how the project can be started.
18.2 Main Application
The main application for this contractor application is used to do the following:
- Create Address objects for two customers
- Using the LocalDate class from the java.time package from the java API to create date objects for the start/end dates for each project
- Create two projects, one for a new house and one for a small project to add outdoor motion lighting
- Create Address objects for all the workers, the last worker uses an overloaded constructor since this worker has a second address line for the apartment number
- Add three workers, an electrician, plumber, and carpenter that can be used on these projects
- Add these workers to an ArrayList so we can assign them to a project
- Add all three workers to the house project
- Set the lumber costs to $2000
- Set the general contractor overhead to 18% for this large project
- Print out the project information
- Repeat the process for the small outdoor motion lighting project
- Compare the start dates to determine which project needs to start first and print the appropriate message
Now that all the classes are created, we turn our attention to the main method. The goal of the main method in this example includes logic to demonstrate all the topics covered in this unit. A few important concepts are shown in Listing 18.7 (lines 28-30) where the Worker class is used to create a reference variable that points to a subclass object. These lines are enabling polymorphism.
Since all the workers are created using the superclass Worker, line 37 shows how I had to cast the worker as the specific subclass that was used when it was created to allow access to methods defined in the subclass that were not overridden methods.
Before reviewing the code for the main method for this application, here is a printout of some sample output:
Figure 18.2 Screenshot of sample output for Contractor application

Listing 18.7 part 1 shows the main method that includes the code to create all the Address, Project, LocalDate, and Worker objects.
Listing 18.7 The main method for this application (part 1)
1 package lesson18_example; 2 import java.time.LocalDate; 3 import java.util.ArrayList; 4 import java.util.Date; 5 6 public class Lesson18_Example { 7 public static void main(String[] args) { 8 Address client1 = new Address("123 Main Street", "Anywhere", "PA", //#A 9 "19001"); 10 Address client2 = new Address("44 South Main Street", "Cleveland", "OH", 11 "42111"); 12 LocalDate start1 = LocalDate.parse("2019-11-03"); //#B 13 LocalDate end1 = LocalDate.parse("2020-05-29"); 14 Project p1 = new Project("House", "Shira Gotshalk", client1, //#C 15 start1, end1); 16 LocalDate start2 = LocalDate.parse("2019-06-26"); 17 LocalDate end2 = LocalDate.parse("2019-07-27"); 18 Project p2 = new Project("Motion Lights", "Maggie Thygeson", 19 client2, start2, end2); 20 21 Address eAddress = new Address("467 Seminole Avenue", "Jenkintown", 22 "PA", "19446"); 23 Address cAddress = new Address("88 Stallion Circle", "Horsham", 24 "PA", "19022"); 25 Address pAddress = new Address("9821", "Apt B", "Siglerville", 26 "PA", "19345"); 27 28 Worker e = new Electrician("Peg", "Fisher", eAddress, 1234, 15, 20); #D 29 Worker c = new Carpenter("Yusef", "Eberly", cAddress, 2456, 17.40, 30); 30 Worker p = new Plumber("Harley", "Davidson", pAddress, 3214, 25, 20);
Next is the second part of the main method. This is where the workers are added to the project. The first project uses all three types of workers and extra costs are assigned for each worker. The second project only requires an electrician, so the plumber and carpenter are removed from the list of workers and the wiring costs are updated for the electrician prior to creating the project. Finally, the projects are printed using the overridden method toString.
Listing 18.7 The main method for this application (part 2)
31 ArrayList<Worker> workers = new ArrayList<>(); //#E 32 33 workers.add(c); //#F 34 workers.add(e); 35 workers.add(p); 36 ((Carpenter)c).setLumberCosts(2000); //#G 37 ((Electrician)e).setWiringCosts(3200); 38 ((Plumber)p).setPlumbingCosts(2750); 39 p1.addWorkers(workers); //house requires all three workers //#H 40 p1.setOverhead(.18); //the overhead is higher for a house 41 42 System.out.printf(p1.toString(), p1.getName(), 43 p1.getTotalCost(), p1.getOverhead()); 44 System.out.println("***************************************************" 45 + "\n***************************************************\n"); 46 47 workers.remove(p); //project 2 does not need a plumber //#I 48 workers.remove(c); //project 2 does not need a carpenter 49 ((Electrician)e).setWiringCosts(300); //#J 50 workers.get(0).sethoursWorked(20); //set the hours worked to 20 //#K 51 p2.addWorkers(workers); 52 System.out.printf(p2.toString(), p2.getName(), 53 p2.getTotalCost(), p2.getOverhead()); 54 55 if (p2.compareTo(p1) < 0) { 56 System.out.println("\nThe "+p2.getName()+" project is " 57 + "scheduled before "+p1.getName()); 58 } else { 59 System.out.println("\nThe "+p1.getName()+" project is " 60 + "scheduled prior to "+p2.getName()); } 61 System.out.println("\n"); 62 p2.printPayroll(); 63 } 64 }
18.3 Summary
In this lesson, you learned:
- How to write an application that uses overloaded methods specifically for constructor methods
- How to create overridden methods in a subclass
- How to create a list of superclass objects that are instantiated as specific subclasses
- Based on the type of worker, update specific values for each project such as lumber costs, wiring costs by casting the superclass as one of the subclasses
- How to use the Comparable method and overriding the compareTo method to compare the start date of any two projects
This lesson provided an activity that included all the topics from lessons 13 - 17. In the next unit, I will continue to work with classes and objects. The first lesson in the next unit is all about the difference between pass by value vs. pass by reference.
Try this:
Use the Contractor application and add the required code to print out a payroll statement by project that includes:
- Worker name, id, address, and compensation
- Include the project name
Figure 18.3 shows a sample of the output from print a payroll report.
Figure 18.3 screenshot of payroll report

Solution to the Try This activity:
18.8 Print the payroll by project - Project Class
1 package lesson18_example; 2 import java.time.LocalDate; 3 importjava.util.ArrayList; 4 5 public class Project implements Comparable { 6 //Please see Listing 18.1 for the omitted code //#A 7 public void printPayroll(){ 8 System.out.println("Payroll Report for Project: "+ getName()); 9 System.out.println("(Salary only)"); 10 for(Worker w: workers) 11 { 12 if(w instanceof Plumber) //#B 13 System.out.print("Plumbing costs: "); 14 else if (w instanceof Electrician) 15 System.out.print("Electrician: "); 16 else if(w instanceof Carpenter) 17 System.out.print("Carpenter: "); 18 System.out.println(w.fName + " " + w.lName + "\n"+ 19 "ID number: "+w.idNumber + "\n"+ 20 w.address.toString()+ 21 "\nHourly Rate: " + w.hourlyRate + 22 "\nHours worked: " + w.hoursWorked + 23 "\nTotal Compensation: $"+w.hourlyRate * w.hoursWorked + 24 "\n================"+"\n"); 25 } 26 } 27 }
18.9 Print the payroll by project – Main Class
1 package lesson18_example; 2 import java.time.LocalDate; 3 import java.util.ArrayList; 4 import java.util.Date; 5 6 public class Lesson18_Example { 7 public static void main(String[] args) { 8 //Please see Listing 18.7 for the omitted code //#A 9 System.out.println("\n\n"); 10 house.printPayroll(); //#B 11 // System.out.printf(house.toString(), house.getName(), 12 // house.getTotalCost(), house.getOverhead()); 13 // System.out.println("***************************************************" 14 // + "\n***************************************************\n"); 15 16 workers.remove(p); //project 2 does not need a plumber 17 workers.remove(c); //project 2 does not need a carpenter 18 ((Electrician)e).setWiringCosts(300); 19 workers.get(0).hoursWorked = 20; //set the hours worked to 20 20 project2.addWorkers(workers); 21 // System.out.printf(project2.toString(), project2.getName(), 22 // project2.getTotalCost(), project2.getOverhead()); 23 // 24 // if (project2.compareTo(house) < 0) { 25 // System.out.println("\nThe outdoor light project is scheduled " 26 // + "before the addition"); 27 // } else { 28 // System.out.println("\nThe addition is scheduled prior to the " 29 // + "outdoor lighting project"); 30 // } 31 System.out.println("\n"); 32 project2.printPayroll(); //#B 33 } 34 }