University of Washington, CSE 142

Lab 8: Classes and Objects

Except where otherwise noted, the contents of this document are Copyright 2013 Stuart Reges and Marty Stepp.

lab document created by Marty Stepp, Stuart Reges and Whitaker Brand

Basic lab instructions

Today's lab

Goals for today:

Declaring a class (syntax)

public class ClassName {
    // fields
    fieldType fieldName;

    // methods
    public returnType methodName() {
        statements;
    }
}
A couple things look different than programs for past homeworks:

Exercise : Client code method call syntax practice-it

Suppose you have the following BankAccount class (on the left) and client code (on the right):

public class BankAccount {
   public BankAccount() {...}
   public double computeInterest(int rate) {...}
}
public class BankAccountClient {
   public static void main(String[] args) {
      BankAccount acct = new BankAccount();
      // your code goes here
   }
}
What would be a valid call to computeInterest given the following client code, and a desired rate of 42?

Exercise : PointCoordinates practice-it

What are the x- and y-coordinates of the Points (iconPoint.java) p1, p2, and p3 after all of the following code executes? Give your answer as an x-y pair such as (0, 0). (Recall that Point use reference semantics).

public class PointClient {
   public static void main(String[] args) {
      Point p1 = new Point();
      // changes the value of the x field of p1
      p1.x = 17;
      p1.y = 9;
      Point p2 = new Point();
      p2.x = 4;
      p2.y = -1;
      Point p3 = p2;

      p1.translate(3, 1);
      p2.x = 50;
      p3.translate(-4, 5);
   }
}
[^0-9,]+
p1:
(20, 10)
p2:
[^0-9,]+
(46, 4)
p3:
[^0-9,]+
(46, 4)

Exercise : Point class errors

Can you find all the errors in the following code?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class Point {
    int x;                                       // Each Point object has
    int y;                                       // an int x and y inside.

    public void Point(int initX, int initY) {    // Constructor
        initX = x;
        initY = y;
    }

    public static double distanceFromOrigin() {  // Returns this point's
        int x;                                   // distance from (0, 0).
        int y;
        double dist = Math.sqrt(x*x + y*y);
        return dist;
    }

    public void translate(int dx, int dy) {      // Shifts this point's x/y
        int x = x + dx;                          // by the given amounts.
        int y = y + dy;
    }
}

Exercise - solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Point {
    private int x;                               // Each Point object has
    private int y;                               // an int x and y inside.
    // a constructor does not have a return type
    public void Point(int initX, int initY) {    // Constructor
        // we want to be changing the values of the fields!
        x = initX;
        y = initY;
    }
   
    public static double distanceFromOrigin() {  // Returns this point's
        int x;                                   // distance from (0, 0).
        int y;
        double dist = Math.sqrt(x*x + y*y);
        return dist;
    }

    public void translate(int dx, int dy) {
	// we want to change the values of fields, not create new local variables
        int x = x + dx;
        int y = y + dy;
    }
}

Exercise : Printing objects practice-it

Point p1 = new Point();
...
System.out.println(p1);

The above println statement (the entire line) is equivalent to what?

Exercise : PointClient practice-it

Point and PointMain

Exercise : quadrant practice-it

Add the following method to the Point class:

public int quadrant()

Returns which quadrant of the x/y plane this Point object falls in. Quadrant 1 contains all points whose x and y values are both positive. Quadrant 2 contains all points with negative x but positive y. Quadrant 3 contains all points with negative x and y values. Quadrant 4 contains all points with positive x but negative y. If the point lies directly on the x and/or y axis, return 0.

(Test your code in Practice-It! or by running the PointMain program.)

Exercise : flip practice-it

Add the following method to the Point class:

public void flip()

Negates and swaps the x/y coordinates of the Point object. For example, if an object pt initially represents the point (5, -3), after a call of pt.flip(); , the object should represent (3, -5). If the same object initially represents the point (4, 17), after a call to pt.flip();, the object should represent (-17, -4).

Test your code in Practice-It! or by running the PointMain program.

Exercise : Point toString practice-it

Modify the toString method in the Point class. Make it return a string in the following format. For example, if a Point object stored in a variable pt represents the point (5, -17), return the string:

Point[x=5,y=-17]

If the client code were to call System.out.println(pt); , that text would be shown on the console. Note that this format is slightly different in the Practice-it problem.

(Test your code in Practice-It, or by running your PointClient or PointMain and printing a Point there.)

Exercise : Critters Setup

To work on the critters assignment, you must first download the classes that are used by the simulator. To begin:

Exercise : LabTA Version 1

Exercise : LabTA Version 2

As we just saw, a default LabTA is black, represented by a ?, and doesn't move over time. This is because LabTA inherits from Critter, and Critter.java tells us that we, by default:

   // make my color black in Critter world
   public Color getColor() {
      return Color.BLACK;
   }

   // don't move when getMove() is called
   public Direction getMove() {
      return Direction.CENTER;
   }

   // represent me as a ? in Critter world
   public String toString() {
      return "?";
   }

