Old version
This is the CS 112 site as it appeared on May 12, 2022.
Lab 3: Static vs. object classes; writing custom/blueprint classes
- Creating the necessary folder
- A couple of reminders
- Working with Roman numerals
- Task 1: Reviewing a static class for Roman numerals
- Task 2: Implementing a class for RomanNumeral objects
- Task 3: Creating a client program for your two classes (optional)
- Task 4: Writing another custom/blueprint class
- Task 5: An optional challenge
Creating the necessary folder
Make sure to create a subfolder called
lab3
within your cs112
folder, and put all of the files for this
lab in that folder.
A couple of reminders
-
Attendance in lab is not dependent on whether you finish the lab. Feel free to work on the lab at your own pace to get the most out of the material. Solutions will always be posted after all of the labs have been held, and you can check your solutions with those posted.
-
Working in pairs or small groups in lab is encouraged. We can learn much from each other, so feel free to pair up as directed by your lab TA.
Working with Roman numerals
Recall that a long time ago, numbers were represented with Roman numerals. The value of each Roman numeral symbol is as follows:
- I = 1
- V = 5
- X = 10
- L = 50
- C = 100
- D = 500
- M = 1000
We can represent different numbers by “stringing” together the symbols. Here are some examples:
- IX = 9
- VI = 6
- XX = 20
Given that each symbol has an individual numeric value, we can convert from Roman numeral to decimal using the following rules:
-
Reading left to right, symbols with higher values will generally appear first. In this case, the overall value is given by taking the sum of the individual symbol values from left to right.
-
If a single lower-value symbol is placed directly to the left of a higher-value symbol, the lower value is subtracted from the total instead, according to the following rules:
- I can only subtract from V and X.
- X can only subtract from L and C.
- C can only subtract from D and M.
- V, L, and D can never subtract.
In this lab we will begin by studying a static class called
RomanNumeralStatic
that provides several static methods for
performing operations on Roman numerals. We refer to this class as a
static class because we do not have to create an instance/object of this
class to invoke its methods.
After we have reviewed this collection of static methods, we will then create an object-oriented version of this same class so we can compare and contrast the differences between them.
Task 1: Reviewing a static class for Roman numerals
Begin by downloading this file:
RomanNumeralStatic.java
Make sure to put the file in your lab3
folder. If your
browser doesn’t allow you to specify where a file should be
saved, try right-clicking on its link above and choosing Save
as... or Save link as..., which should produce a dialog box
that allows you to choose the correct folder for the file.
In VS Code, open your lab3
folder using File->Open Folder,
and then click on the name of the file in the Explorer Pane to open
an editor window for it.
Notice that several methods of the class have been written. Further note that one of the methods has been declared to be private and not public. Why do you think this is the case?
-
The
main
method contains code which tests theconvert
method of this class. This method takes in a string representing a Roman numeral and returns its integer equivalent.The signature of this method is:
public static int convert(String romanNum)
Here are a few examples of the test calls that are provided:
System.out.println(convert("X")); System.out.println(convert("LXXXXIX")); System.out.println(convert("CDV"));
Running the program, you should see the following expected output:
10 99 405
-
The
main
method also contains code to test theadd
method of this class. This method accepts two Roman numerals asString
arguments and returns the sum of their values as an integer. The signature of this method is:public static int add(String romanNum1, String romanNum2)
Here are a few examples of the test calls that are provided:
System.out.println(add("X", "X")); System.out.println(add("XI", "CDV")); System.out.println(add("LXXXXIX", "I"));
Running your program, you should see the following expected output:
20 416 100
Task 2: Implementing a class for RomanNumeral
objects
Classes made up of only static methods are useful, but they don’t take
full advantage of the Object Oriented Programming (OOP) paradigm that
Java is based on. To illustrate the difference, let’s convert our
static RomanNumeralStatic
class into an object-oriented version of
this class.
To begin, consider the following:
- What are the key aspects of a Roman numeral?
- What should the attributes of this class be?
- What are the behaviours that this class should implement?
Thinking through this will help us identify the data we need to store and the methods we need to write.
A Roman numeral is a string which has a corresponding numeric value. In order to properly represent a Roman numeral then, each object we create should contain exactly two fields or data members: the string that represents the Roman numeral, and the decimal value associated with it.
In addition, the class will need to include a number of non-static
or instance methods that belong to objects of the class. We make
these methods non-static so that they will have access to the fields
of the RomanNumeral
object on which they are invoked.
Once you have discussed the features of RomanNumeral
objects,
build your class as follows:
-
Select File->New File, which will open up an empty editor window. Then select File->Save, and give the new file the name
RomanNumeral.java
. -
Write the class header, and then declare the data members of the class as private fields (aka instance variables).
-
Write a constructor that takes in a
String
that you can assume is a valid Roman numeral. Initialize the fields based on theString
that is passed in.To help you complete this method, consider what methods you have available to you in the
RomanNumeralStatic
class. Can one of those methods help here? If so, how would you call it? -
Write a
toString
method that returns the string that represents theRomanNumeral
object. We discussed this type of method in lecture. -
Write an
equals
method that checks if twoRomanNumeral
objects are equivalent. We discussed this type of method in lecture. -
Write an
add
method that takes in anotherRomanNumeral
object and returns an integer that is the sum of the calledRomanNumeral
(i.e., the object on which the method is invoked) and the otherRomanNumeral
that is passed in. -
Write a
main
method to test your class. Here’s one simple test that you could include:RomanNumeral r1 = new RomanNumeral("X"); RomanNumeral r2 = new RomanNumeral("IX"); System.out.println( r1 ); System.out.println( r2 );
Expand your
main
method to test each of the methods you have written. For example:System.out.print( "Testing for equality: the objects are " ); if ( !r1.equals(r2) ) System.out.print( "not " ); System.out.println( "equal!" ); // Invoke the add method to add two RomanNumeral objects. // Note that the output should be a decimal integer. System.out.println( r1.add(r2) );
Task 3: Creating a client program for your two classes (optional)
Create a new program TestRomanNumerals.java
. This program only
needs a main
method that we are going to use to write and test
the code we have written in our two previous classes.
Much of the code that we will write in this method we have already
written in the main
methods local to each class. However
depending on whether or not we are using the static API or creating
instance objects, the methods may not be called the same way
as they were in the main
method of their own class file.
Add code in the main
method of this class to accomplish each of the
following:
-
Create two
String
objects for Roman numerals. Invoke the staticconvert
andadd
methods of ourRomanNumeralStatic
class, passing the appropriate arguments to see the decimal equivalents of the two Roman numeral strings that you created and then to add them together. -
Create at least two instances of
RomanNumeral
objects, add them together, and print out the results. -
Create an array of
String
objects that represent Roman numerals. For each element of the array, compute and print out the corresponding integer value. -
Create an array of
RomanNumeral
objects. For each element of the array, compute and print out the corresponding integer value.
Task 4: Writing another custom/blueprint class
Our RomanNumeral
class allowed us to create our own custom data type
– i.e., our own type of object. This type of class is sometimes
referred to as a blueprint class to distinguish it from a class that
simply serves as a container for a program.
In this task, we will implement a blueprint class for Point
objects,
each of which will represent a single point with integer coordinates
(x, y).
-
Begin by downloading
Point.java
Make sure to put the file in your
lab3
folder.In VS Code, open your
lab3
folder as needed using File->Open Folder, and then click on the name of the file in the Explorer Pane to open an editor window for it.Read through the file to understand what is already provided.
-
Use File->New File to create a separate test program that you can use to create and modify
Point
objects. Give your test class an appropriate name, and don’t forget that the name of the class must match the name of the file.At the start of your test program’s
main
method, add a line in which you fill in the blanks below to create aPoint
object with an x-coordinate of -2 and a y-coordinate of 5.______ p1 = ________________;
-
The current version of the
Point
class does not employ appropriate encapsulation. To see this, add the following statements to your test program’smain
method after you create your objectp1
:System.out.println("x = " + p1.x); System.out.println("y = " + p1.y);
Running your program now should produce:
x = -2 y = 5
In a properly encapsulated class, code that is outside of a class should not be able to directly access its fields. Make the necessary changes to prevent this, and then try to rerun your test program.
If you’ve been successful, your code should no longer compile.
-
To provide indirect access to the fields, you must add a public accessor method and a public mutator method for each field.
Note that each coordinate can take on any integer value, which means that the mutators don’t need to perform any error-checking, and that we also don’t need to add any error-checking to the constructor. However, keep in mind that ordinarily you do need error-checking in your mutators and constructors.
-
Add the following statement to your
main
method. What do you expect to see when you execute your program?System.out.println(p1);
To see something more descriptive, uncomment the
toString()
method in thePoint
class, and then save and rerun your program.Note that we don’t need to actually call the
toString()
method. Rather, it is called on our behalf whenever we print an object of the class. -
Add an accessor method called
quadrant
that returns the number of the quadrant (if any) in which the calledPoint
object (this
) falls. The method should return:- 1 if both coordinates are positive
- 2 if the x coordinate is negative and the y coordinate is positive
- 3 if both coordinates are negative
- 4 if the x coordinate is positive and the y coordinate is negative
- 0 if the point lies on the x-axis or y-axis
Example 1:
Point p1 = new Point(3, 4); System.out.println(p1.quadrant());
Running this code, you should expect to see:
1
Example 2:
Point p3 = new Point(-3, -4); System.out.println(p3.quadrant());
You should expect to see:
3
Example 3:
Point p5 = new Point(0, -4); System.out.println(p5.quadrant());
You should expect to see:
0
-
Although most of the methods in a blueprint class are non-static (meaning that we can think of them as being inside each object of the class), blueprint classes can also include static methods (which belong to the class as a whole).
A non-static method is preferred if the method needs to access to the fields of a particular called object. However, if a method does not need a called object – i.e., if it makes more sense to pass in all of the information that it needs as parameters – then we typically make it static.
Write a static method
closestToOrigin()
that takes twoPoint
objects and returns thePoint
that is closest to the origin.Hint: Make use of the
distanceFromOrigin()
method that everyPoint
has!Because the method is static, we must prepend the class name to call it from outside the class:
Point p1 = new Point(3, 4); Point p2 = new Point(2, -1); System.out.println(Point.closestToOrigin(p1, p2));
You should expect to see:
(2, -1)
Task 5: An optional challenge
Create a new program RomanNumeralGame.java
that creates a game that
allows you to play with roman numerals objects.
The game is of your design (feel free to adlib), but it can be played something like this:
Sample Run #1:
Welcome to my Roman Numeral Game, what is your name? Christine Hello Christine, would you like to play (yes/no)? no You are a chicken ...@&FHF!!!!
Sample Run #2:
Welcome to my Roman Numeral Game, what is your name? Sarah Hello Sarah, would you like to play (yes/no)? maybe Well, Sarah if you cannot follow simple instructions .... &D*&HS%!!!
Sample Run #3:
Welcome to my Roman Numeral Game, what is your name? Amaeli Hello Amaeli, would you like to play (yes/no)? Yes You are brave Amaeli!!! Continue to enter roman numerals, when are done, enter quit. Enter a roman numeral and be amazed: X Oh that was easy! X has a decimal value of 10! Enter a roman numeral and be amazed XX ha! Is that supposed to challeng me? XX has a decimal value of 20! Enter a roman numeral and be amazed: XXVVXCCIIXXV Thinking, Thinking, Thinking aha 235!!! Enter a roman numeral and be amazed: 10 DAA! Enter a roman numeral and be amazed: This!!!game!!!stinks!! AUTOMATIC DESTRUCTION SEQUENCE ACTIVATED. YOUR DEVICE WILL IMPLODE IN TWO MINUTES!!! Just kidding... Enter a roman numeral and be amazed: quit Quitting after only 3 tries! loser!
You guys get the idea... Make it your own, make it fun. No one will see it but you!