So far, we have used classes as modules: ways of dividing a program into parts. In this lab, we will begin to explore how we can classes to create new types in Java.
In our previous use of classes, everything that we have
declared—whether method or variable—has been static
.
When we declare something as static, it means that there is exactly
one of them, and it is associated with the class.
When we declare a variable or method without specifying that it is
static
, we are saying
that there should be one for every value of the type; the way we say
that about Java is that there will be one for every instance
of the class. So we will talk about “instance variables” and
“instance methods”. Creating a value of the type is called
instantiation, and it is done using a special method called a
constructor. The constructor's job is to initialize the
instance variables. It looks much like other methods,
except that (a) it does not have a return type, and (b) it has the
same name as the class. The constructor is invoked in connection with
new
, which indicates that a new instance is to be created.
Change into the appropriate directory, and then clone the repository for this week's lab:
There will be two subdirectories in you$ hg clone /cslab/class/csci235/labs/lab7
lab7
directory, one
for each part of this lab.
Complex numbers are numbers that have a real part and an imaginary part (factor of square root of -1 or i). Here are some examples of complex numbers:
The pre-lab reading explained more about how to do arithmetic on complex numbers.
Some programming languages, such as Fortran, have a primitive complex number type. Java does not. We will write a class for complex numbers (including some operations) in this lab.
Change into the complex
directory in your working copy.
You can look at the file ComplexDriver.java
, which reads a
couple of complex numbers from the keyboard and then prints the result of
several arithmetic operations performed on them.
You will not need to modify this file, but you will want to see how it
manipulates values of type Complex
. Pay particular
attention to the places where it creates a new instance of class
Complex
.
The program twice reads a pair of double
s, creates an
instance of Complex
from each pair, and then calculates
their sum, product, and quotient.
There are methods to do these operations, but not all of them are
finished.
Now look at Complex.java
, This provides you with the
skeleton for a complex number class: the instance variables and
constructor have been provided, but you will need to write the rest of the
methods.
A. First, implement the method toString()
to make a string representation of a complex number.
Currently it returns "not implemented"
.
If your number has a 3.1 real part and 5.7 imaginary part,
it should produce a string like 3.1+5.7i
.
You should now be able to test your program, verifying that it prints correctly the numbers that were input. Take some care to do reasonable things when either (or both!) of the real or imaginary part is zero.
(You may want to commit this to your repository when you are satisfied that it works correctly.)
B. Now take a look at the plus()
method, and find
the place in ComplexDriver.java
where it is invoked:
answer = comp1.plus(comp2);
This call involves two instances of class Complex
. The
method called belongs to the one on the left of the dot; we often call
this one the receiver of the call. You can think of this call as
sending a message to comp1
asking it, “give me the result of
adding comp2
to yourself.”
You need to fill in the body of plus()
. Note that you
refer to the instance variables of the receiver with unqualified names,
while you refer to the instance variables of the parameter
other
using qualified names, such as other.real
.
C.In similar fashion, complete the methods minus()
,
times()
and dividedBy()
. Do you need a
hint for multiplication?
for division?
Compile and test. (And, probably, commit.)
The second example in the lab is a very different kind of object, one that models a game clock, as for a sporting event. This will give you a feel for the range of things that objects can be used to model or simulate. This is also an exercise in implementing a class when you can not look at the program that is the client.
Change to its directory by moving up one directory, and then down:
$ cd .. $ cd gameclock
First try compiling and running the game clock program.
$ javac GameClock.java $ java -cp .:gc.jar GC &
(You don't need to worry right now about what the -cp .:gc.jar
stuff means.)
A window will pop up (yes, this is your first program with a graphical user interface, or GUI) representing the clock. You'll notice that the clock has a current time left, buttons for stopping and starting the clock, for adding seconds, ten seconds, and minutes, and for setting the clock to a specific time.
Try the buttons out. You'll see that, although you can add time to the clock, the button to start it running doesn't work, nor does the button to set the clock to a specific time. You will implement these.
GameClock
classOpen the file GameClock.java
.
You will notice the class has three instance variables:
The time left on the clock (timeLeft
),
the time-of-day when we updated
the time left (lastUpdatedTime
),
and whether or not the clock is currently running
(running
).
Internally we keep time by milliseconds, even though
the clock will display only in seconds.
We also use the long
type instead of
int
, because that is what the Java
method System.currentTimeMillis()
returns.
Look also at the instance methods.
You should notice that the methods correspond to the
buttons on the window.
The GUI component of this program has already been written (it is
hiding in the gc.jar
file)
so that the appropriate methods will be invoked on the object
whenever the user clicks on the buttons.
The methods addSecond()
,
addTenSeconds()
,
and addMinute()
are written for you.
Figure out how they work.
The method getTime()
has also been written, but it
depends on the method update()
, which you will need to complete.
Your GameClock
needs to count down at the correct rate
as determined by the system's built-in clock, which you can read by
calling System.currentTimeMillis()
.
The clock works by maintaining a class invariant:
timeLeft
is
the time remaining.
Think first about how to update the instance variables when the
clock starts or stops (and don't forget the variable
running
!). After you have that figured out, you need to
think about how update()
changes the instance variables
so that lastUpdatedTime
becomes the current time while
maintaining the invariant.
The portion of the program that you cannot see will call
getTime()
many times each second in order to update the
display.
Your job is to:
startStop()
so that it toggles the running
boolean variable
and, when appropriate, records the time.
update()
so that the time left will be
updated correctly when the clock is running.
setTime()
. When the "Set" button is clicked,
the text from the box next to it will be passed (as a string) to
setTime()
. You may assume that the text is an integer
indicating the number of minutes to which to set the clock.
Extra credit: if the string is only an integer, interpret it as
minutes; but if the string is an integer, a colon,
and another integer (such as "5:15") intrepret it as minutes and
seconds. Note that setTime()
will be called only if the
string is in one of those formats.
Compile GameClock.java
, and run the program
as indicated above.
From your lab7
directory, make a typescript as you change
into the complex
directory and run the program. (Don't
forget to end the script.) It doesn't make sense to make a script of the
gameclock program.
Turn in your three files—typescript
,
complex/Complex.java
, and
gameclock/GameClock.java
—electronically
as lab7
.