CS46A Lab

Implementing Classes

Copyright © Cay S. Horstmann 2009 Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.

See lab 1 for reporting instructions.

The steps tagged with this icon are optional. Do them if you have time and want to practice more.

Implementing Classes

A. Enhancing the BankAccount class

  1. Make a project account in BlueJ and a class BankAccount. Paste in the code from BankAccount.java. This is the class from Chapter 3 of your text book.
  2. Right-click on the class and construct an object with the BankAccount() constructor. Right-click on the object and invoke the deposit method, depositing $1000. What happens?
  3. How can you find out how much money is in the account?
  4. Now withdraw $2000. What happens? How much money is in the account?
  5. The National Bank of Java charges a $1 fee for every transaction that occurs in a given month. The fee is applied at the end of the month. Each deposit and withdrawal counts as a transaction. Mercifully, there is no charge for getting the balance.

    Your task is to enhance the BankAccount class so that the fee can be deducted by calling the void endOfMonth() method. Add the method (with a blank body) and a suitable comment to the BankAccount class. What did you add?

  6. Of course, you need to count the transactions. Add an instance variable and update it in the deposit and withdraw methods. What changes did you make?
  7. Now complete the endOfMonth method. To test it, add a class BankAccountTester with the following contents:
    /**
       A class to test the BankAccount class.
    */
    public class BankAccountTester
    {
       /**
          Tests the methods of the BankAccount class.
          @param args not used
       */
       public static void main(String[] args)
       {
          BankAccount harrysChecking = new BankAccount();
          harrysChecking.deposit(2000);
          harrysChecking.withdraw(500);
          System.out.println(harrysChecking.getBalance());
          System.out.println("Expected: 1500");      
          harrysChecking.endOfMonth();
          System.out.println(harrysChecking.getBalance());
          System.out.println("Expected: 1498");      
          harrysChecking.deposit(1000);
          harrysChecking.withdraw(500);
          harrysChecking.endOfMonth();
          System.out.println(harrysChecking.getBalance());
          System.out.println("Expected: 1996"); 
       }
    }

    To run the tester class, right-click and select main.

    What does your program print? If you didn't get the right output the first time, explain what error you made.

  8. The National Bank of Java, in its infinite generosity, also pays interest on the minimum balance during the month. For example, if the account started out at $1000, then dipped to $500, and then went to $2000, the interest is only paid on $500.

    Adding the interest does not count as a transaction with a fee. The interest is added before fees are deducted.

    Enhance the bank account class to simulate this behavior. First, add a parameter double interestRate to the endOfMonth method. Add a @param comment too. Add an instance variable minimumBalance to the class. Initialize it to the initialBalance in the BankAccount(double initialBalance) constructor. Update the minimumBalance variable in the withdraw method, like this:

    minimumBalance = Math.min(minimumBalance, balance);

    In the endOfMonth method, compute the interest as

    double interest = minimumBalance * interestRate / 100 / 12; 

    Here, we divide by 100 to compute the percentage, and by 12 to convert to a monthly rate. For example, if the annual interest rate is 6%, the monthly rate is 0.5% or 0.005. What is your endOfMonth method now?

  9. Now modify the tester class to check that your endOfMonth method is correct. What is the code of your tester class now?
  10. What output do you get when you run the tester class?
  11. Actually, banks rarely charge for every transaction. You usually have some number of free transactions. Modify the endOfMonth method to give 5 free transactions. Use Math.max(..., 0) to compute the fee. What is the code for your endOfMonth method?
  12. What is the code of your tester class?

B. A Car class

  1. Your task is to implement a Car class that simulates a car. When constructing a Car, you supply the fuel efficiency (miles per gallon). The class has methods for adding gas, checking the gas level, checking the odometer (i.e., total miles driven), and driving for a number of miles. Here is a typical tester program:
    /**
       This program tests the Car class.
    */
    public class CarTester
    { 
       public static void main(String [] args)
       { 
          Car myHybrid = new Car(50); // 50 miles per gallon       
          myHybrid.addGas(20); 
          myHybrid.drive(50); // consumes 1 gallon      
          myHybrid.drive(50); // and another gallon      
          myHybrid.addGas(10);
          double gasLeft = myHybrid.getGasInTank();       
          System.out.print("Gas left: ");
          System.out.println(gasLeft);
          System.out.println("Expected: 28");
          System.out.print("Miles driven: ");
          System.out.println(myHybrid.getMilesDriven());
          System.out.println("Expected: 100");
       } 
    }

    In BlueJ, make a project car and classes Car and CarTester. Start out with this Car class:

    /** 
        A car can drive and consume fuel. 
    */ 
    public class Car 
    { 
       /** 
          Constructs a car with a given fuel efficiency. 
          @param anEfficiency the fuel efficiency of the car 
       */ 
       public Car(double anEfficiency) 
       {
       }
    
       /** Adds gas to the tank. 
           @param amount the amount of fuel to add 
       */ 
       public void addGas(double amount) 
       { 
       } 
    
       /** 
           Drives a certain amount, consuming gas. 
           @param distance the distance driven 
       */ 
       public void drive(double distance) 
       { 
       } 
    
       /** 
           Gets the amount of gas left in the tank. 
           @return the amount of gas 
       */ 
       public double getGasInTank() 
       { 
          return 0;
       } 
    
       /** 
           Gets the total miles driven by this car. 
           @return the miles driven
       */ 
       public double getMilesDriven() 
       { 
          return 0;
       } 
    } 

    Now run the tester program. What output do you get? Why don't the actual values match the expected values?

  2. Let's first fix the total miles driven because that seems to be pretty similar to updating a bank account. Introduce an instance variable milesDriven and update it in the drive method. Also fix up the getMilesDriven method. What changes did you make?
  3. Now right-click on the Car class and make a new Car(50) object. Right-click on the object and call drive(50) twice. Call getMilesDriven. What answer did you get?
  4. Run the tester program again. Did the second test pass?
  5. You also need an instance variable for the gas in the car. Add the variable and update the addGas and gasInTank methods. Test your changes by making a Car object in BlueJ and invoking methods. What methods did you invoke? What result did you get?
  6. On to the gas consumption. You need to divide the distance by the efficiency to get the gallons consumed. For example, if you drive 100 miles and get 50 miles per gallon, you consume 100 / 50 = 2 gallons. So, in the drive method, you will want to compute
    double gasConsumed = distance / efficiency;

    What problem do you run into when you try this?

  7. Solve that problem by adding an instance variable. Where did you set it? Does it ever get modified afterwards?
  8. Now finish the drive method and test it by making a Car object in BlueJ and invoking methods. What methods did you invoke? What result did you get?
  9. Run the CarTester. What output did you get?

