CSE131 Module 4: Encapsulation


By the end of this lab, you should...

Practice Problems

Expect exercises like these on the quiz. There will be a help session covering these exercises on Wednesday at 10:00am in the Steinberg 105 lecture hall. You will benefit most by doing the exercises before you look at the solutions or attend the Wednesday help session when they will be discussed.

Directions: Consider the following class definition and then answer the questions below. (We recommend doing these practice exercises on paper. Do not bother typing them into a computer. You'll learn more doing them by hand.)

public class Account {
   private int balance;

   public Account(int openingBalance) {
      balance = openingBalance;

   public void deposit(int dollars) {
      balance = balance + dollars;

   public boolean withdraw(int dollars) {
      if (dollars <= balance) {
         balance = balance - dollars;
         return true;
      } else
         return false;

   public boolean transfer (int dollars, Account destination) {
      if (withdraw(dollars)) {
         return true;
      } else
         return false;

   public String toString() {
      return ("$" + balance + ".00");

  1. What output would be printed as the result of executing the following code?
    Account alice, bob;                             // line 1
    alice = new Account(100);                       // line 2
    alice.deposit(25);                              // line 3
    System.out.println("Alice has " + alice);
    bob = new Account(100);                         // line 5
    System.out.println("Bob can withdraw $125.00? " + bob.withdraw(125));
    System.out.println("Bob can withdraw $25.00? " + bob.withdraw(25));
    System.out.println("Bob has " + bob);
    Account charlie = alice;                        // line 9
    System.out.println("Charlie can withdraw $25.00? " + charlie.withdraw(25));
    System.out.println("Charlie has " + charlie);
    System.out.println("Alice has " + alice);
    alice.transfer(50, charlie);
    System.out.println("After transfer...");
    System.out.println("Charlie has " + charlie);
    System.out.println("Alice has " + alice);

  2. During the execution of the code in Problem 1, how many Account reference variables have been (cumulatively) declared after completing execution of lines 1, 2, 3, 5, and 9? (That is, hand simulate the code, and at each numbered line, say how many Account reference variables have been declared up to that point.)

  3. During the execution of the code in Problem 1, how many Account objects have been instantiated after completing execution of lines 1, 2, 3, 5, and 9?

  4. What would be printed as the result of executing the following code? Explain.
    System.out.println("This account has " + (new Account(60)));

  5. In Problem 4, what happens to the Account object created? If we added some code right after that line, would that code be able to use the Account object that was created?

  6. What's wrong with the following?
    Account foo;            // line 1
    foo.withdraw(25);       // line 2
    Suggest a line that could be added between lines 1 and 2 in order to avoid the error on line 2. (Alternatively, suggest a modification to line 1 that would avoid the problem.)


Download lab4.zip and import it into your CSE131 project in Eclipse.

Also read the CSE131 Style Guide. A substantial part of your grade on this and future labs in CSE131 will be based on style, which includes clear code and documentation. Good syle is important because clarity helps avoid program errors and following standard conventions makes it easier for you and others to understand and modify your code. Expectations are described in the style guide.

Project: Creating and testing a Vector class and a Point class

In Part I, you will define a Java class that models a mathematical vector. Part II involves writing methods to test your Vector class. In Part III you will create a related Point class.

You are encouraged to work on Parts I and II simultaneously, using test-driven development. Thorough testing is important, because you will use your Vector and Point classes in later assignments, as part of some new image manipulation and graphics tools, so you want to be sure that they work correctly.

Part I. Implementing a Vector class:

A vector is a mathematical description of a direction and a magnitude. Another way to think about a vector is a location relative to some point of origin. If you think about them this way, you can see how vectors can be added, as shown below.

  1. Open the file Vector.java in the provided lab4 package, and fill in your name and other information at the top. A class named Vector has been defined in the file, but so far it contains no instance variables or methods. (Notice that the class name exactly matches the file name, including capitalization. Java requires this.)
  2. Instance variables: The instance variables of a class define what kind of information each object of that class will hold. If we think of a vector as a translation in two-dimensional space, then we can represent a vector as the change in x and the change in y. In other words, we want each Vector object to contain two distances, deltaX and deltaY. To accomplish this, declare two instance variables in the Vector class, and name them deltaX and deltaY. Both should be of type double.

    Naming conventions: By convention, names of instance variables and methods should begin with lower case letters, to distinguish them from class names, which begin with upper case letters. If a variable has multi-word name, we usually capitalize subsequent words. For example, thisIsAVeryLongVariableName.

    Encapsulation: Objects usually contain data, and it is good design practice to make sure that this data can't be "messed with" by other classes. Other classes should call methods on the object to access the information. That way, each class can control what is seen and, more importantly, how it is modified. Make both of the instance variables in your Vector class private by typing the keyword "private" at the beginning of the declaration, before the type of variable. When you make the variable privates, Java will make sure that the only way that code in other classes can see or modify their values is by calling methods of the Vector class.

  3. Initialization: Assigning to a variable for the first time is called "initializing" the variable. Constructurs usually have the job of initializing instance variables. When we create Vector objects, we will probably want to supply the deltaX and deltaY values for them. So, define a public constructor that takes two double parameters and assigns their values to deltaX and deltaY. Recall that a constructor always has the same name as the class.

    Tip: You can type the constructor yourself if you want, but Eclipse provides some tools for generating these kinds of constructors automatically. To create the constructor automatically, first position your text cursor on the class name at the beginning of the file. Then open the Source menu and select "Generate constructor using fields." Finally, select the boxes for deltaX and deltaY so that the constructor will have parameters that are used to initialize those instance variables.

    Name masking: A method or constructor may have a parameter whose name is the same as the name of an instance variable. For example, you might have a parameter and instance variable both with the name "deltaX." When a name is used in a program, it refers to the "closest" declaration. So any use of the name "deltaX" would refer to the parameter. In this case, we say that the parameter masks the instance variable. But inside the method or constructor, we may still want to use or change the value of the instance variable. Within a method, the keyword this always refers to the object on which the method has been invoked (i.e., "this" object). When an instance variable is masked, you can still refer to it by preceding its name with "this." For example, inside the method, this.deltaX = deltaX will assign the value of the parameter deltaX to the instance variable named deltaX inside "this" object.

  4. Implicit targets: Normally, when you call a method on a target object, you identify the target, and then identify the method and its actual parameters. For example,
    calls the deposit method on the object to which alice refers. In other words, alice is the target. If you don't identify a target, then it is assumed that the target is the same object that is currently executing a method. For example, if we call the deposit method on alice and inside of the deposit method there is an expression getBalance(), then it is understood that the method will be called on alice since that is the object in which the deposit method is executing. In such cases, it is not necessary (and considered bad style) to use the word "this" because it is already understood that this object is the target.

  5. The toString method: It is customary to provide a method called toString that takes no parameters and returns a String value that is a textual description of the object. You can call this method yourself, but Java will also call it whenever it needs to concatenate the object onto a String. Define a toString method for the Vector class that returns a textual description of the vector. For example, (new Vector(4,3)).toString() might have the value "[4 3]" as its return value. (Hint: Form this string by concatenating various characters with the deltaX and deltaY values.)

  6. Accessors: Most classes provide accessor methods that other parts of a program can call to get information from an object. For the Vector class, define two accessor methods named getDeltaX and getDeltaY that take no parameters and return the values of the instance variables deltaX and deltaY, respectively. Note: Here, the instance variables will not be masked by matching parameter names (in fact, there are no parameters at all), so there is no need to use "this." You can refer to the instance variables by their names alone. (Tip: You can type the methods yourself, or you can open the Eclipse Source menu and select "Generate Getters and Setters." Check the boxes for "getDeltaX" and "getDeltaY." Study the methods after creating them.)
  7. Accessors that compute their return value: Sometimes accessors provide information that is not directly stored inside the object, but is instead computed when the method is called. For example, write a method called magnitude that takes no parameters and returns a double, the length of the vector. Use the pythagorean theorem to compute the length of the vector. Recall that the method Math.sqrt(x) returns the square root of x.
  8. Mutators and immutable objects: Often, a class will provide mutator methods, such as setDeltaX, that allow controlled modification of the data stored in the corresponding instance variables. However, we will not provide mutators for the Vector class. Instead, each of our Vector objects will be immutable, meaning that once it is created, its value will never change. So, whenever we want a Vector with a different direction or magnitude, we will have to create a new object.

    Since Vector objects will be immutable, the rest of these methods will create new vectors as their return values. They'll do this by first computing the desired deltaX and deltaY values, and then using the Java keyword new to call the constructor you wrote earlier. You can define local variables inside the methods whenever it's convenient, but remember that the final result of each method will be a new vector. Don't modify the object on which the method was called.

    Note: You may want to add the word final to the declaration of your instance variables. This indicates that the instance variable's value should be established by the constructor and not be changed by any other method. Adding final will prevent you from accidentally changing the value in the methods you write for the Vector class.

  9. Define a method called deflectX that takes no parameters and returns a new vector that is identical to "this" one, except that its deltaX component has the opposite sign. For example, if this vector is [-3 4], then the new vector would be [3 4]. In other words, the method creates a vector oriented in the opposite x direction.
  10. Define a method called deflectY that takes no parameters and returns a new vector that is identical to "this" one, except that its deltaY component has the opposite sign.

  11. Define a method called plus that takes another vector as its parameter and returns a new vector that is the sum of this vector and the one provided as input. Recall that to add two vectors, you add their x-coordinates and their y-coordinates. For example, suppose you have a vector with value [3 4] and you call the plus method on it, passing in a vector with value [-5 2]. Then the vector returned by the method should have the value [-2 6].

    Hint: The parameter type and return type of this method are both Vector. When you create the new vector to be returned, you will need to supply parameter values. To compute those parameter values, you can use both "this" vector (the one on which the method was called) and the vector that was passed in as a parameter.

  12. Define a method called minus that takes another vector as its parameter and returns a new vector that is the difference of this vector minus the one provided as input.
  13. Challenge: Write minus in terms of methods you have already defined for the Vector class. Which computer science principle are you applying by doing that?

  14. Define a method called scale takes a double named factor as its parameter. When you call this method on a vector, it should return a new vector whose direction is the same, but whose magnitude has been multiplied by the given parameter.
    Recall: Scaling a vector by some factor can be accomplished by scaling its deltaX and deltaY components by that same factor. Be sure to return a new vector, and don't change the one on which this method was called.

  15. Define a method called rescale takes a double named magnitude as its parameter. When you call this method on a vector, it should return a new vector whose direction is the same, but whose magnitude is the one supplied as the parameter.
    Hint: First call the magnitude method to find this vector's magnitude and save it in a local variable. Use this to compute a scale factor, and then let the scale method do the rest of the work.
    NOTE: If the target of the rescale method has a zero magnitude, no particular direction is defined for the resulting vector. One could consider this an error condition, but for the purposes of this assignment, if the original magnitude is zero, let the resulting vector have deltaX equal to the given magnitude, and deltaY equal zero.

Part II: Testing with JUnit

Thorough testing is very important to help ensure that software works as expected. JUnit is a feature of Eclipse that supports automated testing. To begin testing your Vector class, first create a JUnit test, as follows.
  1. In the Package Explorer window of Eclipse, right click on the Vector class and select "New -> JUnit Test" from the popup menu.
  2. A dialog box will come up showing VectorTest as the name of the test class. It is important that you do the following in the dialog box:
    1. At the top, select "New JUnit 4 test." (We are not using the older JUnit 3.8)
    2. At the bottom, you may see a warning that JUnit 4 is not on the build path. In that case, click on "Click here" in that message to add JUnit 4 to the build path. What this means is that the Java compiler will know to look in the JUnit package to find the relevant files to compile your tests. Another dialog box will come up to add to the build path. JUnit 4 should be selected already. Just click "OK."
    3. Click "finish."
  3. A new class called "VectorTest.java" will appear in your project. This is where you will put your test cases. Every file that you turn in should begin with a header comment that includes your name, lab section, etc. Copy the header comment from one of your other files and modify the information as appropriate.
  4. Just above your header (but after the line that says "package lab4"), add the following lines so that the compiler will import certain JUnit features:
    import static org.junit.Assert.*;
    import org.junit.Test;
  5. A test method: Now you're ready to begin writing some tests your Vector class. Start by copying the following test method into your TestVector class. This test method creates a vector, makes sure that toString returns the correct string, and also checks that the accessors for deltaX and deltaY return the correct values.
    	public void initialization() {
    		Vector v = new Vector(5,-3);
    		assertEquals("[5.0 -3.0]", v.toString());
    		assertEquals(5.0, v.getDeltaX());
    		assertEquals(-3.0, v.getDeltaY());
  6. Things to remember about JUnit: Every test method must be preceded by the annotation "@Test" on the line before the start of the method. Also, JUnit requires that every test method be public and have a "void" return type, meaning that it does not return a value. The method assertEquals is available for use in JUnit test cases. It takes two parameters: The first parameter should be what you "expect" the value to be, and the second parameter is an expression that is supposed to equal that expected value. The assertEquals method checks to see if the two parameter values are equal. When comparing doubles, you can provide a third parameter to specify an amount by which the first two parameters are allowed to differ. When an assertEquals fails, the test will fail and JUnit will show you a failure trace so you can diagnose the problem. But the first thing to check is whether you have written the test correctly!

    To run the JUnit test, right click on VectorTest in the Package Explorer, and select "Run as -> JUnit test." After running a JUnit test, results are shown in a JUnit tab at the left. Is the bar green? If so, congratulations! Your constructor, toString, and accessors must be working. If the bar isn't green, you'll see a failure trace. Click on the line of the failure trace that's inside your VectorTest program, and you will see where the failure occurred. Then you can start checking your Vector implementation to see what's wrong. After fixing the problem(s), rerun the test case to make sure that the bar is green. To rerun the test case, click the little green arrow in the JUnit window, or right click on the TestVector class and select "Run as -> JUnit Test."

  7. Writing your own test methods: After fixing any problems discovered by the above test, create several more test methods inside the VectorTest class. Create a test method that checks the correctness of each of your Vector methods: deflectX, deflectY, plus, minus, magnitude, scale, and rescale. In each test case, you will create one or more vectors, call one or more methods, and have one or more assertEquals statements to check the results.

    We recommend adding one test case at a time, perhaps writing each test as you complete each method of the Vector class. Ideally, use a test-driven development methodology, as discussed in class. Run the test case, fix the method it is testing (if necessary), and then add another method to the Vector class and a new corresponding test method to your VectorTest class. Don't delete any of the previous test methods. By the time you are done, you'll have a number of methods that each test a different part of your class.

    Remember that when the parameters are of type double, assertEquals can take a third parameter, which is the tolerance within which you are willing to treat the values as equal. For example, assertEquals(5.0, m, 0.025) says that the value of m is expected to be within 0.025 (+/-) of the value 5.0.

    Be sure to create test cases that cover not only the "normal" cases, but also cases that are likely to cause errors. Your goal in VectorTest is to make the Vector class fail so you can find errors and fix them. For example, how does your scale method handle a vector whose magnitude is 0? You will use your Vector class in future assignments, so you will want to make sure it works correctly.

Part III: A Point Class

  1. In the Package Explorer, select the lab4 package and use the File menu to create a new class named Point in that package. In the Point.java file that is created, write an implementation according to the specificaion described in the following steps. Just as for the Vector class, create a separate JUnit test case for the Point class, and write tests for the Point constructor and each method. Test-driven development is recommended. Write the tests as you go, rather than at the end.

  2. Instance variables: Since a point is just an (x,y) pair, declare two instance variables (of type double) to hold the x and y coordinates of the point. These variables should be private to prevent changes from outside. The constructor and all methods in this class should be public.

  3. Constructor: Write a constructor that takes x and y as parameters, and initializes the new Point object with the values that are passed in.

  4. Accessors: Create getX and getY methods that return the coordinate values.

  5. toString: Write a toString method that returns a String representation of the point. For example, if x is 3 and y is -2, you might return the String "(3.0, -2.0)".

  6. Adding a Vector to a Point: It doesn't make sense to add two points together, but it does make sense to add a vector to a point. The result is a new point that differs from the old point by the deltaX and deltaY of the vector. For example, if we have the point (3,-2) and we add the vector [4 1], we will get the point (7,-1). Write a plus method of the Point class that takes a Vector as a paramter and creates a new point that results from adding this point to the given vector.

  7. Subtracting Points:When you subtract one point from another, you get a Vector, as shown in the figure below. As an example, suppose point P is (4,2) and suppose that point Q is (1,6), then P-Q would be the vector [3 -4]. (To see why this makes sense, consider what point you would get by adding the vector to Q.)

    Write a minus method of the Point class that takes another Point as its parameter and returns the appropriate vector.

  8. Distance to another point: Write a method that takes another point as a parameter and returns the distance between this point and the given point.

  9. Test all of your methods thorougly by writing tests in the PointTest.java file.

Optional Extension 1: Test-Driven Development (quiz-based)

Test-driven development is an iterative process. You write a simple test, and that forces you to write an implementation that passes the test. Then you see that the implementation is incomplete, but rather than immediately modifying the implementation, you first modify the test to force the implementation to be complete. You are being your own adversary in a sort of a game. The implementation is designed to be as simple as possible to pass the test, and the test is designed to force the implementation to be completely correct. The main benefit of this process is that it results in a set of tests that fully capture the specification. In other words, the goal is that the tests are so thorough that any implementation that passes the tests should be considered correct. Also, it's fun to develop software this way.

This week's quiz is based on the practice problems above. However, next week's quiz counts as an optional extension on the topic of test-driven development. This week's lab asks you to develop methods and to develop associated test cases. On next week's quiz, you will be asked to show the stages in test-driven development that might arise in the development of a particular method. A grade of 85% or higher on that quiz will give you credit for this optional extension. Some practice problems in the area of test-driven development will be provided as part of next week's lab. However, the best preparation would be to carry out your implementation of this lab using test-driven development.

Optional Extension 2: 3D Point and 3D Vector

A 3D point has x, y, and z coordinates. Similarly, a 3D vector has a deltaX, deltaY, and deltaZ. To complete this optional extension, implement a Point3D and a Vector3D class, with all of the same features provided by the corresponding 2D classes. Provide corresponding thorough test cases for each.

What To Turn In:

Demo your code using the course-sponsored DemoVectorTest class, which you should load into your lab4 package space and run under JUnit.

Follow these submission instructions to turn in the following files and demonstrate your running program for a TA.

  1. cover-page.txt -- Be sure to fill in all information.
  2. Vector.java
  3. VectorTest.java
  4. Point.java
  5. PointTest.java
  6. (for optonal extension) Vector3D.java, Vector3DTest.java, Point3D.java, and Point3DTest.java

Kenneth J. Goldman

Last modified 16:33:03 CDT 01 October 2008 by Ron K. Cytron