Warm-ups:
1. Consider the following 'nonsense class'.
Identify the constructors, mutator functions, and accessor functions. What kind of variable isclass A { public A() { n = 0; } // constructor public A(int a) { n = a; } // constructor public void f() { n++; } // mutates n public void g() { f(); n = 2 * n; f(); } // g mutates n directly and indirectly (f) public int h() { return n; } // accessor of n public void k() { System.out.println(n); } // does not return, only prints, the value of n private int n; // instance variable }
n
?
2. With the nonsense class from the preceding exercise, determine what the following program prints.
It prints 9
and 17
and here's why:
Work through the program by hand. Do not actually compile and run the program. Then run it and compare the results.public static void main(String[] args) { A a = new A(); // a.n is 0 A b = new A(2); // b.n is 2 A c = b; // c points where b points so c.n = b.n = 2 A d = new A(3); // d.n is 3 a.f(); // a.n is 1 b.g(); // b.n becomes 3, 6, then 7 c.f(); // c.n is b.n and it becomes 8 d.g(); // d.n becomes 4, 8, then 9 d.k(); // d.n is printed on a line by itself A e = new A(a.h() // a.n is 1 + b.h() // b.n is 8 and is equal to c.n + c.h() // which is 8 ); // so e.n is set to 1 + 8 + 8 = 17 e.k(); // e.n (17) is printed on a line by itself }
3. Implement all the methods of the following class:
Write a small test program that creates and works with objects of classclass Person { public Person() { name = "YetToBeNamed"; birthdayYear = 1999; // my default } public Person(String givenName, int yearOfBirth) { name = givenName; birthdayYear = yearOfBirth; } public String getName() { return name; } public String changeName(String name) { String aux; aux = this.name; this.name = name; return aux; } public int getAgeInYears(int currentYear) { return currentYear - birthdayYear; } private String name; private int birthdayYear; public static void main(String[] args) { Person a = new Person(); Person b = new Person("Richard P. Feynman", 1918); String name = a.changeName("The Next Richard Feynman"); System.out.println( "Physicist " + name + " makes big " + "discovery, touted as " + a.getName() ); System.out.println( b.getName() + " was " + b.getAgeInYears(1945) + " in 1945, in May. " ); } }
Person
as well.
As shown, the test program can be the very
main
method of the class we wrote.
Design exercises:
4. Implement a class Address
. An address has
print
function that prints the address with the street
on one line and the city, state, and postal code on the next line.
Supply a method compareTo
that tests whether one address
comes before another when the addresses are compared by postal code.
class Address { int houseNumber; String street; int apartmentNumber; String city; String state; String zipCode; // e.g., "47405-1234" Address(int houseNumber, String street, // no apartmentNumber String city, String state, String zipCode) { this.houseNumber = houseNumber; this.street = street; this.city = city; this.state = state; this.zipCode = zipCode; } Address(int houseNumber, String street, int apartmentNumber, String city, String state, String zipCode) { this(houseNumber, street, city, state, zipCode); this.apartmentNumber = apartmentNumber; } void print() { System.out.println("Street: " + street); System.out.println("City: " + city + "State: " + state + "Postal Code: " + zipCode); } int compareTo(Address a) { // same conventions as for Strings return this.zipCode.compareTo(a.zipCode); } }
5. Implement a class Account
. An account has
balance
,
add
withdraw
money,
inquire
the current balance.
If no value is passed the initial balance should be set to $0
.
Charge a $5
penalty if an attempt is made to withdraw more money
than available in the account.
Enhance the Account
class to compute interest
on the current balance.
class Account { double balance; double add(double sum) { balance += sum; return sum; } double withdraw(double sum) { if (sum > balance) { balance -= 5; return -5; // this will come in handy in Prob. 6 } else { balance -= sum; return balance; // Notice: always >= 0 (never < 0) } } double inquire() { return balance; } Account() { balance = 0; } Account(double sum) { balance = sum; } double interest (double rate) { return rate * balance; } }
6. Implement a class Bank
. This bank has two objects
checking
savings
Account
that was developed in the preceding
exercise. Implement four instance methods:
Here the account string isdeposit(double amount, String account) withdraw(double amount, String account) transfer(double amount, String account) printBalances()
"S"
or "C"
. For
the deposit or withdrawal, it indicates which account is affected. For
a transfer it indicates the account from which the money is taken; the
money is automatically transferred to the other account.
class Bank { Account checking; Account savings; void deposit(double amount, String account) { if (account.equals("C")) checking.add(amount); else // my default savings.add(amount); } void withdraw(double amount, String account) { if (account.equals("C")) checking.withdraw(amount); else // my default savings.withdraw(amount); } void transfer (double amount, String account) { if (account.equals("C")) if (checking.withdraw(amount) >= 0) savings.add(amount); else checking.add(5); // somewhat fault-tolerant else // default if (savings.withdraw(amount) >= 0) checking.add(amount); else savings.add(5); // no penalty for transfers } void printBalances() { System.out.println( "Checking: " + checking.inquire() + "\nSavings: " + savings.inquire() ); } }
7. Define a class Country
that stores the name of the
country, its population, and its area. Using that class, write a test
program that creates a few countries and stores them in an array and
then prints
main
as part of the very class
we are defining:
class Country { String name; long population; double area; Country(String name, long population, double area) { this.name = name; this.population = population; this.area = area; } double density () { if (area > 0) return population/area; else return 0; } public static void main(String[] args) { int numberOfCountries = 10; Country[] countries = new Country[numberOfCountries]; double lArea = -1; int lAreaIndex = -1; long lPop = -1; int lPopIndex = -1; double lDensity = -1; int lDensityIndex = -1; for (int i=0; i < countries.length; i++) { if (lArea < countries[i].area) { lArea = countries[i].area; lAreaIndex = i; } if (lPop < countries[i].population) { lPop = countries[i].population; lPopIndex = i; } if (lDensity < countries[i].density()) { lDensity = countries[i].density(); lDensityIndex = i; } } System.out.println( "Largest area: " + country[lAreaIndex] + "Largest population: " + country[lPopulationIndex] + "Largest density: " + country[lDensityIndex] ); } String toString() { // comes in handy in the println above return "\nCountry name: " + name + "\nPopulation: " + population + "\nArea: " + area + "\nDensity: " + density() } }
8. Write a class called Triangle
that can be used to
represent a triangle. It should include the following methods that
return boolean
values indicating if the particular
property holds:
isRight
(a right triangle)
isScalene
(no two sides are the same length)
isIsosceles
(exactly two sides are the same length)
isEquilateral
(all three sides are the same length)
class Triangle { int sideA, sideB, sideC; Triangle (int a, int b, int c) { // constructor sideA = a; sideB = b; sideC = c; } // negative numbers and zero lengths accepted // but see how isTriangle() used below boolean isTriangle () { int max = Math.max(Math.max(sideA, sideB), sideC); return sideA > 0 && sideB > 0 && sideC > 0 && (max < sideA + sideB + sideC - max); } boolean isRight() { int max = Math.max(Math.max(sideA, sideB), sideC); return isTriangle() && (max * max) == (sideA * sideA) + (sideB * sideB) + (sideC * sideC) - (max * max); } boolean isScalene() { return isTriangle() && ! isIsosceles(); // we get some peer help } boolean isIsosceles() { return isTriangle() && (sideA == sideB || sideA == sideC || sideB == sideC); } boolean isEquilateral() { return isTriangle() && (sideA == sideB && sideA == sideC); } public static void main(String[] args) { Triangle a, b, c; a = new Triangle( 3, 4, 5); b = new Triangle( 0, 0, -1); c = new Triangle( 6, 6, 6); System.out.println( a + " isosceles? Answer: " + a.isIsosceles() ); System.out.println( a + " right? Answer: " + a.isRight() ); System.out.println( c + " isosceles? Answer: " + c.isIsosceles() ); System.out.println( c + " scalene? Answer: " + c.isScalene() ); } String toString() { System.out.println( "Triangle: (" + sideA + ", " + sideB + ", " + sideC + ") "; ); } }
9. This problem has several parts:
Vehicle
class that has fields for
(at least) current speed, current direction in degrees, and owner
name.
class Vehicle { int currentSpeed; int currentDirection; String owner; }
Vehicle
class for the
highest Vehicle Identification Number issued, and a non-static
field that holds each vehicle's ID number.
class Vehicle { int currentSpeed; int currentDirection; String owner; static int highestVIN; int VIN; }
main
method for your Vehicle class that
creates a few vehicles and prints out their field values. Note that
you can also write a separate tester program as well.
class Vehicle { int currentSpeed; int currentDirection; String owner; static int highestVIN; int VIN; public static void main(String[] args) { Vehicle a = new Vehicle(); a.VIN = highestVIN++; a.owner = "Larry Bird"; Vehicle b = new Vehicle(); b.VIN = highestVIN++; b.owner = "Mark Jackson"; System.out.println("VIN: " + a.VIN + " belongs to " + a.owner); System.out.println("VIN: " + b.VIN + " belongs to " + b.owner); // Note that both cars are stopped, and facing East. } }
Vehicle
. A no-arg constructor
and one that takes an initial owner's name. Modify the tester program from
the previous step and test your design.
class Vehicle { int currentSpeed; int currentDirection; String owner; static int highestVIN; int VIN; Vehicle() { VIN = highestVIN++; } Vehicle (String owner) { this(); this.owner = owner; } public static void main(String[] args) { Vehicle a = new Vehicle("Larry Bird"); Vehicle b = new Vehicle("Mark Jackson"); System.out.println("VIN: " + a.VIN + " belongs to " + a.owner); System.out.println("VIN: " + b.VIN + " belongs to " + b.owner); } }
Vehicle
class private
,
and add accessor methods for the fields. Which fields should have methods to
change them and which should not?
class Vehicle { private int currentSpeed; int getSpeed() { return currentSpeed; } void changeSpeed(int newSpeed) { currentSpeed = newSpeed; } private int currentDirection; int getCurrentDirection() { return currentDirection; } void setDirection(int newDirection) { currentDirection = newDirection % 360; } private String owner; int getOwner() { return owner; } void setOwner(String newOwner) { owner = newOwner; } private static int highestVIN; private int VIN; int getVIN() { return VIN; } Vehicle() { VIN = highestVIN++; } Vehicle (String owner) { this(); this.owner = owner; } public static void main(String[] args) { Vehicle a = new Vehicle("Larry Bird"); Vehicle b = new Vehicle("Mark Jackson"); System.out.println("VIN: " + a.getVIN() + " belongs to " + a.getOwner()); System.out.println("VIN: " + b.getVIN() + " belongs to " + b.getOwner()); } }
changeSpeed
method that changes the current speed
of the vehicle to a passed-in value, and a stop
method that
sets the speed to zero.
class Vehicle { private int currentSpeed; int getSpeed() { return currentSpeed; } void changeSpeed(int newSpeed) { currentSpeed = newSpeed; } void stop() { currentSpeed = 0; } private int currentDirection; int getCurrentDirection() { return currentDirection; } void setDirection(int newDirection) { currentDirection = newDirection % 360; } private String owner; int getOwner() { return owner; } void setOwner(String newOwner) { owner = newOwner; } private static int highestVIN; private int VIN; Vehicle() { VIN = highestVIN++; } Vehicle (String owner) { this(); this.owner = owner; } public static void main(String[] args) { // ... } }
turn
methods to Vehicle
. One that
takes a number of degrees to turn, and one that takes simply either a
Vehicle.TURN_LEFT
or a Vehicle.TURN_RIGHT
constant. Define the two constants accordingly.
class Vehicle { private int currentSpeed; int getSpeed() { return currentSpeed; } void changeSpeed(int newSpeed) { currentSpeed = newSpeed; } void stop() { currentSpeed = 0; } private int currentDirection; int getCurrentDirection() { return currentDirection; } void setDirection(int newDirection) { currentDirection = newDirection % 360; } static final String TURN_LEFT = "Turn left"; static final String TURN_LEFT = "Turn left"; void turn(int degrees) { currentDirection = (currentDirection + degrees) % 360; } void turn(String direction) { if (direction.equals(left)) { currentDirection = (currentDirection + 90) % 360; } else { //default currentDirection = (currentDirection - 90) % 360; } } private String owner; int getOwner() { return owner; } void setOwner(String newOwner) { owner = newOwner; } private static int highestVIN; private int VIN; Vehicle() { VIN = highestVIN++; } Vehicle (String owner) { this(); this.owner = owner; } public static void main(String[] args) { // ... } }
Vehicle
that returns the highest
identification number used so far.
class Vehicle { private int currentSpeed; int getSpeed() { return currentSpeed; } void changeSpeed(int newSpeed) { currentSpeed = newSpeed; } void stop() { currentSpeed = 0; } private int currentDirection; int getCurrentDirection() { return currentDirection; } void setDirection(int newDirection) { currentDirection = newDirection % 360; } static final String TURN_LEFT = "Turn left"; static final String TURN_LEFT = "Turn left"; void turn(int degrees) { currentDirection = (currentDirection + degrees) % 360; } void turn(String direction) { if (direction.equals(left)) { currentDirection = (currentDirection + 90) % 360; } else { currentDirection = (currentDirection - 90) % 360; } } private String owner; int getOwner() { return owner; } void setOwner(String newOwner) { owner = newOwner; } private static int highestVIN; static int highestVIN() { return highestVIN; } private int VIN; Vehicle() { VIN = highestVIN++; } Vehicle (String owner) { this(); this.owner = owner; } public static void main(String[] args) { // ... } }
toString
method to Vehicle
.
class Vehicle { String toString() { return "The radar reports: VIN " + VIN + " owned by " + owner + " heading " + currentDirection + " (degrees) " + " at a speed of " + speed); } private int currentSpeed; int getSpeed() { return currentSpeed; } void changeSpeed(int newSpeed) { currentSpeed = newSpeed; } void stop() { currentSpeed = 0; } private int currentDirection; int getCurrentDirection() { return currentDirection; } void setDirection(int newDirection) { currentDirection = newDirection % 360; } static final String TURN_LEFT = "Turn left"; static final String TURN_LEFT = "Turn left"; void turn(int degrees) { currentDirection = (currentDirection + degrees) % 360; } void turn(String direction) { if (direction.equals(left)) { currentDirection = (currentDirection + 90) % 360; } else { currentDirection = (currentDirection - 90) % 360; } } private String owner; int getOwner() { return owner; } void setOwner(String newOwner) { owner = newOwner; } private static int highestVIN; static int highestVIN() { return highestVIN; } private int VIN; Vehicle() { VIN = highestVIN++; } Vehicle (String owner) { this(); this.owner = owner; } public static void main(String[] args) { // ... } }
10. Define a class of Fractions
Consider ordinary fractions like 3/4 and
-1/2. A fraction is the ratio of two integers:
a numerator and a denominator. Create a user-defined type for fractions
by defining a class Fraction
. The class should supply a set
of necessary operations on fractions
Remember that a class encapsulates data structures with access and manipulation procedures. In designing a class, an important task is to decide on the internal data representation which is isolated from the outside view. Member methods will keep the data representation consistent. Outside methods are not allowed to create or modify the internal structures directly. They may do this by calling methods in the class.
Here are some (internal) representation considerations to guide your design:
numerator
and denominator
.
Fraction
class can be designed to enforce such conventions,
not just to have them as principles that one can choose to follow or ignore.
This is one big advantage of object-oriented programming. The canonical
representation conventions should be enforced by the Fraction
constructor.
The constructor should take the two arguments n
and
d
and construct a fraction n/d
out of it. The denominator of the resulting Fraction
should not
be zero or negative. The fraction should be reduced by removing the
gcd
(greatest common divisor) between the numerator and
the denominator. You should define a member method gcd
that computes the gratest common divisor of two numbers and make the
constructor use it to create canonical Fraction
s.
gcd
should be implemented as a classwide method since
it is independent of Fraction
instances. It should be
declared private
because it does not contribute to the
public interface of the Fraction
class.
gcd
is described in your text on page 149.
The operations for fractions listed above should implement binary operations.
In other words we are going to define methods such that a Fraction
can be added to, subtracted from, multiplied with, or divided by another
Fraction
. The result should be a Fraction
.
You should also define a few predicates.
Each Fraction
that you create should be able to respond to the
following questions:
isZero()
isInt()
equals(anotherFraction)
greaterThan(anotherFraction)
toString
method to Fraction
(an instance method) that returns a String
representation of a Fraction
. It must be an instance method as it is
Testing your Fraction
s:
// TestFrac.java class TestFrac { public static void main(String[] args) { Fraction x = new Fraction( 1, 20); Fraction u = new Fraction(-1, 60); Fraction v = new Fraction( 1, 30); Fraction y; y = x.plus(u).minus(v); // in one step! System.out.println( x + " + " + u + " - " + v + " = " + y); } }
For the ambitious:
Add a private method lcm
to the class Fraction
that takes two int
s and returns their least common multiple.
(For example, lcm(15, 12)
is 60
. Hint: use
gcd
). Modify minus
and plus
in
Fraction
to use lcm
.
The part for the ambitious will be posted here.// File: Fraction.java public class Fraction { private int num; // numerator private int denom; // denominator public Fraction(int n, int d) { int g; if (d == 0) { System.out.println("Fraction: fraction " + "with 0 denominator?"); System.exit(1); } if (n == 0) { num = 0; denom = 1; } else { if (d < 0) { n = -n; d = -d; } if ((g = gcd(n, d)) != 1) { // remove gcd n /= g; d /= g; } num = n; denom = d; } } private static int gcd(int a, int b) { a = Math.abs(a); b = Math.abs(b); if (a == 0) return b; // 0 is error value if (b == 0) return a; int t; while (b > 0) { t = a % b; // take "-" to the extreme a = b; b = t; } return a; } public boolean isZero() { return (denom == 1 && num == 0); } public boolean isInt() { return (denom == 1); } public boolean equals(Fraction y) { return (num == y.num && denom == y.denom); } public boolean greaterThan(Fraction y) { return (num * y.denom > denom * y.num); } public Fraction minus(Fraction y) { return new Fraction( num * y.denom - y.num * denom, denom * y.denom ); } public Fraction plus(Fraction y) { return new Fraction( num * y.denom + y.num * denom, denom * y.denom ); } public Fraction times(Fraction y) { return new Fraction(num * y.num, denom * y.denom); } public Fraction dividedBy(Fraction y) { return new Fraction(num * y.denom, denom * y.num); } }
If you have any questions please let us know.