CPSC 124, Fall 2005
Answers to the Second Test


Question 1: Some short essay questions...

Part a) What does it mean to say that a subroutine can be considered to be a black box?

Answer: A black box is a module that has an interface through which it interacts with the rest of the world and an implementation that is hidden, so that it is possible to use the black box through its interface without understanding its implementation. A subroutine is a black box because you can use it without understanding the code inside the subroutine that actually does the work. The code is the implementation. The interface is the subroutine's name, parameter list, and return value.

Part b) Explain the difference between formal parameters and actual parameters.

Answer: Formal parameters are found in the declaration of a subroutine, such as the x, y, and z in "static double average(double x, double y, double z)". Actual parameters are found in subroutine call statements. Their values are assigned to the formal parameters before the code in the body of the subroutine is executed.

Part c) The full name of the square root function in Java is java.lang.Math.sqrt. Why?

Answer: The square root function is named sqrt, and it is defined as a static member of the class named Math. This class belongs to the package named lang which is in turn a sub-package of the package named java.

Part d) Explain carefully what the value null means in Java.

Answer: Null is a special pointer value that can be stored in a variable to indicate that the variable does not, in fact, point to anything. It can only be used with a variable whose type is given by a class, rather than by one of the primitive types. Such a variable cannot hold an actual object, only a pointer to an object. If its value is null, it does not currently point to any object.

Part e) What is a garbage collection in Java, and why is it important?

Answer: When there are no longer any references (or "pointers") to a particular object, there is no way for that object ever to be used again, so there is no reason for the object to continue to exist. Java uses garbage collection to identify these no-longer-useful objects and recover the memory that they occupy so that it can be reused for other objects. This is important since it relieves the programmer of the difficult task of keeping track of which objects are in use, and it makes it impossible for the programmer to commit such nasty errors as memory leaks and dangling pointers.


Question 2: Write a subroutine that computes the average of three numbers of type double. The three numbers are parameters to the subroutine, and their average is the return value. (To compute the average, add up the numbers and divide by 3.)

Answer: This is very easy. Note that no name is specified for the subroutine, so any name could be used. Although it is most natural for the subroutine to be static, this is not actually required by the problem, so it is optional in the answer. Also, the access modifier public is optional. Here is a possible answer:

        public static double average(double x, double y, double z) {
            return (x + y + z) / 3.0;
        }

Question 3: Write a subroutine that draws a set of parallel lines of increasing length, like those shown below. The subroutine should have two parameters: A parameter g of type Graphics, and a parameter N of type int. There is no return value. N tells how many lines to draw. You need g to do the drawing. (Recall that g.drawLine(x1,y1,x2,y2) is used to draw a line.) The scale of the drawing is not important.

Answer: The picture shows horizontal lines of increasing length. They are located one below another, and each line starts at the same x-value. In the command g.drawLine(x1,y1,x2,y2), we must have y1 = y2 to get a horizontal line. We have to call this routine N times. Each time it is called, the value of x1 is the same, but the values of y1 and x2 have to increase. If we assume that x1 is 0 and that the values of the other variables increase by 10 each time, here are two possible answers:

        public void parallelLines(Graphics g, int N) {
            for (int i = 0; i < N; i++) {
               g.drawLine( 0, 10*i, 10*i, 10*i );
            }
        }
   
   OR:
        public void parallelLines(Graphics g, int N) {
            int x1 = 0;
            int y = 10;
            int x2 = 10;
            for (int i = 0; i < N; i++) {
                g.drawLine( x1, y, x2, y );
                y += 10;
                x2 += 10;  
            }
         }

