COM1204 Object-Oriented Design

Quiz 1 -- Thursday, May 3rd

ANSWERS -- QUESTIONS IN ROUGH ORDER OF INCREASING DIFFICULTY

Spring 2001 -- Professor Futrelle
College of Computer Science, Northeastern U., Boston, MA

This was a closed-book test, duration 30 minutes.


Each of the 5 questions on the quiz were worth 20 points. The extra-credit question was worth 10 points.

Question 1.

Does the following method "expose the rep" for the private instance variable b?

    public int getEven (int n) {
        return b[2*n];
      }

Answer: No, because it does not give the caller of the public method access to the array b[] itself (textbook, pg. 111). Therefore the caller would not be able to alter b[] or the element b[2*n]. Instead, it simply returns one of the values of b[] which is an int. It does not return a reference to (address of) the location, just the integer that was stored there. This does not even allow the caller to change the contents of b[2*n], because that element will continue to contain the integer that was contained in b[2*n] before the call. The incorrect and most "dangerous" answer was simply "Yes", because there was no way for me to give partial credit based on how you decided on your answer. For just plain "Yes", you lost 20 points on the quiz. Sorry. No short answers next time I hope!

Question 2.

What constraints are placed on a method with the following header:

    private static int[] fn(int k) ....

Answer: The method is private so it can only be called by other methods within the class (static or ordinary methods). It cannot be called by a method in any other class, since it is private. It returns an array of integers (it could return null) and it must be given one integer argument. A working example is shown below (you were not required to write out an example). The most difficult aspect of this for people was "static". Some said it could only be called once or only occured once. In fact, it can be called as often as needed, but only from within the class. If it were public and called from some other class it would have to be called with the class name, since it is only associated with the class, not with any object. It cannot refer to any non-static instance variables because a static function does not execute in the context of an instance.

public class Priv {

    public static void main(String[] args) {
        System.out.println(fn(3)[1]); // call from static method
        Priv pr = new Priv(); 
        pr.tryFn();
    }

    private  static int[]  fn(int  k) {
        return new int[] {0,1,2};  // argument k ignored
    }

    public void  tryFn() {
        System.out.println(fn(3)[2]); //  call from non-static  (instance) method
    }
}
/*  Output produced by the above code is
1
2
*/

Question 3. EXTRA CREDIT

For a record with two integer instance variables, m and n, write a toString() method that produces a string of the form [a,b] where a is the lesser value of m and n and b is the greater. For example, for a record with m=5 and n=3 the string would be "[3,5]".

Answer: We assume that there's some class with two instance variables m and n, which according to the rest of the question appear to be ints. You were to write a method for it (which would override the method in Object or some superclass). You did not need to define the class, but for convenience below I have, and I've even included a test of the function and its output. But all that was required in your answer was the definition of toString() itself, nothing more. There are of course many correct implementations of toString() that meet the specification (and unfortunately, many that do not).

Other points: toString() is not needed for primitives such as ints. Returning a value does not mean printing it. It means using return so that the call, where it appears in the calling program, is replaced by the value. Some people gave toString() some arguments, but it is a method that runs in a class with access to the instance variables. They should not and cannot be passed to toString() since when called by the system, no arguments are passed to it.

public class SomeClass {

    public static void main(String[] args) {
        SomeClass  s  =  new SomeClass();
        // m is less  than n -- interchanged  in the toString() example output
        s.m = 2;
        s.n  = 10;
        System.out.println(s);
    }

    int m,n;

    public String toString(){

        // tentatively, assume  this  ordering
        int greater = m;
        int lesser = n;

        // but roughly half the time,  interchange them.
        if( m < n) { greater = n; lesser = m;}
        return "[" + lesser + "," + greater + "]";
    }
}

/* output of the above is

   [2,10]

as expected
*/

Question 4.

Assume that a Vector v has a descriptive String as its 0-th element and Integer objects in the remaining elements. Write two lines of code that assign the 0-th element to a String variable s and the 6-th item to an int variable n. Hint: Use the get(int) method for Vector and the intValue() method for Integer.

Answer: This material is contained, almost identically, in the example at the bottom of page 31 and the one just before Sec. 2.7 on page 32. Specifically the line of code to access the 0-th element is,

String s = (String) v.get(0);

(You could omit the type declaration for s, since you were already told that it is of type String.) get() is a method of Vector and v is an instance of a Vector. That's why the access has this form. In addition the cast (String) must be done, because the Object returned from the Vector cannot be assigned to a subclass variable. This is very standard when using a Vector.

The other access is similar, also using get(). Then the result must be cast using (Integer). But in order to assign the value in this Integer object to an int, the intValue()method must be used. So the resulting expression is,

int n = ((Integer) v.get(6)).intValue();

It was not important whether you chose to use 5 or 6 in the accessor.

