The purpose of this lab is to practice building new classes by inheriting methods and data from existing classes. We’ll start with a toy example and then move on to consider our next homework assignment.
![]() |
|||
![]() |
Download the following classes for this lab: {Employee, HourlyWorker, SalariedWorker, Accountant, Driver}. These classes represent an inheritance hierarchy with the Employee class acting as the Parent class for both HourlyWorker and SalariedWorker. Read the code in each class, and run the corresponding driver to see the output from each employee. In this warm-up exercise, I have created an Accountant class, which inherits from SalariedWorker. SalariedWorker, in turn, inherits from Employee, which is the topmost class in our hierarchy. In fact, Employee is so generic that you cannot even create Employee objects (it’s an abstract class), so we must define subclasses that override the calculateWeeklyPay() method in order to create objects we can use. The Accountant class is rather short, as most of the class’s functionality is inherited from the SalariedWorker class. Your job is to create two classes here: one that inherits from SalariedWorker (see Accountant for such an example), and one that inherits from HourlyWorker. To start things off, be sure your class header indicates who you are inheriting from, such as: “public class Consultant extends HourlyWorker {“.
(1) Create a class called ClarkOlson, and this should inherit from SalariedWorker.
a. public class ClarkOlsen extends SalariedWorker
(2) Once you’ve built ClarkOlson, then you can create constructors for your class
a. See the Accountant class for examples of constructors
(3) Try overriding the calculateWeeklyPay() method in your subclass so it does something different than the original version.
a. Consider making ClarkOlson an employee that has a base salary plus a flat bonus every month, which would require a new (overridden) calculateWeeklyPay() method.
(4) Create a class called RobNash, and this should inherit from HourlyWorker
a. public class RobNash extends HourlyWorker
(5) Create constructors for RobNash just like you did in ClarkOlsen, and as you can see in Accountant.
(6) Override the calculateWeeklyPay() method so that it calculates the hours worked (20 for part-time) by the hourly pay ($3.00/hr) to produce a result.
Our classes shouldn’t start from scratch when we design them for use in our applications, and we have an opportunity to realize the often-elusive goal of code reuse here in this assignment. If you still have the Square and Circle classes from the first lab, you should locate them now (but don’t worry if you don’t have them, as we’re going to make a Square class and I’ll later give you a Square example). The purpose of this lab is to get you started with inheritance using the Shape hierarchy, so let’s begin by defining a new class (Square or Circle) that will extend (or inherit from) the Shape parent class. Define a new class with using the following format: “public class Square extends Shape {”, and make sure Shape.java is in the same directory as your new Square.java file. Even though the class is empty, it should compile just fine, and in fact, contains all the methods and data defined in the Shape superclass.
(1) Find your old Square and Shape classes, or build a new Shape superclass now.
As we build our subclasses Square and Circle, we will eventually need to access data that was declared in the Parent class Shape (x and y, specifically). If we simply try to reference x or y, we’ll get a scope error from Java. We have a few options here of how we should change the Parent Shape class. The most obvious is to add accessor and mutator functions to the Shape class, and use those. Another approach relies on a new access modifier “protected”, which is in between public and private with respect to accessibility. Protected data may be accessed by the class that defines it (Shape in this case) or by any subclass that extends this Parent class (Square and Circle here). Either of these approaches is acceptable here, and the latter gives us exposure to a new access modifier. Once you’ve modified Shape.java, be sure to recompile and run your driver to ensure nothing has changed or broken. Note that the sample Square.java I will distribute relies on accessing the x and y data items (it uses the accessor approach, but this could be circumvented if you choose to use the “protected” access modifier), so you must make the changes outlined above for it to compile.
In class Shape, there are a number of methods that need to be updated or replaced. The technique we use to accomplish this is called overriding, and it literally replaces the old method with the newly defined one whenever that method is called on our object. To override a method, we need to know the method signature as defined in the parent class so that we can define a method with an identical signature. Doing this indicates to Java that we wish to replace (or override) the older method and use this newer one whenever that method is called. We’ve been overriding the equals() and toString() methods inherited from the Object class in a number of our previous assignments. We’ll need to focus on overriding two methods in specific for our Square subclass: draw() and getArea().
If you still have the old versions of Square and Circle hanging around, notice how much code was duplicated between the two classes. By factoring out the common code into a parent class (Shape), we have reduced redundancy, increased code reuse, and are able to create new classes that “act like Shapes” rather quickly. While it may be quicker to just start with a new Square or Circle class, you can still modify the old versions to be compatible with our new software. To do so, we need to include the “extends Shape” clause to each of the classes, and then cut out all of the functions and data (since we now inherit them from Shape). The two most important functions in the subclasses are draw() and getArea(), which will function differently for the Square class than the Circle class. Lets define a draw() function in Square that actually draws a square. In the draw() method in Square, insert the line “g.drawRect(x,y,width,height);”. This tells Java to draw the rectangle at the corresponding x,y position with the defined width and height. If you’d like to set the color of the rectangle before you draw it, use “g.setColor( Color.blue );” just before the call to drawRect. For the Circle class, try the line “g.drawOval(x,y,width, height);” to draw a circle, where width == height. In fact, it seems that the Square class will need to define these two new data items that aren’t in Shape; so, go ahead and add the two new data items to your Square class for the width and the height. The Circle class doesn’t need to maintain both a width and a height (since they’ll always be the same to draw a true circle in Java2D and not an oval). This matches our intuition of circles containing an x,y coordinate pair and a radius, so go ahead and define this one extra data item in Circle (and while it’s not officially the radius here, you can go ahead and name it that, or something such as size). Make sure the draw methods now use these instance variables when calling drawRect or drawOval, and we now need to make some constructors for these classes that take an (x,y, width, height) for a Square and a (x,y,size) for a Circle. If you’d like to see an example first of the Square class in action, you can download this version for use in this project. Note that while you cannot submit a Square class for this assignment, you can submit your Circle class (so use the Square class as a guide).
(1) Build a Square subclass that extends Shape
a. Add a sideLength data member to this class
(2) Build a Circle subclass that also extends Shape
a. Add a radius data member to this class
(3) Write a method that accepts an array of Shapes and prints out each shape, regardless of subclass
It’s up to you as to the Shapes you’d like to include in your software, but for each class you create, they should all inherit from the Shape parent class and override the draw() and getArea() functions. The Graphics and Graphics2D classes provide a large number of interesting graphics functions that are premade for you, so you can draw whatever you like in your new draw() methods. For Graphics and Graphics2D functions, Google Java and {drawLine, drawString, drawPolygon, …}.