CS 5 Fall 2009
Short Assignment #6
Due Wednesday, October 7

In this assignment, you will modify in a few ways the more elaborate Counter class that we saw in lecture. (The version in which you can specify how many digits you want to print.)

Observe that, for a given Counter object, whenever the show method is called on that object, it creates the same format string and a DecimalFormat object that does the same thing every time. In other words, the way I designed this version of the Counter class, the show method does repeated work each time it's called.

Instead of creating the format string and the DecimalFormat object each time that show is called, your first mission is to alter the Counter class so that each constructor creates an appropriate DecimalFormat object once and for all, saving a reference to this DecimalFormat object in an instance variable of Counter. To accomplish this change, you need to do the following:

  1. Remove the instance variable myDigits, since the DecimalFormat object that each constructor creates obviates the need to keep track of the number of digits to display. (In other words, the number of digits to display is already taken into account in the DecimalFormat object.)

  2. Declare an instance variable that is a reference to a DecimalFormat object, and give this variable an appropriate name.

  3. Define a new, private method named createFormat. This method takes one parameter, an int giving the number of digits to display for the Counter, and it returns a reference to a DecimalFormat object. This method should start off much like the show method that we saw in class. That is, given the number of digits to display (but here, provided as the parameter, rather than as an instance variable), it creates a format string, and then it creates a DecimalFormat object, passing the format string to the DecimalFormat constructor. The createFormat method finishes up by simply returning to its caller a reference to the DecimalFormat object it created.

    Although createFormat will be a private method of Counter, it need not, and should not, access any instance variables of the Counter class.

  4. Modify all three constructors to make appropriate calls to createFormat, where each constructor stores the reference to the DecimalFormat object returned by createFormat into the instance variable that you added in step 2, above.

    For the first two constructors, the number of digits you pass to createFormat should just be the value that a call to the private method digitsToDisplay returns. (Of course, make sure that any call to digitsToDisplay occurs after assigning to the instance variable myLimit, since digitsToDisplay relies on myLimit having been previously set.)

    For the third constructor, the number of digits you pass to createFormat should be the same as I stored in the instance variable myDigits. As in my version of this constructor, you should print out the warning that I printed out when too few digits are requested.

Once you've made the above changes, your Counter class is more efficient than mine, because now it doesn't do the same work over and over upon each call of show.

You're not done, however. I want you to make some more changes.

You might recall that if one operand of the + operator is a reference to a String but the other operand is not, then the other operand is converted to a reference to a String. How does this happen? It turns out that every class in Java has a method named toString, which is called implicitly if necessary. Java provides a default version of toString for all classes: you get a reference to a String containing the object's address in memory, written in hexadecimal (i.e., base 16). That might not seem terribly useful to you, but believe it or not, it can be.

But you always have the option of defining your own toString method for a class. That's what you'll do for Counter.

  1. Define a new public method, toString, that takes no parameters and returns a reference to a String. The String should be the same String that my version of show prints by passing it to System.out.print.

    How do you create this String? You've got a reference to a DecimalFormat object saved in an instance variable, and you know that when you call the format method of DecimalFormat, it returns a reference to a String. So that's all toString has to do: call the format method of the DecimalFormat object whose reference is stored in the instance variable, and return the String reference that format returned. Naturally, the parameter passed to format should be the current value of the Counter.

  2. In step 5, you moved the rest of the work that my show method did to the toString method. The show method no longer has to create a format string or a DecimalFormat object, because the constructors do that, and it no longer has to call the format method, because toString does that.

    Therefore, you should modify the show method so that it merely prints to the console the String whose reference is returned by a call of toString. If this sounds incredibly simple, that's because it is.

You have one other change to make to the Counter class: you're going to add another constructor. Recall how if s1 and s2 are references to String objects, then s2 = new String(s1) makes a copy of the String that s1 references and assigns to s2 a reference to this new String. You're going to create similar behavior for Counter objects.
  1. Create a new constructor which takes one parameter: a reference to a Counter. For the sake of making this concrete, the header of this constructor should be public Counter(Counter other) so that other references a Counter, which is the Counter whose instance variables you are to copy into the instance variables of the Counter you're constructing.

    The body of this constructor is really simple: three assignment statements, one for each instance variable. Not surprisingly, you can just use myLimit, myValue, and the instance variable you added in step 2 above on the left-hand sides of the assignment statements. And you should use the corresponding instance variables of the Counter referenced by other on the right-hand sides.

    How can you access the instance variables of the Counter referenced by other, when it's not the object that the constructor is called on? Actually, it turns out to be really easy. One of the rules of Java is that

    If a method in a class has a reference to an object of that class, then the method can access all the instance variables of that object, even if the object is not the one that the method was called on, and even if the instance variables are private.

    You access an instance variable using a syntax similar to a method call: objectReference.instanceVariable, but of course with no parentheses needed, since you're not calling a method.

    So, within your constructor, you can access the instance variable myLimit of the object referenced by other by simply writing other.myLimit.

Note that this approach of accessing private instance variables of an object other than the one that the method is called on works only for objects of the same class. For example, if we had a class Bozo with a private instance variable shoeSize, and if a method of Counter had a reference clown to a Bozo object, then we cannot say clown.shoeSize within methods of Counter.

Once you have made the above changes, you need to modify the driver to show that they work. Fortunately, you don't need to do much for the first three constructors, toString, or show, since the driver that I wrote already exercises them. (It exercises toString because it calls show, which will call toString when you complete step 6 above.) But you should modify the driver to show that the new constructor you wrote, which makes a copy of a Counter, works. All you need to do is make a copy of a Counter, and call tick on the copy a different number of times from how many times you call tick on the original Counter, and then call show on both of them. (Hint: You can call tick on one of the Counter objects zero times.)

To prove that toString is called implicitly, I also want you to add to the driver a call of System.out.print, where the parameter is just a reference to a Counter object. You should get exactly the same output to the console as if you had called show on this object.

Hand in your modified Counter and CounterDriver classes, along with the output from running the program. Start with my Counter and CounterDriver classes, and modify them. Don't change the names of these classes.

You don't have to hand in the following, but it's worth trying. Observe that once you assign to the instance variables myLimit and the reference to the DecimalFormat object that you add, their values will never change. What would happen if you declared them as not only private, but also as final? Try it; it'll take you only a minute.


Back to Short Assignments
Thomas H. Cormen <thc@cs.dartmouth.edu>
Last modified: Tue Oct 6 20:39:39 2009