Second Summer 2002


An Older Set of Notes for Lab Ten: Classes and objects revisited. Solutions.
Here are the answers to all the problems.

The answers (or, rather, the hints) are in blue.

Warm-ups:

1. Consider the following 'nonsense class'.

class 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  
}
Identify the constructors, mutator functions, and accessor functions. What kind of variable is 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:

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   
}
Work through the program by hand. Do not actually compile and run the program. Then run it and compare the results.


3. Implement all the methods of the following class:

class 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. "
    );
  }  
}
Write a small test program that creates and works with objects of class 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

Supply two constructors: Supply a 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

Pass a value into a constructor to set an initial 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

of the type Account that was developed in the preceding exercise.

Implement four instance methods:

deposit(double amount, String account)

withdraw(double amount, String account)

transfer(double amount, String account) 

printBalances()
Here the account string is "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.

class Country {
  String name;
  long population;
  double area;
  Country(String name, long population, double area) {
    this.name = name; 
    this.population = population; 
    this.area = area; 
  }
}


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:

Write a simple tester program that creates a few triangles and asks them about their type.
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. For this problem what's listed below is just to get started.

This problem has several parts:

  1. Write a simple 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; 
    }
  2. Add a static field to your 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;
    }
  3. Write a 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. 
    
      } 
    }
  4. Add two constructors to 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); 
      }
    }
  5. Make the fields in your 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()); 
      }
    }
  6. Add a 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) {
        // ... 
      }
    }
  7. Add two 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) {
        // ... 
      }
    }
  8. Add a static method to 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) {
        // ... 
      }
    }
  9. Add a 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. I leave this out, as part of it was presented in the lecture. This problem used to have an extra-part (that I mention below).

For the ambitious:

Add a private method lcm to the class Fraction that takes two ints 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 very ambitious:

One could prove the following:

lcm(p, q) * gcd(p, q) = p * q
And the rest is easy.

If you have any questions please let us know.


Last updated: Jul 28, 2002 by Adrian German for A201