CPSC 124, Spring 2021:
Sample Answers to the Second test

These are sample answers only.

Question 1. Briefly explain the meaning of each of the following modifiers in Java:

a) public
b) final
c) static

Answer.

a)  When a variable or method is declared public, it can be accessed from anywhere in the program, that is, from any class.

b)  When a variable is declared final, its value cannot be changed after it has been initialized.

c)  When a variable or method is declared static, it is part of the class itself. There is only one copy, and it exists as long as the class exists. (This is as opposed to non-static variables and methods, which become part of objects created from that class, and each of those objects has its own copy.)

Question 2. Explain what is meant by an instance of a class.

Answer. An instance of a class is an object that was created by a constructor from that class and containing copies of all the instance variables and instance methods that are defined in the source code of the class. [Soon, we will see that an instance of a subclass of a class is also considered to be an instance of the class.]

Question 3. A variable can be a local variable or a global variable. What do these two terms mean? Explain the difference.

Answer. Local variables are declared inside subroutines. They are local to the block in which they are declared. That is, they can only be used in that block, and after that block ends, they no longer exist and do not keep their value. (Local variables are inside the "black box" and are used for scratch work that is invisible from outside the box.)

Global variables are declared outside any subroutine (but inside a class, of course). They keep their values between calls to subroutines, so that a value that is assigned to a global variable in one subroutine can be used in another subroutine. Thus, they represent part of the permanent, ongoing state of a class or object.

Question 4. The first line of a subroutine is

          public static void process(String s, int x, int y)

Explain why each of the following attempts to call the subroutine is a syntax error:

a) process("Hello",142);
b) process("Hello", 3.14, 2.17);
c) process('H', 1, 3);

Answer.

a)  The subroutine has three formal parameters, so a call to the subroutine must provide three actual parameters, not two.

b)  The formal parameters x and y are of type int, so the corresponding actual parameters have to be values that can be assigned to an int variable. A double value like 3.14 or 2.17 can't be assigned to an int

c)  The actual parameter 'H' is of type char, which cannot be assigned to the formal parameter s, which is of type String, not char

Question 5. Write a static subroutine named almostEqual with two parameters of type double and return type boolean. This function should return true if the difference between the two paramters is between -0.0001 and +0.0001; if not, it should return false.

Answer.

     public static boolean almostEqual(double x, double y) {
         if ( -0.0001 < x - y && x - y < 0.0001 ) {
             return true;
         }
         else {
             return false;
         }
     }

( The test could also be written:  if (Math.abs(x - y) < 0.0001 )

(Also, note that "between" is ambiguous as to whether equality is allowed, so testing <= instead of < would be OK.)

Question 6. he subroutine multiPrint(s,n) that has a parameter of type String and a parameter of type int. It does not return a value. Calling multiPrint(s,n) will print the string s, and it will do that n times. Write a definition for the subroutine.

Answer.

     public static void multiPrint( String s, int n ) {
         for (int i = 0; i < n; i++) {
             System.out.println( s );
         } 
     }

Question 7. All parts of this question use class Player:

    public class Player {
        private String name;
        private int score;
        public Player(String s) {
            name = s;
            score = 0;
        }
        public String getName() {
            return name;
        }
        public int getScore() {
            return score;
        }
        public void addPoints(int n) {
            score = score + n
        }
    }

a)  Player.name does not exist. Why?

b)  Draw, or explain carefully, the result of executing the following code segment:

    Player p;
    p = new Player("Fred");
    p.addPoints(3);

c)  What happens when the computer tries to execute the following statements, and why?

    Player plr = null;
    System.out.println(plr.getName()); 

d)  The addPoints() method allows you to add a negative number of points to the score. How can you modify the class to make that impossible, and why does the change ensure that the score of a player can never decrease?

e)  Suppose that players is an array of type Player[], and that the array has already been filled with objects. Write a code segment that will print the name and score of every player in the array, and then at the end will print the highest score.

Answer.

a)  Player.name would have to be a static variable in class Player.

b)  Creates a variable named p, creates an instance of the class Player, and sets the value of p to be a pointer that new object. The constructor assigns "Fred" as the value of the instance variable name in the object, and the call to p.addPoints(3), adds 3 to the value of the instance variable score, which was initialized to zero. (The picture at the right is an alternative compete answer. However, it is not totally correct. A String is an object, so name actually contains only a pointer to the string, not the string itself.)

c)  A NullPointerException is thrown and crashes the program (unless it is caught elsewhere). (This is because the value of plr is null, so it does not point to an object, and there is no such thing as plr.getName.)

d)  I can add a test to check if n < 0 in the addPoints method; if so, I could throw an IllegalArguementException. This would ensure that addPoints() cannot be used to decrease the value of score. Furthermore, score is private, so it cannot be changed directly from outside the class, which means score can never decrease.

e)  Here is a code segment for part e):

  int highestScore = 0;
  for (int i = 0; i < players.length; i++) {
      Player p = players[i];
      System.out.println( p.getName() + ": " + p.getScore() );
      if ( p.getScore() > highestScore ) {
          highestScore = p.getScore();
      }
  }
  System.out.println( "The highest score is " + highestScore );

Question 8. Write a static subroutine that takes an array of integers as its only parameter and returns the sum of all the positive numbers in the array. That is, a number in the array should be added into the sum only if it is greater than zero.

      public static int arraySum( int[] array ) {
          int sum = 0;
          for (int i = 0; i < array.length; i++) {
              if (array[i] > 0) {
                  sum = sum + array[i];
              }
          }
          return sum;
      }

Question 9. A subroutine is a black box, but it can interact with the rest of the program through parameters and a return value. Explain these three terms, and discuss what this has to do with the idea of the "interface" and the "implementation" of a black box.

Answer. A black box is something that can be used without understanding how it works internally. (Furthermore, it can be designed without knowing all about the complete systems in which it will be used.) The implementation of a black box is its hidden interior, which makes it work. The interface of a black box is how it interacts with the outside. To use the black box, you need to know the interface, but not the implementation.

A subroutine is a kind of black box because in order to use the subroutine, you don't need to understand, or even see, the code in the definition of the subroutine. That code is the implementation of the subroutine. Its interface is how it communicates with the rest of the program. It does that with parameters and return values. The formal parameters of a subroutine are specified in its parameter list. They represent input that will be sent into the subroutine from elsewhere in the program, where the subroutine is called. The input values come from the actual parameters in the subroutine call statement, which are assigned to the formal parameters before the code in the subroutine is executed. The return value of a subroutine, if it has one, represents output from the subroutine, which is sent back to the caller of the subroutine. A subroutine that has a return value is specified to have a return type, rather than to be "void". Inside the subroutine, the return value is specified with a return statement, which ends the subroutine and sends back the value.

[Technically, the interface of a subroutine also includes any global variables that are used inside the subroutine. Global variables can carry information both into and out of a subroutine. And to use a subroutine effectively, you need to know more than its interface. You also need a specification of the exact task that it accomplishes — but not how it accomplishes that task. The interface is basically the syntax, while the task is the semantics.]