How To: Implementing a Class
Hopefully this guide will be a useful reference to you as you write more and more complex classes. This text is HEAVILY inspired by Cay Horstmann’s Big Java although I do things in a slightly different order. Any errors or bad advice are my own.
As you follow this tutorial, write the code and make sure you understand it step by step. We’ll go through creating a CashRegister class. Objects created from this class should be able to do the following:
- Ring up the sales price for a purchased item
- Enter a payment amount
- Calculate the amount of change due
Notice that there’s no sales tax, no sales total calculation, etc. It’s meant to be a very simple example.
Step 1: Determine instance fields
What information does an object built from the class you are creating need to store? This can sometimes be a little tricky and will require you to think ahead to the kinds of state changes that an object might go through over its lifetime. Remember also that methods can be called in any order so objects need to have enough internal memory to process each action at any time.
In the cash register example, it is clear that you will need to keep track of a running total of purchases charged. In our CashRegister.java file, we can write:
public class CashRegister {
public double charges; // running total of purchases
}
It’s ok to come up with the more obvious state first and come back and add fields later. But let’s think a little further ahead by looking at what our class needs to do. We know we have to ring up items, and that’s what we’ll store in the charges field. We also need to be able to calculate change as a separate task as receiving payment. Thus, a cash register object needs to keep track of what payments have been applied so far.
public class CashRegister {
public double charges; // running total of purchases
public double payment; // running total of payments made
}
Step 2: Find out which methods you need and write their headers
For now, when I ask you to write classes, I will generally specify the kind of behavior you should be simulating. In the future, you will have to figure those out yourself from the context of the task you are completing.
I highly recommend starting by coming up with calls applied to a sample object, first. This is really helpful for understanding how each method will be used, what the parameters need to be and whether or not they will return anything. In a file called CashRegisterClient.java, you can have a main method containing the following:
CashRegister register = new CashRegister(); register.recordPurchase(29.95); register.recordPurchase(9.95); register.enterPayment(50); double change = register.giveChange();
This should help you see a number of things about what you’ll have to write in the CashRegister class. Clearly, recordPurchase needs to take a double parameter. Similarly, it’s clear that the giveChange() method needs to return a double.
Now, it should be fairly simple to write the method headers for your CashRegister class. In CashRegister.java, you can write the following:
-
public void recordPurchase(double amount)
-
public void enterPayment(double amount)
-
public double giveChange()
Step 3: Write constructors
Often, you will need some way of initializing the state of objects of the type you are creating. I think it’s a good place to start actually writing code because constructors are generally pretty simple and give you a sense of the initial state of your objects.
In the CashRegister case, there’s nothing really to do when objects are created. We can write an explicit constructor or just let Java use default values for the instance variables. I don’t really see any reason to write an explicit constructor, but to review the syntax, here it is:
public CashRegister() {
charges = 0;
payment = 0;
}
Notice that there is no type listed with the two variables. THIS IS VERY IMPORTANT! If you wrote int charges = 0 instead, you would create a variable local to the constructor and not modify the instance variable! To make it more explicit that you want to refer to the instance variable, you can use the keyword this in the following way:
public CashRegister() {
this.charges = 0;
this.payment = 0;
}
It should be very clear now that you’re talking about object state. The way to read this is “hey Java, no matter what object of type CashRegister you’re in, I want you to take that one’s charges and payment fields and set them to 0.”
Step 4: Implement methods, testing as you go
By now, you should have all of your state figured out, method headers written and constructors completed. At this point, write methods one by one, making sure one works before moving on to the next. I recommend doing the easier ones first.
For example, we could start with the recordPurchase method:
public void recordPurchase(double amount) {
double newTotal = this.charges + amount; // notice use of this. to make it clear we're using an instance variable
this.charges = newTotal; // this. is optional but I think it can keep you from making mistakes
}
At this point, you should be able to record a purchase. Make sure this is the case by recording a couple of purchases and printing out the value of the charges field. For example, use this code in your client:
CashRegister register = new CashRegister(); register.recordPurchase(29.95); System.out.println(register.charges); register.recordPurchase(9.95); System.out.println(register.charges);
Giving change is a little more complex:
public double giveChange() {
double change = this.payment - this.charges;
this.charges = 0;
this.payment = 0;
return change;
}
A common mistake would be to forget to set the charges and payment back to 0 to get ready for the next transaction. Testing this method after you are convinced the recordPurchase method works should help you find that error very quickly.
If you have trouble with implementing a particular method, you may have chosen instance fields that are not quite right. It’s really common to come up with a set of fields that doesn’t accurately reflect the state of an object. Go back and adjust as needed.
Exercises
- Complete the CashRegister class and its client.
- Implement a class Car with the following properties and methods:
- fuel efficiency (measured in miles/gallon or liters/km — pick one and make sure to specify it in your comments)
- mileage
- fuel tank capacity (again, pick your units)
- current fuel level
- constructor that allows the user to set efficiency, mileage and tank capacity. Fuel level should be set to 0.
- drive method that simulates driving for a certain distance, reducing the gasoline in the fuel tank (you may assume that drive is never called with a distance that consumes moree than the available gas)
- getGasInTank method that returns the current amount of fuel
- addGas method that adds gas to the tank (if the amount to add exceeds the tank capacity, throw an IllegalArgumentException)
Sample usage:
Car myHybrid = new Car(50, 20000, 15); // 50 miles per gallon, 20,000 miles and 15 gallon tank myHybrid.addGas(15); // pump 15 gallons of gas myHybrid.drive(100); // drive 100 miles double gasLeft = myHybrid.getGasInTank(); // get gas remaining in tank
Create a class that tests all of your methods by creating a couple of different cars. Make sure you test all cases (ex: adding more gas than the tank has space for).




