Exercise 3

The aim of this exercise is for you to become familiar with the different behaviours exhibited when using the Java primitive data types and Java objects.


Part A - Details

In this part of the exercise, you'll be expected to look at three example programs that illustrate some of the finer points of Java programming - in particular looking at the difference between Java's primitive types and Java objects.

Section I - Value vs. Reference

In Java, there is a subtle difference between using the built-in, primitive data types (boolean, byte, short, char, int, long, float, double) and objects (String, Date, etc., and your own user defined classes, like Radio). In particular, the primitive data types are stored as values, while the objects are stored as references. If you are familiar with Pascal or C/C++ you can think of these references as handles or pointers to the object.

This can give rise to some odd behaviour if you're not careful. For example, take a look at the ValRef.java piece of code and answer the following questions:

  1. Why doesn't String one == String two?
  2. Why can't we use the .equals() operator on a and b?

Hints

You should:

  1. Copy, compile and run the ValRef.java code (as usual)
  2. Read the code and your reference books closely to make sure that you understand why the program does what it does
  3. If you're having problems understanding what's going on, try drawing some diagrams
  4. When you think you do understand, write some experimental programs that do similar things and try to predict what will happen when you run them.

Section II - Differences when Copying

Another area where you have to know the difference between having your data stored as a value or as a reference, is when you copy objects. The code in Copying.java illustrates this.

Answer the following questions (on paper, with diagrams):

  1. Why, when we print 'a' again, is it the same?
  2. Why then, does the station that the wireless is tuned to change?
  3. What would happen if you created a new Radio() for the walkman, instead of copying the wireless?

Hints

You should:

  1. Copy, compile and run the Copying.java code
    (also make sure you've copied and compiled Radio.java too)
  2. Read the code and your reference books closely
  3. Try printing the value of wireless and walkman, using System.out.println
    (in particular, this might help with the third question)
  4. Experiment!

Section III - Parameter Passing

Another difference between primitive values and object references occurs when you pass them as parameters to other methods. When this happens, the parameter is copied for use in the method - the code in Parameters.java tries to show this.

So:

  1. Why are there two change() methods?
  2. Does 'a' get changed permanently by the call to the change() method?
  3. Does the wireless get changed permanently by the call to the change() method?
  4. So why do you think that happens?

Hints

You should:

  1. Copy, compile and run the Parameters.java code
    (also make sure you've copied and compiled Radio.java too)
  2. Read the code and your reference books closely
  3. Experiment!

Section IV - Wrapping Primitive Types with Objects

Since primitive values aren't Java Objects, if you want to pass them as arguments to methods that take parameters of type Object - it won't work. Luckily, the clever people at JavaSoft have thought of that and provided a handy set of Object wrappers for each of the primitive types. The code in Wrapping.java illustrates this process.

So:

  1. Why is it necessary to cast the Object retrieved from storage to its actual object type before using it again?
  2. What happens if you try to store( primitiveInt ) without wrapping it first?
  3. What line of code is doing the 'unwrapping' for us?

Hints

You should:

  1. Copy, compile and run the Wrapping.java code
  2. Read the code and your reference books closely
  3. Experiment!


Part B - A Simple Postfix Calculator

In this part of the exercise you will build a simple reverse polish (or postfix) calculator. That is, one that accepts arithmetic expressions like 23 + 4 in the form 23 4 +.

You are given the following piece of pseudocode that describes an algorithm for evaluating a postfix arithmetic expression:

   WHILE more symbols in expression DO
      symbol <- next symbol
      IF symbol is an operand THEN
         push symbol onto stack
      ELSE (symbol is an operator)
         op1 <- pop stack
         op2 <- pop stack
         value <- result of applying symbol to op1 and op2
         push value onto stack
      ENDIF
   ENDWHILE
   result <- pop stack

Your program should should ask the user for a valid postfix expression and then evaluate it and print out the result.

Hints

  1. Take a look at the SimpleCalc.java program for some ideas on how to structure your program
  2. You should use an instance of the java.util.Stack class as your stack. Remember to import it!
  3. Because the stack only stores Java Objects and not primitive types, you will have to wrap your ints with instances of the java.lang.Integer class. e.g.
  4. You should use the java.util.StringTokenizer class as a method of parsing the user's input.
  5. Think carefully about what sort of error conditions your program might encounter and try to write your program so that it catches them
  6. Other arithemtic expressions that you should test your program with are (infix/postfix):


Extras

Part A

Section I

What method would you use with String objects if you only wanted to compare whether two strings had the same letters in them, and not whether they were in the same case (upper or lower). i.e. so that "fred" would equal "FRED"?

Section II

To copy objects you either have to make a new one and copy the values, or use the clone() method if it is implemented. Unfortunately our Radio class isn't currently cloneable - but we can change that...

Replace line 9 in the Radio.java file:

public class Radio implements Cloneable

Insert the following at line 111 in Radio.java:

  /**
   * Makes a copy of this Radio.
   *
   * @return a clone of this radio.
   * @exception java.lang.OutOfMemoryError
   *            thrown if we run out of memory while cloning
   *
   **/

  public Object clone()
    {
    Object clone = null;

    try
      {
      // get our superclass to do the cloning for us
      clone = super.clone();
      }
    catch ( CloneNotSupportedException e )
      {
      // ignore this, because we know we're cloneable
      }

    return clone;
    }

Then change line 41 of Copying.java to read:

Radio walkman = (Radio)wireless.clone();

So:

  1. Now what happens, and how is this different from the previous case?
  2. What's the odd (Radio) doing in parentheses just to the right of the equals (=) sign on line 41?
    (try removing it and compiling to see what happens.)

Section III

What happens if you try to assign a new Radio() to wireless2 in change(), before setting its frequency to CLASSIC_FM? Why?

Section IV

Try storing doubles, floats, bytes, chars and Strings into the storage object. Note the different Object wrappers required/not required.

Part B

If your calculator doesn't already, it should allow users to enter more than one expression before quitting, perhaps by asking "Do you wish to enter another?" before exiting.