C. A Car with Alice and Netbeans

  1. It's no fun that we don't get to see the car. Let's do it in Alice. Download this Alice project. Start Netbeans (not Alice!). Select File -> New Project -> Java Project from Existing Alice Project -> Next -> Browse, then browse for the file you just downloaded. Click Finish. Select Run -> Run Main Project from the menu. What happens?
  2. In the Projects tab, open up at car -> Source Packages -> <default package> and double-click on MyCar. Alice generated this empty class for us to fill in instance variables and methods. Leave the imports and the line public class MyCar extends Car { unchanged. Remove the empty MyCar constructor. Copy all instance variables and methods from the Car class of the previous part inside, but rename the constructor MyCar (to match the name of the class). What happens when you try to run the program?
  3. Fix the error by changing
    private MyCar car1 = new MyCar();

    to

    private MyCar car1 = new MyCar(50);

    in MyScene.java. Now your program should compile and run.

  4. Of course, it doesn't do anything interesting yet. In the drive method of MyCar, add a call
    move(MoveDirection.FORWARD, distance / 100);

    This will make the car move. We divide by 100 so that the car doesn't leave the screen. In the run method of MyScene, add

    car1.addGas(20);
    car1.drive(50);
    car1.drive(50);

    Run the program. What happens?

  5. Now add this line of code:
    car1.say("Gas: " + car1.getGasInTank());

    Run the program again. What happens?

  6. Ok, that's nice. But it would be even nicer to have an actual gas gauge instead of a talking car. I couldn't find a gas gauge in Alice's collection of shapes, but hey, there is always the CatClock whose tail makes a splendid gauge.

    Add this import statement to MyScene:

    import org.alice.apis.moveandturn.gallery.objects.CatClock;

    Add this code to the run method in MyScene:

    CatClock clock = new CatClock();
    clock.resize(2);
    addComponent(clock);
    clock.turnToFace(camera);
    Model gauge = clock.getPart(CatClock.Part.ClockTail);

    As always, don't worry about the Alice magic. You will never be asked to memorize or create it. Now we want to move the gauge whenever the addGas or drive method is called. The easiest way is to pass the gauge as another parameter:

    car1.addGas(20, gauge);

    What happens when you try to compile?

  7. Of course that couldn't have worked. The addGas method in MyCar needs to be modified to take that parameter. Here it is:
    public void addGas(double amount, Model gauge)
    {
       gas = gas + amount;
       gauge.roll(RollDirection.RIGHT, (0.25 / 20) * amount );
    }

    Here, I figure the tank holds 20 gallons, and a full tank should roll the gauge by a quarter turn.

    Now compile and run. What happens?

  8. Almost there... We want to move the gauge to the left during driving. Add the gauge parameter to the drive calls. Add a Model gauge parameter to the drive method. Add this line to the method:

    gauge.roll(RollDirection.LEFT, (0.25 / 20) * gasConsumed);

    Compile and run. You'll see the gauge, erm, cat tail, moving to indicate the gas consumption.

  9. Isn't it grand? The only flaw is that the car moves first and then the gauge is adjusted. In Java, statements are executed in sequence. It is possible to make both movements together, but that goes well beyond what you'll learn in your first CS course. And it's pretty ugly in Java. (Other programming languages make it easier.) Don't peek if you are squeamish...

    Ok, you peeked. Here is the outline.

    DoTogether.invokeAndWait(
       new Runnable() 
       {
          public void run() 
          {
             move(MoveDirection.FORWARD, distance / 100);
          }
       },
       new Runnable() 
       {
          public void run() 
          {
             gauge.roll(RollDirection.LEFT, (0.25 / 20) * gasConsumed);
          }
       });

    You also need to declare the variables used inside the run methods as “final”:

    public void drive(final double distance, final Model gauge)
    {
       final double gasConsumed = distance / efficiency;
       ...
    }

    We won't explain this—you'll learn more about it in CS151.

    Try it out. Now the car and the gauge move together.