Lab 3: Writing a Class¶
In this lab, you will implement a Car
class that represents a car.
You will learn about non-static attributes and methods.
And you will gain experience creating and using objects.
Learning Objectives¶
After completing this lab, you should be able to:
- Interpret a UML class diagram and stub out the corresponding code.
- Implement constructors, accessors, mutators, equals, and toString.
- Write a test program that calls non-static methods of another class.
Step 1. Getting Started¶
Do the following steps in VS Code:
- Create a
lab03
folder under yoursrc/labs
folder. - Add two new files:
Car.java
andMain.java
. - Write the
package
andpublic class
statements. - Write a Javadoc comment with your name and date.
When finished, your Car.java
and Main.java
should look like this:
Step 2. UML Class Diagram¶
Based on the diagram below, declare each attribute and write a stub for each method.
Do not implement any methods yet, but make the code compile.
For example, if a method returns a String
, write return "";
as a stub (placeholder).
Show your code to the instructor or TA before proceeding to the next step.
classDiagram
class Car {
- make: String
- speed: double
- year: int
+ Car(make: String, year: int)
+ getMake() String
+ getSpeed() double
+ getYear() int
+ accelerate() String
+ brake()
+ equals(obj: Object) boolean
+ toString() String
}
Note
The brake()
method is void
(does not return a value).
The word void
is usually omitted in UML class diagrams.
Step 3. Constructor, Getters¶
The purpose of a constructor is to initialize the attributes of this
object.
Notice the Car
class has three attributes: make
, speed
, and year
.
The constructor has two parameters: make
and year
.
Use the parameters to initialize this
object's make
and year
.
Initialize this
object's speed
to zero.
Then write the Javadoc comment for the constructor.
Note
When writing documentation for constructors, do not use the word create.
Constructors do not "create" objects; the new
operator creates an object.
Once an object has been created, the constructor is called to initialize the object.
The purpose of a getter method is to return the current value of an attribute.
Notice that the attributes are private
, meaning they can be accessed only in the Car
class.
Other classes, like Main
, will need to use the public
getters to access the attributes.
Implement each getter by returning the corresponding attribute.
Javadoc comments are not required for most getter methods. However, a Javadoc comment is required if a getter does more than simply return an attribute.
Step 4. Test the Constructor¶
Before implementing the other methods in Car.java
, let's make sure the constructor and getter methods work correctly.
Open Main.java
and define a main
method.
Tip
In VS Code, you can type the word main
inside the class, press Ctrl+Space (shortcut for "Trigger suggestion"), and press Enter.
That will generate the code for main
for you.
However, you should memorize how to write a main
method on your own,
so that you will be able to do so on a written exam, without assistance from VS Code.
Write a Javadoc comment for main
, for example:
/**
* Test the Car class.
*
* @param args command-line arguments
*/
Then add the following code to main
:
- Create two
Car
objects.- Each car should have a different make and year.
- Write
System.out.println()
statements that show the attributes of car:getMake()
should return the make you chose.getSpeed()
should return zero (at this point).getYear()
should return the year you chose.- You should have six
println
statements in total (3 for each car).
- Write one more
System.out.println();
in the middle to separate the two cars.
Run the Main
program by clicking the button or pressing F5.
The output should look something like:
Car #1's make: Nissan
Car #1's year: 2003
Car #1's speed: 0.0
Car #2's make: Tesla
Car #2's year: 2025
Car #2's speed: 0.0
Step 5. Accelerate and Brake¶
The accelerate()
method increases the current speed of the car by 5 miles per hour.
After increasing the speed, accelerate()
returns a string describing the change.
Use the format "15.0 + 5.0 = 20.0"
where 15.0
is the old speed and 20.0
is the new speed.
Note
The String.format()
method is useful for formatting double
values.
For example, you can format the speed values to one decimal place as follows:
return String.format("%.1f + 5.0 = %.1f", speed - 5, speed);
%.1f
in the format string is replaced by an argument.
So the first %.1f
is the argument speed - 5
, and the second %.1f
is the argument speed
.
Your code must not allow the speed to increase above 150 miles per hour.
If the speed is already 150, and accelerate()
is called, the speed should remain 150.
In that case, the method should return the string "150.0 + 0.0 = 150.0"
.
The brake()
method should decrease the current speed by 5 miles per hour.
Your code must not allow the speed to decrease below 0 miles per hour.
Notice the brake()
method is void
, which means no value is returned.
Write Javadoc comments for accelerate()
and brake()
before moving on to the next step.
Step 6. Test Driving the Car¶
Add the following code to Main
:
- Call
System.out.println();
to output a blank line.- Doing so will separate Step 6's output from Step 4's output.
- Call the
accelerate()
method of the first car object.- Print the value returned from
accelerate()
. - Call
getSpeed()
, and print the result.
- Print the value returned from
- Call the
brake()
method of the first car object.- Call
getSpeed()
, and print the result.
- Call
The output for this step should look something like:
0.0 + 5.0 = 5.0
Car #1's speed: 5.0
Car #1's speed: 0.0
Step 7. The equals() method¶
The purpose of the equals()
method is to determine if two objects are equivalent.
Replace your equals()
method with the following partial solution:
@Override
public boolean equals(Object obj) {
if (obj instanceof Car) {
Car car = (Car) obj;
return true; // TODO compare make and year
}
return false;
}
The above code:
- Overrides the default implementation of
equals()
.- By default,
equals()
returns true ifthis
andobj
are the same object.
- By default,
- Checks if
obj
, which can be any type of object, is actually aCar
object.- If not, then
equals()
returns false at the end by default.
- If not, then
- Declares a
Car
variable namedcar
to reference the same object asobj
.
Finish the method by replacing the word true
with an expression that determines whether car
has the same make and year as this
object.
In other words, does car.make
equal this.make
, and does car.year
equal this.year
?
Warning
In Java, comparing strings using the ==
operator does not work.
You must call one string's equals()
method and pass the other string as the argument.
Test your equals()
method by adding the following code to Main
:
- Call
System.out.println();
to output a blank line. - Create a third
Car
object with the same make and year as the firstCar
object. - Add the following two lines:
System.out.println("Car #1 equals Car #2: " + car1.equals(car2)); System.out.println("Car #1 equals Car #3: " + car1.equals(car3));
The first line should output false
, because the two cars are different.
The second line should output true
, because the two cars have the same make and year.
Step 8: The toString() method¶
The purpose of the toString()
method is to return a string that represents the object.
Replace your toString()
method with the provided solution:
@Override
public String toString() {
return String.format("A %d %s that is going %.1f mph",
year, make, speed);
}
The above code:
- Overrides the default implementation of
toString()
.- By default,
toString()
returns the class name and the memory location of the object. For example,"labs.lab03.Car@5b6f7412"
.
- By default,
- Uses the
String.format()
method to build a string based on the object's attributes.
Note
Javadoc comments are not required for @Override
methods, because the
documentation is already defined by the default implementation.
In VS Code, you can hover the mouse over a method's name to see the documentation.
Test your toString()
method by adding the following code to Main
:
- Call
System.out.println();
to output a blank line. - Call the
accelerate()
method:- One time for the first car.
- Two times for the second car.
- Three times for the third car.
- Write
System.out.println()
statements that print each of the car objects.- You don't have to call the
toString()
method.System.out.println(car1)
will automatically call thetoString()
method ofcar1
.
- You don't have to call the
The output should look something like:
A 2003 Nissan that is going 5.0 mph
A 2025 Tesla that is going 10.0 mph
A 2003 Nissan that is going 15.0 mph
Step 9. Review and Submit¶
Your final program should call println()
18 times.
Therefore, you should have 18 lines of output (including 4 blank lines).
If not, double check that you completed the following steps:
- Step 4: output 7 lines
- Step 6: output 4 lines
- Step 7: output 3 lines
- Step 8: output 4 lines
Tip
You will refer back to this code in a future lab.
To make the code easier to remember, add the bullets above as comments to Main.java
.
For example:
// Step 8: output 4 lines
System.out.println();
car1.accelerate();
car2.accelerate();
car2.accelerate();
...
Submit both Car.java
and Main.java
to Gradescope.
Points will be allocated as follows:
Criterion | Points | Details |
---|---|---|
Compile | 0 pts | Success Required |
CompileOfficialTests | 0 pts | Success Required |
Style | 2 pts | Partial Credit Possible |
OfficialTests | 8 pts | Partial Credit Possible |