Question 4: Write a subroutine that strips extra spaces from a String. That is, any sequence of consecutive spaces should be replaced by a single space. The subroutine has one parameter of type String, and it has a return type of String. The return value is a copy of the parameter, except that extra spaces have been removed. (Suggestion: To build the new string, go through the old string character by character. Add each character to the new string, except don't add a space onto the new string when the preceding character is also a space.)

Answer: Here are two possible answers, one using tricky logic and one using more code:

      public static String stripSpaces( String original ) {
          String copy = "";
          for (int i = 0; i < original.length(); i++) {
             if (original.charAt(i) != ' ' || i == 0 || original.charAt(i-1) != ' ')
                 copy = copy + original.charAt(i);
          }
          return copy;
      }
      
  OR:
  
      public static String stripSpaces( String original ) {
          String copy = "";
          for (int i = 0; i < original.length(); i++) {
             if (original.charAt(i) != ' ')
                 copy = copy + original.charAt(i);  // add any non-space to the copy
             else { // Handle the case where the character is a space.
                 if (i == 0)
                     copy = copy + ' ';  // Add a space if it's the first character
                 else if (original.charAt(i-1) != ' ')
                     copy = copy + ' ';  // Add a space if previous char is not a space
             }
          }
          return copy;
      }

Question 5: For this problem, you should write a complete definition of a simple class. The name of the class is SavingsAccount, and an object of type SavingsAccount represents the balance in a savings account in some bank. The class has one private instance variable that holds the amount of money in the account. It has a constructor that specifies the amount that is placed in the account when it is created. It has three instance methods: one for depositing a specified amount in the account, one for withdrawing a specified amount, and one for getting the current amount of money in the account. (Note: This is a highly simplified class. The point is mainly to get the structure of the class correct. The body of each instance method can be just one line long.)

Answer:

      public class SavingsAccount {
      
          private double amount;  // Amount of money in the account.
          
          public SavingsAccount(double initialDeposit) {  // The constructor.
              amount = initialDeposit;
          }
          
          public void deposit(double depositAmount) {
              amount = amount + depositAmount;
          }
          
          Public void withdraw(double withdrawalAmount) {
              amount = amount - withdrawalAmount;
          }
          
          public double getCurrentBalance() {
              return amount;
          }
          
      }

Question 6: Using the class that you defined in the previous problem, write Java code that will create a SavingsAccount object with an initial amount of money equal to $1000.00 and store a reference to the object in a variable. (You can answer this question even if you did not complete the previous problem.)

Answer:

      SavingsAcount account = new SavingsAccount(1000.00);

Question 7: When the type of a variable is given by a class, the variable can only hold a pointer (also known as a reference) to an object. Explain carefully what this means and how it relates to using the assignment operator (=) and the comparison operator (==). (What do these operators mean for variables that point to objects?)

Answer: Objects are stored in a part of memory known as the "heap". When an object is constructed, a block of memory is allocated in the heap to hold the object. The constuctor returns a pointer to the object. This pointer is really just the numerical address of the object in memory. This pointer can be stored in a variable, which then "points" or "refers" to the object. When the variable is used, the systen can follow the pointer (that is, go to the correct location in memory) to find the actual object.

An assignment statement A = B copies the contents of the variable B into the variable A. But when dealing with objects, it is only a pointer that is copied. The actual object is not copied. So, you end up with two variables that point to the very same object. Similarly, the comparison A == B tests whether the values stored in A and B are the same. For objects, this means that pointer values are being compared, not the contents of the objects themselves. If A and B refer to two different objects, then A == B is false, even if the contents of the objects are the same. To make it possible to compare objects, rather than pointers, many classes define the instance method equals to compare object contents.


Question 8: The event-driven style of programming that is used in GUI programs is very different from the scripted, step-by-step programming that is often used for command-line applications. Discuss event-driven programs and how they relate to object-oriented programming. (What is an event? What does it mean to say that events are asynchronous? How does the programmer deal with the asynchronous nature of events? Why do objects fit in naturally with events?)

Answer: An event is something that occurs externally to the program and outside its control, such as when the user clicks the mouse or types a key or when data arrives over a network connection. Such events are asynchronous because they occur at unpredictable times, not at particular points in a "script". The program must be prepared to respond to events whenever they occur.

A programmer can deal with events by writing event-handling methods, which will be called by the system when the event occurs. For example, if a program needs to respond when the user presses a key on the mouse, it can define a mousePressed method. (It must also tell the system that it wants to receive mouse events by registering a "MouseListener" with the component that generates the events.) In general, the response to an event depends not just on the fact that the event occurred but also on the state of the program when it occurs. The programmer can use instance variables to keep track of the current program state. When an event-handling method is called, it can inspect those variables to find out what the current state is, and the response can include modifying the state of the program by changing the instance variables. For example, in the MosaicDraw program, the current drawing color is part of the program state. This part of the state changes when the user selects a new color, and the state is checked when the user draws something. This program is driven by the user's actions, since the user can select the new color or draw at any time, and the program must be prepared to handle those actions no matter when and in what order they occur.

Objects fit in naturally with events, because from the point of view of an individual object, messages coming into the object (that is, calls to its methods) are like events. The object does not control when or what order the messages will arrive -- that's under the control of the program that is using the object. So, when you design and code an object, its very much like writing an event-driven program: You use variables to keep track of the object state, and you must be prepared to handle messages as they arrive. So writing a class that handles events is really not much different than writing any other class.


David Eck, 6 November 2005