Exercise : LabTA Version 2

To change our look/behavior, we need to override the default methods of our LabTA class.

Exercise : LabTA Version 2

Exercise : LabTA Version 4

Our LabTA critters currently have very simple behaviors that don't change. They are always magenta, displayed as :-), moving NORTH, attacking using POUNCE, and eating when finding food.

Now we're going to alter the LabTA to change over time. Specifically, we want to alternate colors between magenta and white, switching every time the LabTA moves (getMove() is called), with the initial color (before any moves are made) being magenta.

Developing this kind of behavior is a central part of the critters homework, so reasoning through how to implement this behavior is really important. Think about what kind of information you need to change behavior over time, and recall from the last lab how to encode information into an Object.

Hint: Remember that in defining critters, you get to decide what fields to introduce!

Another hint: Think about what kind of field is suitable. What type of variable captures that we'll either want to be magenta or white?

Exercise : LabTA Version 4

To allow your LabTA critters to change colors on alternate moves, they need to keep track of where they are in the cycle. For example, you could introduce a boolean field that keeps track of whether a LabTA should be displaying itself as magenta or as white. You can then switch the boolean value each time the LabTA makes a move.

  • Add a field to your class called isWhite to keep track of whether the LabTA should be white, or not (in which case it should be magenta). Remember that fields should be declared to be private. Also recall that the default value of a boolean is false.
  • Modify the getMove method to flip this boolean value each time getMove() is called.
    Important: Can the boolean switch be flipped in a different method? Why/why not?
  • Rewrite the getColor method using the isWhite boolean to change colors as expected.
  • Test your new version by recompiling the LabTA class and running CritterMain.

Expression : Solution

import java.awt.*;
public class LabTA extends Critter {
    
    // default value = false
    private boolean isWhite;
    
    public Direction getMove() {
        isWhite = !isWhite;
        return Direction.NORTH;
    }
    
    public Color getColor() {
        if (isWhite) {
            return Color.WHITE;
        } else {
            return Color.MAGENTA;
        }
    }
    
    // methods implemented earlier ommitted
}

Exercise : Important: another solution

import java.awt.*;
public class LabTA extends Critter {
    
    // default value = 0
    private int moves;
    
    public Direction getMove() {
        moves++;
        return Direction.NORTH;
    }
    
    public Color getColor() {
        if (moves % 2 == 1) {
            return Color.WHITE;
        } else {
            return Color.MAGENTA;
        }
    }
    
    // methods implemented earlier ommitted
}


There are many ways of storing information about the state of the Critter. On the last slide, we used a boolean (isWhite). When there are only two possible outcomes, booleans are better style.


Some tasks will require knowing more information about the Critter's history/state. Using an integer to solve this problem is not the best style. However, you might run into other Critters who will need something like an integer move counter to remember how many moves its made.

Exercise : LabTA Version 4

Now we're going to work on the moves that the LabTA critters make.

  • Open the FlyTrap class to see how it is written. Notice its getMove method:
        public Action getMove(CritterInfo info) {
            if (info.getFront() == Neighbor.OTHER) {
                return Action.INFECT;
            } else {
                return Action.LEFT;
            }
        }
    
  • Copy and paste this code to replace the current version of getMove in the LabTA class. Then modify it so that it always infects when it can and otherwise it hops if it can and otherwise it turns left. This involves adding a new branch in the if/else. Remember that the constant Neighbor.EMPTY can be used to see if a position is empty and that you move forward with the Action.HOP move.
  • Test your new version by running CritterMain and observing the LabTA critters.

Exercise : LabTA Version 5

Now we're going to include a bit of randomness. The current version of the LabTA class always moves NORTH. We are going to change it so that it instead randomly chooses between going EAST and WEST.

To solve this problem, we will need access to a Random object. We don't want to construct one every time we call getMove, so we will instead store it as a field. Remember to import java.util.*; to use Random.

  • Declare a field called rand of type Random. Do not initialize the field where it is declared.
  • Constructors exist to set the initial state of our Objects (initializing fields!) So far, we've been using an implicit constructor that takes no parameters and does nothing when it constructs LabTAs. Now add a constructor that takes no parameters, and in the constructor, initialize the Random object.
  • Modify the getMove method so that it uses the Random object to randomly pick between going WEST and going EAST.
  • Test your new version by recompiling LabTA, and running CritterMain again.

Exercise : Solution

import java.awt.*;
import java.util.*;
public class LabTA extends Critter {

    private boolean isWhite; 
    private Random rand;
    
    public LabTA() {
        rand = new Random();
        isWhite = false;      // this line is not necessary, boolean default value is false
    }
    
    public Direction getMove() {
        isWhite = !isWhite;
        boolean goEast = rand.nextBoolean();
        if (goEast) {
            return Direction.EAST;
        } else {
            return Direction.WEST;
        }
    }    
    // methods implemented earlier ommitted
}