There is no [...] notation for Vectors. Some people used elementAt() (Java 1.1) instead of the simpler get() (Java 1.2) -- no points were deducted for this choice. intValue() is a method of Integer, not a method of Vector.

Question 5.

Consider the following method and its implementation:

    public int stepAndCount (int[] a, int n) {
        a[n]++;
        return ++count;
      }

Write out the appropriate contents of the REQUIRES, MODIFIES and EFFECTS specifications for this function (some or all may apply).

Answer: All three specifications are required for this function (Section 3.3).

REQUIRES: a[] should not be null. n should be within the range of allowed index values, 0 <= n < a.length. (The specification should NOT include the facts that the first argument is an integer array and the second an integer. This is obvious from the parameter list and is never described in a REQUIRES clause.)

MODIFIES: This specifically describes which inputs are modified by the procedure, if any are, as well as noting whether or not the object itself, this, is modified. No details should be given here; it is simply a short list. In this case a[] and this are modified.

EFFECTS: This describes the fact that it increments an internal counting variable by 1 and returns the incremented value. The procedure is underdetermined (pg. 51) because we don't know whether count is public or private or what other operations might be altering count. In addition, it describes the changes to a[]. In this case, a single element is altered by adding 1 to it.

Question 6.

Consider the following code:

    Object o = "abc";

For each of the following statements, indicate whether or not a compile-time error will occur, and for those statements that are legal at compile time, indicate whether they will return normally or by throwing an exception; if the return is normal, also indicate the result.

    boolean b = o.equals("a, b, c");
    char c = o.charAt(1);
    Object o2 = b;
    String s = o;
    String t = (String)o;
    c = t.charAt(1);
    c = t.charAt(3);

Answer: This question is identical to Exercise 2.5 on page 36 of the textbook. A little thought is required to make sense of it. A overly literal interpretation of it misses the point of the question. The lines below are numbered for discussion.

    1.  Object o = "abc";
    
    2.  boolean b = o.equals("a, b, c");
    3.  char c = o.charAt(1);
    4.. Object o2 = b;
    5.  String s = o;
    6.  String t = (String)o;
    7.  c = t.charAt(1);
    8.  c = t.charAt(3);

In 1, a variable of type Object is assigned the value of a String. This is legal.

In 2, the equals() method does exist for Object, so the line will compile. Dispatching is then done according to the actual run-time type of the object, which is String. It is false for Strings that "abc" is equal to "a, b, c" so the boolean b is set to false. equals() tests two objects for equality and therefore returns only true or false, a boolean that can be assigned to the variable on the left-hand side. (There are still one or two people in the class who think that "=" is a test, not an assignment. It's much too late in the game to have this misunderstanding! Also, an assignment computes the value of the expression on the right-hand side of the statement and changes the value of the item on the left-hand-side -- it assigns the value to the variable on the left-hand side. A couple of people are still confused about this very basic aspect of the language.)

In 3, the compiler does not know the actual type of the object o. But its apparent type, what the compiler knows, is Object. Object has no charAt() method so a compile-time error occurs. Line 3 will not compile. Here is what the (Sun) compiler returns:

Test.java:16: cannot resolve symbol
symbol  : method charAt  (int)
location: class java.lang.Object
            char c = o.charAt(1);
                      ^

In 4, the assignment attempts to assign a primitive type to an Object. That is not allowed in Java and causes a compile-time error. The compiler says,

Test.java:17: incompatible types
found   : boolean
required: java.lang.Object
            Object o2 = b;
                        ^
In 5, another illegal assignment conversion is attempted. In this case, an attempt is made to assign a value of type Object to a String variable s (a subclass). If this were allowed then calls to methods of String might be attempted on an Object that has no such methods. So this causes a compile-time error,

Test.java:19: incompatible types
found   : java.lang.Object
required: java.lang.String
            String s = o;
                       ^

A cast of the form String s = (String)o would work here, since the actual value of o is of type String.

In 6, no problems arise. o, which is a String, "abc", is cast to that type and assigned to a variable t of type String.

In 7, since t is a legitimate String, the charAt(1) function returns the character at position 1 in the String, which is 'b'. You might object that since line 3 couldn't compile, then c is undefined. But this is where you have to use a little common sense. If this were actual code then once a compile-time error occurred, none of the code would compile and the entire question would be meaningless. So it makes sense to assume that c is in fact a char variable.

In 8, the assignment is almost identical except that it is trying to access the character at position 3 in the String "abc", which only has characters at positions 0, 1 and 2. This leads to a run time error, reported as,

Exception in thread "main"
java.lang.StringIndexOutOfBoundsException: String index out of range: 3

        at java.lang.String.charAt(String.java:506)
        at Test.test(Test.java:24)
        at Test.main(Test.java:10)