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 Rationals 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)
Rationals 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.