Old version
This is the CS 112 site as it appeared on December 31, 2020.
Lab 5: Understanding Classes and Object Oriented Programming
Using folders
We strongly encourage you to create a separate folder for each lab
and each problem set, so that you can more easily keep track of
your work. For example, you could create a folder called lab2
for your work on this lab, and put all of the files for this lab
in that folder. If you are working on a lab machine, you will need
to create the folder on the Z: drive, so that it won’t be lost when
you log out.
Regrade Requests in Gradescope
This is an online video tutorial you watch at your own liesure which will guide you through the regrade request process in Gradescope.
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.
Example:
- 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 values from left to right.
-
If a single lower value is placed left of a higher value letter, it is subtracted from the total instead.
-
Only one single lower value can be subtracted from a higher value.
-
”I” can only be subtract from ”V” and ”X”. ”X” can only subtract from ”L” and ”C”, ”C” can only subtract from ”D” and ”M’, and ”V”, ”L”, and ”D” can never subtract.
In this lab we will begin by studying a static class, RomanNumeralStatic
which provides several static methods that allow us to perform
operations on roman numerals. We refer to this class as
a static class because we do not have to create an instance of this class
to invoke the methods.
After we have reviewed this static
API, we will then create
an object based version of this same class so we can
compare and contrast the differences between them.
Task 1: Static Roman Numeral Class
Begin by downloading RomanNumeralStatic.java.
Notice that several methods of this 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 value.The signature of this method is:
public static int convert(String romanNum)
Following are a few examples of test calls that are provided:
System.out.println(convert("X")); System.out.println(convert("LXXXXIX")); System.out.println(convert("CDV"));
Running your 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 (as String arguments) and returns the sum of the inputs as an integer. The signature of this method is:public static int add(String romanNum1, String romanNum2)
Following 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: Roman Numeral (Object) Class
Classes made up of only static methods are useful, however, they do not take full advantage of the Object Oriented Paradigm (OOP) that Java is based on. To illustrate the difference, let’s convert our static Roman NumeralStatic API into an object version of this class.
To begin, consider the following:
- What is 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, namely the string that represents the Roman Numeral, and the decimal value associated with it.
Once you have discussed the features of Roman Numberal objects, build your class as follows:
-
Create a new file called
RomanNumeral.java
. -
Declare the
data members
of the class as private instance variables. -
Write a
constructor
that takes in a String which is expected to be a Roman Numeral. Initialize the data members of the class based on the string passed.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 Roman Numeral representation of the decimal number. -
Write an
equals
method that checks if two RomanNumerals are equivalent. -
Write an
add
method that takes in another RomanNumeral object, and returns an integer that is the sum of the invoked RomanNumeral, and the other RomanNumeral. -
Write a
main
method to test your class. A simple test could look as followsRomanNumeral 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. Example:System.out.print( "Testing for equality: object are " ); if ( !r1.equals(r2) ) System.out.print( "not " ); System.out.println( "equal!" ); // Invoke the add method to add two roman numeral objects // Note the decimal output System.out.println( r1.add(ry) );
Task 3: Interacting with Objects and Static APIs
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 strings of roman numerals. Invoke the
add
andconvert
static methods of our static Roman Numeral class, passing the appropriate arguments to add the two roman numeral strings you created and then to see their decimal equivalents. -
Create at least two instances of RomanNumeral objects, add them together and print out the results.
-
Create an
array
of Roman numeral strings. For each element of the array, print out the corresponding integer value. -
Create an
array
of RomanNumeral objects. For each element of the array, print out the corresponding integer value.
Task 4: 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, 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 if fun. No one will see it, but you who write it!
Moving On with OOP
Task 5: Understand and use Inheritance
As we discussed in lecture, a class can extend another class.
Consider the Animal
and Cat
classes in the following Java
source code files:
Save these classes, open them in your IDE along with a simple
progam testDriver.java
that we can
use to test the methods of our classes.
Review each file and take note of how they are related.
Note: The Cat
class will not compile until we first make some
changes to it, so don’t try to compile anything yet!
-
Which class is the superclass? Which is the subclass? What does it mean that the
Cat
class extends theAnimal
class? -
The
Cat
class cannot directly access the fields it inherits fromAnimal
. Why not? -
The subclass constructor typically calls the superclass constructor to initialize the inherited fields. Write a constructor for the
Cat
class above. It should take as parameters the cat’s name and a boolean indicating whether it is short-haired, and it should call the superclass constructor to initialize the inherited fields.Update the test program to create an instance of class
Cat
.Cat c = new Cat("Kitty", false);
-
To manipulate the inherited fields, the subclass can use the inherited accessor and mutator methods. Write a
toString
method for theCat
class above. It should return a string consisting of the cat’s name followed by either" (short-haired)"
or" (long-haired)"
.Update the test program to test your method.
System.out.println( c );
-
The subclass can override an inherited method, replacing it with a version that is more appropriate. Write an
isSleeping
method for theCat
class. It should reflect the fact that cats seem to sleep all of the time!Update the test program to test your method.
-
Let’s say that we now want to define a class called
Abyssinian
for cats that belong to that particular breed of short-haired cat. Which class should it extend? -
Go ahead and create a class named
Abyssinian
, defining it so that it extends the correct class. It should not have any new fields of its own. However, it should include:-
a constructor that takes only a name, and that calls the superclass constructor to initialize the inherited fields. When making that call, make sure that it reflects the fact that Abyssinians are short-haired.
-
an
isExtroverted()
method that overrides the inherited version and replaces it with one that reflects the fact that Abyssinian cats are known to be extroverted.
Once your class is created, go ahead and test out the methods in your main program.
-
-
Another possible class for this hierarchy of animals is the
Dog
class, which you should examine now, although you don’t need to open it in your IDE. In addition to its inherited fields and methods, it has aboolean
fieldisSmall
, and methodsisSmall()
andbark()
. -
Let’s say that we have created an
Abyssinian
object and assigned it to the variablea
:Abyssinian a = new Abyssinian("Abby");
For each of the following method calls:
-
Indicate whether it will compile. Because the variable
a
is declared to be of typeAbyssinian
, a method call usinga
will compile if there is a corresponding method insideAbyssinian
objects – either defined in theAbyssinian
class itself or inherited from a superclass. A method call will not compile if there is no corresponding method in objects of that class. -
If the method call will compile, specify which version of the method will be called. In other words, in which class can we find the version of the method that will be called?
Here are the calls to test:
-
a.getNumLegs()
-
a.isExtroverted()
-
a.isSleeping(12, 30)
-
a.isSmall()
-
a.toString()
-
a.equals(a)
-
-
You will notice a static method defined in the
Animal
class namedprintAnimalName
. How can you call this method in your main program to print out the names of all the animal objects you have created? Note that it is astatic
method. How does this differ from the other methods of the class?Update the test program to test this method.
Task 6: Understand polymorphism
Your work for this task should go on the piece of paper that we give you. Please show your paper to a staff member before you leave the lab.
Thanks to a feature of Java called polymorphism, we can do something like this:
ClassA myObject = new ClassB(...);
Where ClassB
extends ClassA
, or equivalently, ClassB
is a subclass
of ClassA
. Specifying a more general type for myObject
than the
actual type of the object can be useful when writing a
method that needs to take more than one type of object as a parameter,
or when creating an array of objects of different but related types.
For example, if we wanted to have an array containing different types of animal objects, we could define the array as follows:
Animal[] zoo = new Animal[10];
Then, any element of the array could be of type Animal
or any subclass
of Animal
. In other words, this would be allowed:
zoo[0] = new Dog(...); zoo[1] = new Cat(...); zoo[2] = new Abyssinian(...);
Consider the following class headers:
public class A extends B { ... } public class B extends C { ... } public class C { ... } public class D extends C { ... }
-
Draw an inheritance hierarchy for these classes.
-
Which of these assignments would be allowed, taking into account the rules of polymorphism?
-
B myObj = new A();
-
B myObj = new C();
-
C myObj = new A();
-
A myObj = new B();
-
D myObj = new B();
-