BankAccount class

  • The next exercise refers to the following icon BankAccount class (download it and open it in jGRASP).
// Each BankAccount object represents one user's account
// information including name and balance of money.

public class BankAccount {
    String name;
    double balance;

    public void deposit(double amount) {
        balance = balance + amount;
    }

    public void withdraw(double amount) {
        balance = balance - amount;
    }
}

Exercise : BankAccount transactionFee practice-it

  • Add a double field to the BankAccount class named transactionFee that represents an amount of money to deduct every time the user withdraws money. The default value is $0.00, but the client can change the value. Deduct the transaction fee money during every withdraw call (but not from deposits).
  • Make sure that the balance cannot go negative during a withdrawal. If the withdrawal (amount plus transaction fee) would cause it to become negative, don't modify the balance value at all.
  • Test your solution to this problem in Practice-It.

Exercise : BankAccount toString practice-it

Add a toString method to the BankAccount class. Your method should return a string that contains the account's name and balance separated by a comma and space. For example, if an account object named benben has the name "Benson" and a balance of 17.25, benben.toString() should return:

Benson, $17.25

If the client code were to call System.out.println(benben); , that text would be shown on the console.

(Test your code by writing a short client program that constructs and initializes an account, then prints it.)

Exercise : manhattanDistance practice-it

Add the following method to the Point class:

public int manhattanDistance(Point other)

Returns the "Manhattan distance" between the current Point object and the given other Point object. The Manhattan distance refers to how far apart two places are if the person can only travel straight horizontally or vertically, as though driving on the streets of Manhattan. In our case, the Manhattan distance is the sum of the absolute values of the differences in their coordinates; in other words, the difference in x plus the difference in y between the points.

Click on the check-mark above to try out your solution in Practice-it! (Write just the new method, not the entire Point class.)

Exercise : TimeSpan practice-it

Define a class named TimeSpan. A TimeSpan object stores a span of time in hours and minutes (for example, the time span between 8:00am and 10:30am is 2 hours, 30 minutes). The minutes should always be reported as being in the range of 0 to 59. That means that you may have to "carry" 60 minutes into a full hour.

Exercise : Circle practice-it

Define a class named Circle. A Circle object stores a center point and a radius.

See the Practice-It link above for a full description of the class and the methods/constructors it should have. You can also test your class in Practice-It.

Exercise : jGRASP Debugger

The debugger can help you learn how classes and objects work. In this exercise we will debug the Ch. 8 "Stock" Case Study example. This program tracks purchases of two stock investments. To download the example:

  1. Go to this link that contains code files from Chapter 8 of the textbook: http://www.buildingjavaprograms.com/code_files/4ed/ch08/
  2. Download and save the files Stock.java and StockMain.java. Right-click each file name and Save the Link in the same folder you use for lab work.
  3. Compile and run StockMain.java in jGRASP to see that it works.

continued on the next slide...

Exercise - jGRASP Debugger

  • Set a stop icon on the System.out.print on line 53, and debug the program. icon
  • Type the user input to recreate the following partial log:
    First stock's symbol: AMZN
    How many purchases did you make? 2
    1: How many shares, at what price per share? 50 35.06
    2: How many shares, at what price per share? 25 38.52
    
  • At this point, what are the values of the fields in the currentStock object?
    (Ask a TA if you need help.)
    totalShares
    75
    totalCost
    2716.0

continued on the next slide...

Exercise - jGRASP Debugger

  • Now let's debug inside one of the Stock object's methods. Your program should still be stopped. Set a new stop at the return on line 29 of Stock.java.
  • Resume your program icon . It will prompt for today's price per share. Enter 37.29 . If you did it properly, the program should now call getProfit on the Stock and hit your stop point.
    What is today's price per share? 37.29
    
  • What are the values of the object (this) 's fields, and the variable marketValue ?
    symbol
    "AMZN"
    totalShares
    75
    totalCost
    2716.0

    marketValue
    2796.75

continued on the next slide...

Exercise - jGRASP Debugger

  • Now let's watch the total shares and cost of a stock change with each purchase. This part can be tricky, so feel free to ask a TA if you want an overview of the different debugger buttons. Remove your existing stop points and set a new stop icon somewhere in the for loop on lines 42-50 of StockMain, and Resume icon .
  • Type the user input to continue recreating the following partial log:
    Second stock's symbol: INTC
    How many purchases did you make? 3
    1: How many shares, at what price per share? 15 16.55
    2: How many shares, at what price per share? 10 18.09
    3: How many shares, at what price per share? 20 17.05
    What is today's price per share? 17.82
    
  • After each call of purchase, what are the field values of currentStock?
    field after 1st purchase after 2nd after 3rd
    totalShares 15 25 45
    totalCost 248.25 429.15 770.15

If you finish them all...

If you finish all the exercises, try out our Practice-It web tool. It lets you solve Java problems from our Building Java Programs textbook.

You can view an exercise, type a solution, and submit it to see if you have solved it correctly.

Choose some problems from the book and try to solve them!