This lab is to be implemented in Java. It reinforces those concepts in Lecture 2 — Preliminaries. These topics were chosen because:
class Name { Name(String first, String last) { … // you are to supply this code } private String first, last; }supply the missing code of the constructor.
class Person { Person(Name name, int age) {…} public String toString() {return name + " (" + age + ")";} private Name name; private int age; }
class Name { Name(String first, String last) {…} public String toString() {return first + " " + last;} private String first, last; }
class Date { Date(int year, int month, int dom) {…} public String toString() {return month + "/" + dom + "/" + year;} private int year, month, dom; }Implement a subclass of
Person
named Employee
with the following state/behavior:
class Employee extends Person { Employee(Name name, int age, int id, Date hireDate) { /* for you to implement */ } Employee(String first, String last, int age, int id, int year, int month, int dom) { /* for you to implement */ } public String toString() { /* for you to implement */ } int id; Date hireDate; }i.e.,
Date
instance variable for the hire date of the employee
Employee(Name name, int age, id, Date hireDate)
Employee(String first, String last, int age, int id, int year, int month, int dom)
toString
method that returns a string of the form:
name (age) #id hire-date(you will probably want to call the corresponding methods of
Person
and Date
in this method)
toString
methods of composition classes (i.e., instance variable) and subclasses
Rational numbers can be negated, inverted, added, subtracted, multiplied, and divided in the usual manner:
re / r2
, r1
is the dividend, r2 is the divisor, and the result r1/r2
is the quotient).
To see why this works: suppose the two rationals were a/b and c/d . Then, the above would produce:
ad + cb ad cb a c ------- = -- + -- = - + - bd bd bd b d |
add
, addInPlace
, sub
, subInPlace
, mul
, mulInPlace
, div
, divInPlace
invert
and negate
, and not implement inverseInPlace
or negateInPlace
6/8
and 3/4
actually represent the same value-- they are said to be equivalent.
6/8
is actually 3/4
multiplied by 2/2
-- and since 2/2
is nothing more than 1
, we have not changed the value of the
represented number.
16/20
, the gcd of 16
and 20
is 4
and dividing 16
and 20
by 4
produces 4
and 5
respectively; thus the simplest form of 16/20
is 4/5
.
gcd(a, b) : if b == 0 return a else return gcd(b, a%b)
Rational
ClassRational
that provides basic support for rational numbers:
class Rational { Rational(int num, int denom) {…} Rational(int num) {…} Rational() {…} // default constructor Rational(Rational r) {…} // copy constructor Rational add(Rational r) {…} Rational sub(Rational r) {…} Rational mul(Rational r) {…} Rational div(Rational r) {…} Rational addInPlace(Rational r) {…} Rational subInPlace(Rational r) {…} Rational mulInPlace(Rational r) {…} Rational divInPlace(Rational r) {…} Rational negate() {…} Rational inverse() {…} int getNumerator() {…} int getDenominator() {…} int compareTo(Rational r) {…} boolean equals(Rational r) {…} public String toString() {…} private static int gcd(int a, int b) {…} private int num, denom; }i.e.,
RationalException
to be thrown
num
of the argument Rational is assigned to the num
of the new Rational (the receiver, i.e., the object referred to by
this
), and similarly for the denomm
add
, sub
, mul
, div
that perform
basic arithmetic on rational numbers. These methods take a single Rational
parameter
corresponding to the second operand (the first operand is the receiver — the Rational
operand on whom the method
is being invoked) and returns a new Rational
containing the result. Thus, if r1
contains
1/2
and r2
contains 1/4
, then calling r1.add(r2)
should return a Rational
containing 6/8
(see above for how the addition should work).
addInPlace
, subInPlace
, mulInPlace
, divInPlace
that perform the same
operations as the four above, but the result is placed into the left operand. Thus, if r1
contains
1/2
and r2
contains 1/4
, then calling r1.addInPlace(r2)
results in r1
containing 6/8
. In other words, add corresponds to +, while addInPlace corresponds to +=.
inverse
that returns the inverse (reciprocal) of the rational number.
negate
that returns the negation (additive inverse — the value multiplied by -1) of the rational number.
-1
) or simply copy the orignal Rational
and
manually negate the num
.
getNumerator
that returns the numerator of the rational number.
getDenominator
that returns the denominator of the rational number.
compareTo
that accepts another Rational
and returns -1, 0, or 1 depending on whether the receiver is
less-than, equal-to, or greater-than the argument (this is similar to the compareTo
method of the String
class.
While normal form makes it easy to test for equality, you might want to give some thought as to how to check for greater-/less-than.
equals
that accepts a Rational
argument and returns whether that argument and the receiver are
equal.
toString
method that returns the string representation of the Rational
, in the form
numerator
/denominator
. If the denominator is 1 — i.e., the number is an
integer, simply print the numerator.
gcd
method
this
in your overloaded constructors (the first three) to leverage the functionality of initializing the rational from a numerator and denominator.
gcd
, and reducing your Rational
in the constructor makes sure that all Rational
s you create are reduced from the get-go.
(The possible exception will be if you make in-place changes to a Rational
, in which case you have to make sure you reduce the result)
Rational
s will be in reduced normal from the moment they're created
num
and denomm
(as opposed to
leveraging the other immutable (non-in-place) operations and copying the result). In that situation, after manipulating the
num
and denomm
, you need to normalize the result (again calling gcd
and dividing). If your implementation does this, you may
want to write a normalize
method that does that for you.
normalize
method, regardless, simply for readability and clean code.
add
and addInPlace
) to maintain semantic consistency.
As will be discussed in class you can go in either direction — e.g., first code addInPlace
, and then use it to implement add
or vice-versa
(C++ uses the former approach; we briefly showed why in the lecture notes; we'll explain why again when we get to that point in C++). If you code add
first, you will need a
copy
method; if you code addInPlace
first, you need a copy constructor — we discussed this in the notes as well.
negate
and inverse
can benefit/contribute to
this leveraging as well.
compareTo
method when implementing equals
. This will prove good practice for
when you code this class in C++ and add all the relational operators (e.g. >
, !=
, etc).
RationalException
class to be used when an exception need to be thrown. I am simply checking the presence or absence
of an exception, so you do not have to worry about exact wording of the exception message.
RationalTest
class; this is the same class that will be used to test your class in CodeLab … we will go over it briefly in
class, and I would suggest you use it in your own IDE before submitting to CodeLab, but even before that, it would be a good idea
if you wrote a simple test class to check the basic functionality of your class. You will understand your own tests better than
mine, and it's good test-writing practice.