Ming's Java UI Basics for Non-Java Programmers Part I

by Ming-Yee Iu

Java is a programming language designed by James Gosling based on C, C++, and many other languages. This document is designed for non-C programmers, so it may not be detailed enough for those with C, C++, or other related experience.

One unfortunate aspect of Java is that it requires a considerable knowledge of software engineering principles to even program trivial pieces of code. Hopefully, this document will provide enough of a knowledge of these principles (or of hacks that will allow you to ignore these principles) that you will be able to do some user-interface programming in Java. It is assumed that you do have some knowledge of some other structured programming language (like Turing or Pascal or BASIC). If you have any comments, criticisms, or find some parts of this document to be unclear, feel free to e-mail Ming at my2iu@undergrad.math.uwaterloo.ca.

Note: All of the examples are centered around user-interface (UI) programming, so hopefully, the reader will gain an understanding of how to create windows and buttons and other interface elements in Java after reading this document. Hopefully, using UI in the examples will make things easier to understand because they are "concrete" instead of animals or generic containers. Also, having UI as the motivation behind all the examples might also give readers more motivation because the examples actually do stuff.

1 How to Use the JDK on Cygnus/Polaris

On the Cygnus/Polaris systems, you have access to Borland's JBuilder and also to the Java Development Kit (JDK). I don't know anything about JBuilder, but feel free to use it if you wish. To use the JDK, go to the Start Menu and choose Start\Programs\Programming\JDK Shell. This will create a DOS text window that gives you access to JDK tools. You probably want to create a directory somewhere (probably on the N: drive) to work on your Java stuff.

Here's a quick overview of DOS commands that you can type at the command prompt:
n: Switch to the n: drive
drive-letter: Switch to the drive with the specified drive-letter
cd directory-name Changes the current directory (i.e."file folder") to the one you specify
cd .. Changes the current directory to the parent of the current directory
mkdir directory-name Creates a directory in the current directory with the specified directory-name
dir Lists the files and directories in the current directory
del file-name Deletes the file with the specified file-name
deltree directory-name Deletes the specified directory-name
exit Closes the DOS text window

Or it may just be easier to do all of your file management in Windows.

Anyway, you need some way to create and modify text files. I don't know what text editors are available on Cygnus/Polaris, but notepad should be sufficient. Just type

  notepad name-of-file

to create or to edit a file. For example, to edit a file called MyFile.java, you would use

  notepad MyFile.java

After editing the file, you have to compile it before you can run it. To compile it, you must use the Java compiler called javac.

  javac MyFile.java

This causes the Java compiler to compile only MyFile.java. If you want the compiler to compile all the Java files in your directory, you would use

  javac *.java

For every .java file that you have, javac will create a corresponding .class file; for example, for MyFile.java, javac will create a new file called MyFile.class. Java uses these .class files to actually run your program. To run your program, you would go to the directory with all of your java files and type

  java MyFile

to run the program that was compiled from MyFile.java.

2 How to Use the JDK on the UNIX Undergrad Environment

On the Math undergrad systems, Java is available on only some of the UNIX servers. These include germain, markov, hermite, mef07, herschel, wronski, and picard. In general, most servers do not have Java available. In particular, these servers do not have Java: the "La..." X-servers, cayley, descartes, noether, and cantor. I do not believe that any Java IDEs are available on the UNIX undergrad environment.

Once you have logged-in to one of the UNIX terminals, the name of the servers that you have access to are usually listed in the title bars and command prompts of windows. You can access alternate servers by holding down the left mouse button in a blank area of the screen and choosing one of the servers from the pop-up window. Alternately, you can simply type

  rlogin name-of-server

in one of the windows. For example, typing

  rlogin germain

Will connect that window to the germain UNIX server.

Here's a quick overview of UNIX commands that you can type at the command prompt:
cd directory-name Changes the current directory (i.e."file folder") to the one you specify
cd .. Changes the current directory to the parent of the current directory
cd ~ Returns you to your "home" directory where all your files are located
mkdir directory-name Creates a directory in the current directory with the specified directory-name
ls Lists the files and directories in the current directory
ls -al Lists all files (including hidden files) in the current directory with information about file size, etc.
rm file-name Deletes (removes) the file with the specified file-name
rm -R directory-name Deletes the specified directory-name
exit Closes the window / Logs you out from that server
rlogin name-of-server Connects the window up to another server
pine Look at e-mail
cat name-of-file Displays a file on the screen
cat name-of-file | more Displays a file on the screen, one screen-full at a time
lpr name-of-file Prints a file on the mfcf printers. Go to the printer room for details about options for this command
any-program | more Displays the output of the program, one screen-full at a time; for example, "ls -al | more" will list all the files in a directory one screen-full at a time
ctrl-C This key combination usually stops a program when it is running
ctrl-D When ctrl-C doesn't work, ctrl-D will sometimes work instead

Anyway, you need some way to create and modify text files. The most popular text-editors available on the math undergrad UNIX environment are emacs, xemacs, vi, xedit, and pico. To use these programs, simply type their names at the command prompt followed by the name of the file you wish to edit.

  xemacs name-of-file
  emacs name-of-file
  vi name-of-file
  pico name-of-file
  xedit name-of-file

Emacs and XEmacs are extremely powerful and customizable editors with a somewhat graphical interface. XEmacs comes with games which are mildly interesting. Vi is an all text-based editor that is powerful and fast. Unfortunately, it is somewhat obscure and difficult to work with, especially for beginner users. The most important command to know in vi is the exit command: press the esc key several times, then type a capital Q, followed by a lowercase q and an exclamation mark !; then press enter. No one uses XEdit (it's slow and the backspace key doesn't work in the undergrad environment). Personally, pico is my editor of choice because it's small, mildly fast, and a no-brainer in terms of ease-of-use. It is also the same editor used in the pine e-mail program. Although it is not nearly as powerful as emacs or vi, most people don't know how to use those powerful features anyway (I would suggest attending CSC talks on vi if you're interested in those things), so it's not a big loss. All the available commands are listed at the bottom of the screen. The caret (^) means that you have to hold down the ctrl key to access that command. The main drawback to pico is that it's slower that vi, has a word-wrap feature that's inappropriate for programming, and doesn't have a lot of customization or power features.

So, for example, to create a file called MyFile.java using pico, you would use

  pico MyFile.java

After editing the file, you have to compile it before you can run it. To compile it, you must use the Java compiler called javac.

  javac MyFile.java

This causes the Java compiler to compile only MyFile.java. If you want the compiler to compile all the Java files in your directory, you would use

  javac *.java

For every .java file that you have, javac will create a corresponding .class file; for example, for MyFile.java, javac will create a new file called MyFile.class. Java uses these .class files to actually run your program. To run your program, you would go to the directory with all of your java files and type

  java MyFile

to run the program that was compiled from MyFile.java.

3 "Hello World" Java Program

So let's create a program that prints out "hello world." Create a file called MyProgram.java and paste this code into it:
/* One way to make a comment is to use a slash and a star 
   followed by your comment and then a star and a slash.
   Like here, anything between the slashes and stars is
   considered a comment
*/

// Two slashes turns the rest of the line into a comment
public class MyProgram
{
  public static void main(String args[])
  {
    // code to run goes here
    System.out.println("Hello world");
  }
}

Notice how comments can be denoted using double slashes or with slashes and asterisks. Also note how you create strings using double quotation marks. The program starts running at the opening curly brace right after the line with public static void main(...). The program stops at the ending curly brace. Compile the program and then run it by typing these lines at the command line:

  javac MyProgram.java
  java MyProgram

The program should print out Hello world.

4 Basic Syntax Reference

Most commands in Java must end with a semi-colon (;).

4.1 Variables and Arithmetic

To create a variable in Java, you type in the type of the variable followed by the names of the variables (separated by commas). You then put a semi-colon at the end of the line. Variable names are case-sensitive, so a variable called height is not the same as a variable called Height.
  int a, b, height, Height;

Here are some of the variable types available in Java:
boolean
can be true or false
char
a character
byte
an integer from -128 to 127
int
an integer from about -2 billion to +2 billion
long an integer from about -9 quintillion to +9 quintillion
float
a decimal (i.e. floating-point) number

Arithmetic in Java generally works like you expect it to (correct order of operations etc.). Use an equals sign to assign a number to a variable. Here is some sample code that creates various variables and performs arithmetic on them:

public class MyProgram
{
  public static void main(String args[])
  {
    int a, b;
    a = 4;
    b = 2+3*4;  // b is set to 14 not 24
    c = a + b * 2;
    System.out.println( c - 2 );

    float aDecimalNumber;
    aDecimalNumber = 0.5;
    aDecimalNumber = 6 * 3 / 0.5 * (a + b);

    boolean k;
    k = true;

    c += 2; // this is equivalent to c = c + 2
    c *= a; // this is equivalent to c = c * a
    c++;    // this is equivalent to c = c + 1
    c--;    // this is equivalent to c = c - 1
  }
}

This code can actually be put into a file called MyProgram.java, be compiled, and be run. Notice how most of the lines end with a semi-colon and the ++, --, +=, etc. notation.

4.2 Flow of Control Statements

Here is the general format of an if statement:
  if ( ... )
    what to do if condition is true

Things to note:

Here is some code that uses if-statements

public class MyProgram
{
  public static void main(String args[])
  {
    int a = 5;
 
    if (a < 4)
      System.out.println("a is less than 4");
    if (a >= 6)
      System.out.println("a is greater or equal to 6");
    if (a == 5)
      System.out.println("a is 5");

    int b = 2;
 
    if (a == 4 && b == 2)
      System.out.println("a is 4 AND b is 2");
    if (a == 5 || b == 1+1)
      System.out.println("a is 5 OR b is 2");
 
    boolean d = false;
    if (d)
      System.out.println("d is true");
    if (!d && b == 4)
      System.out.println("d is false AND b is 4");
  }
}

Things to note:

The restriction of only allowing one command to be executed if the if-condition is true is somewhat annoying. To get around this restriction, put multiple lines inside of some curly braces.

public class MyProgram
{
  public static void main(String args[])
  {
    int a = 5, b = 2;
 
    if (a > 4)
    {
      System.out.println("a is greater than 4.");
      if (b < 2)
        System.out.println("And b is less than 2.");
      if (b > 2)
        System.out.println("And b is greater than 2.");
      if (b == 2)
      {
        System.out.println("And b is 2");
        System.out.println("Which is what I expected.");
      }
    }
    if (a <= 4);
      System.out.println("a is less than or equal to 4");
  }
}

Things to note:

As in most languages, you can put an else after an if-statement.

public class MyProgram
{
  public static void main(String args[])
  {
    int a = 5, b = 2;
 
    if (a > 4)
      System.out.println("a is greater than 4");
    else
      System.out.println("a is not greater than 4");
 
    if (b == 2)
      System.out.println("b is two");
    else
    {
      if (b < 2)
        System.out.println("b is less than 2");
      else
        System.out.println("b is greater than 2");
    }
 
    if (a == 4)
      System.out.println("a is 4");
    else if (a == 5)
      System.out.println("a is 5");
    else if (a == 6)
    {
      System.out.println("a is 6");
      System.out.println("6 is an even number");
    }
    else System.out.println("a is not 4, 5, or 6");
  }
}

Things to note:

The other flow-of-control statements in Java are similar to the if-statement

public class MyProgram
{
  public static void main(String args[])
  {
    int n = 5;
    System.out.println("Countdown!");
    while (n > 0)
    {
      System.out.println(n);
      n--;
    }
  }
}

Things to note:

Here is another looping statement except it uses a do-while loop instead of a while loop

public class MyProgram
{
  public static void main(String args[])
  {
    int n = 5;
    System.out.println("Countdown!");
    do {
      System.out.println(n);
      n--;
    } while (n > 0);
  }
}

Things to note:

Like other languages, Java has a for-loop. Although most languages have for-loops because they are easier to use than while-loops, Java for-loops are sort of cryptic and harder to use than while-loops. Even though the syntax for a Java for-loop is messy, it is very powerful and succinct. Here is the general format of a Java for-loop:

  for ( thing1 ; thing2 ; thing3 )
    what to do each time through loop

Things to note:

      thing1; 
      while(thing2) 
      {
        loop stuff; 
        thing3;
      }

Here is some sample code that uses for-loops:

public class MyProgram
{
  public static void main(String args[])
  {
    int n;
    System.out.println("Countdown!");
 
    /* Set n to 5, and then keep looping while n>0,
       decrementing n by 1 each time. */
    for ( n=5; n>0; n--)
      System.out.println(n);
 
    System.out.println("Countdown from 100 by 10s!");
    for ( n=100; n>0; n -= 10)
      System.out.println(n);
 
    int factorial;
    System.out.println("Calculating 5 factorial (5!)");
    for (n=5, factorial = 1; n>0; n--, factorial *= n)
    {
      System.out.print("Right now n is ");
      System.out.println(n);
      System.out.print("And the running product is ");
      System.out.println(factorial);
    }
  }
}

Things to note:

5 Java Objects and Simple UI Programming

Java is an object-oriented programming language. Fortunately, using objects is pretty easy. Once you understand the general concept of objects, it's pretty easy to use. Unfortunately, using objects well and designing objects so that they are easy to use are difficult skills to master.

The idea behind object-oriented languages is that everything is an object, and to get things done, you just tell these objects what to do or ask questions of these objects. Objects follow the "black box" principle: you don't know what's inside the object or how it works; all you know is that you can give it commands and it will follow them.

[Picture of commands being sent to an object]

So, for example, let's say you're trying to create a window. Here is the "process" you would follow to go about doing that:

[Picture of creating objects etc.
Create a window Frame object
Show it
Wait 5 seconds (keep asking the System object for the time until 5 seconds pass)
Dispose (ie close) the window
]

5.1 Creating Objects

Although the diagram may make sense, how does one go about programming it? Well, the first step is to create a window object. In Java, the window object is called java.awt.Frame. AWT stands for Abstract Windowing Toolkit. All Java objects related to windowing usually have java.awt in their names. A Frame is a window with a title bar on top and a border (sort of like how a picture has a picture frame around it). Java treats objects like other variables, so you can create them the same way: you specify the type of the variable (in this case, a java.awt.Frame) followed by the name of the variable.
public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object
    java.awt.Frame window;
  }
}

Unfortunately, objects in Java aren't quite that simple. Although Java treats objects LIKE variables, it doesn't treat them exactly the same. Java makes the distinction between primitive data types and reference data types. Primitive data types are the normal data types that were described before: int, float, byte, char, boolean, etc. Objects are known as reference data types. When you create an object variable, you are not actually creating the object but a reference to an object of that type (for those of you familiar with the jargon, Java object variables are merely pointers to objects and not the actual objects themselves). What this actually means will become more clear when you actually see some examples.

[perhaps a picture of the difference between an int and a java.awt.Frame variable--java.awt.Frame won't actually point to anything until you create the object and assign it to the variable]

When you create a variable of type java.awt.Frame, you aren't actually creating a java.awt.Frame object, you are merely creating a reference to it. In order to actually create it, you have to use the new command.

public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object
    java.awt.Frame window = new java.awt.Frame();
  }
}

Things to note:

At this point, the only important things that you have to know about reference data types are that

There should be more examples of reference data types later in this document

5.2 Sending Commands to the Object

Once the object has been created, you can then commands to the object. Below is an example of the show command being sent to the java.awt.Frame object.
public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object
    java.awt.Frame window = new java.awt.Frame();
  
    // Send the show command to the Frame causing the
    // window to actually show itself on the screen
    window.show();
  }
}

Things to note:

After getting the window to show itself, you want to wait 5 seconds. To do this you find out what the current time is and set this as your "start time." Then you keep checking what the current time is, and when 5 seconds have passed since the start time, you go on to the rest of the program. To find out what the current time is, you use the currentTimeMillis command. This command returns the number of milliseconds that have passed since January 1, 1970. The object that understands this command is java.lang.System.

public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object
    java.awt.Frame window = new java.awt.Frame();
  
    // Send the show command to the Frame causing the
    // window to actually show itself on the screen
    window.show();
  
    // Find out what the current time is and set it
    // as the start time
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
  
    // Keep checking the time until 5000 milliseconds have elapsed
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Go on to the rest of the program...
  }
}

Things to note:

The final step in the program should be to close the window. This is done using the dispose command.

public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object
    java.awt.Frame window = new java.awt.Frame();
  
    // Send the show command to the Frame causing the
    // window to actually show itself on the screen
    window.show();
  
    // Find out what the current time is and set it
    // as the start time
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
  
    // Keep checking the time until 5000 milliseconds have elapsed
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the window using the dispose command
    window.dispose();
  }
}

Things to note:

So we've now actually written the code needed implement what was in the diagram.

5.3 Sending Commands with Arguments

You may notice that sending a command to an object is similar to making a function call in a non-object oriented language. Although they are similar, the technical name for sending a command to an object is "method invocation." Each of the commands are known as methods, and sending a command is known as invoking a method. Like functions though, you can pass in parameters, arguments, and other extra information when invoking a method.

To do this, you simply put the variables that you want to send with the command in-between the two brackets. For example, if you want to give the name a title, you use the setTitle method with a string with the title as an argument. You can also change the size of the window with the setSize command and the width and height passed in as arguments.

public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object
    java.awt.Frame window = new java.awt.Frame();
  
    // Give the window a title and resize it
    window.setTitle("The title of the window should go here!");
    window.setSize(500, 50);
  
    // Send the show command to the Frame causing the
    // window to actually show itself on the screen
    window.show();
  
    // Find out what the current time is and set it
    // as the start time
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
  
    // Keep checking the time until 5000 milliseconds have elapsed
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the window using the dispose command
    window.dispose();
  }
}

Things to note:

5.4 Constructors

You may have noticed that when you created the java.awt.Frame object, you had to put in some brackets. Similar to how you can pass in arguments when you invoke a method, you can pass in some arguments when you create an object. When the object is created, the object will be initialized (set-up) using the data that you passed in. For example, the java.awt.Frame object allows you to specify the title of the window when it is created.
public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object
    java.awt.Frame window = new java.awt.Frame("Title here!");
  
    // Resize the window only
    window.setSize(500, 50);
  
    // Send the show command to the Frame causing the
    // window to actually show itself on the screen
    window.show();
  
    // Find out what the current time is and set it
    // as the start time
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
  
    // Keep checking the time until 5000 milliseconds have elapsed
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the window using the dispose command
    window.dispose();
  }
}

Things to note:

When you pass in arguments during object creation like this, what you are actually doing is invoking a special method in the object you create that will construct the object using the parameters you specify. Because this special method is only used during object construction, this method is known as a constructor.

5.5 More Complicated Method Invocation

Up to this point, we've only passed strings and integers in as parameters during method invocation. It is possible to to pass in other objects during method invocation (or even the same object that the method is being invoked on). Below is an example piece of code that takes the Frame and adds a button to it. Further comments will come after the code.
public class MyProgram
{
  public static void main(String args[])
  {
    // Create a Java window object and resize it
    java.awt.Frame window = new java.awt.Frame("Title here!");
    window.setSize(200, 200);
    
    // Turn of layout management, so we can position the button
    // ourselves
    window.setLayout(null);
  
    // Create a button with "Click Me!" on it
    java.awt.Button button = new java.awt.Button();
    button.setLabel("Click Me!");
  
    // Add the button to the window and position it
    window.add(button);
    button.setBounds(50, 50, 100, 50);
  
    // Send the show command to the Frame causing the
    // window to actually show itself on the screen
    window.show();
  
    // Find out what the current time is and set it
    // as the start time
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
  
    // Keep checking the time until 5000 milliseconds have elapsed
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the window using the dispose command
    window.dispose();
  }
}

Things to note:

5.6 More on Reference Data Types

I mentioned earlier that objects are known as reference data types instead of primitive data types. I also made the distinction between having a variable with data that you could manipulate directly and having a reference to an object. Usually, the distinction between the two isn't important--in general, things in Java work like you would expect them to and would want them to. If you're interested though, this section contains some examples which explores some of the subtleties of using reference data types. (For those of you familiar with pointers, most of the information here is pretty self-evident and can be skipped.)

Below is the same UI example used before except that it has two Frame variables instead of one. Each of these variables is a reference. With all of the variables being moved around like this, it's hard to understand what's going on, so a more detailed breakdown of what's going on will follow.

public class MyProgram
{
  public static void main(String args[])
  {
    // Create two Frame variables and assign one to a
    // Java window object
    java.awt.Frame window1 = new java.awt.Frame("Title here!");
    java.awt.Frame window2;
  
    // Resize the window and set its location
    window2 = window1;
    window1.setSize(500, 50);
    window2.setLocation(0, 0);
  
    // Send the show command to the Frame causing the
    // window to actually show itself on the screen
    window1 = null;
    window2.show();
  
    // Find out what the current time is and set it
    // as the start time
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
  
    // Keep checking the time until 5000 milliseconds have elapsed
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the window using the dispose command
    window1 = window2;
    window1.dispose();
  }
}

Things to note:

The program starts by creating two variables: window1 and window2. The variable window1 is set to refer to a newly created Frame object while window2 isn't set to anything.

    // Create two Frame variables and assign one to a
    // Java window object
    java.awt.Frame window1 = new java.awt.Frame("Title here!");
    java.awt.Frame window2;

[Picture of window1 and window2 variables after initialization]

Afterwards, window2 is set to be window1. Now, window2 and window1 both refer to the same object. If you send commands to window1 or window2, you will end up sending commands to the same object.

    // Resize the window and set its location
    window2 = window1;
    window1.setSize(500, 50);
    window2.setLocation(0, 0);

[Picture of window2 and window1 referring to same object and calling setSize on window1 and setLocation on window2]

Following that, window1 is set to null. Setting a variable to null means to set the variable so that it doesn't refer to anything. When reference variables are first created, they usually refer to null (ie they don't refer to anything). After window1 is set to null, no commands can be sent to window1 since window1 doesn't refer to any object; however, since window2 refers to the Frame object we're interested in, commands can simply be sent to window2 instead. Please note that only reference variables can be set to null; primitive variables like ints, booleans, or floats cannot be set to null.

    // Send the show command to the Frame causing the
    // window to actually show itself on the screen
    window1 = null;
    window2.show();

[picture of window1 set to null and commands being sent to window2]

We then have the big piece of code which we use to wait for 5 seconds. There is nothing changed with this code.

    // Find out what the current time is and set it
    // as the start time
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
  
    // Keep checking the time until 5000 milliseconds have elapsed
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }

Finally, at the end of the program, we set window1 to be window2. Even though we set window1 to be null, we can set window1 to refer back to the same object that it originally referred to. Now that window1 refers to the java.awt.Frame object again, if we want to send commands to that object, we can use either window1 or window2.

    // Close the window using the dispose command
    window1 = window2;
    window1.dispose();

[Picture of both window1 and window2 referring to the same object again, and of window1 being used to dispose of an object]

As you can see, reference variables can be confusing at times. If you don't understand, don't worry. Reference variables usually take a little bit of time before they sink in, and, again, you can usually get by if you simply assume that variables will work the way you expect them to.

Anyway, let's look at another example. Here is an example that creates two windows: one named Window A and the other named Window B. Window A will be a wide window in the upper-left of the screen while Window B will be a tall window just below it. They will be displayed on the screen for 5 seconds and then removed.

public class MyProgram
{
  public static void main(String args[])
  {
    // Create two Frame objects for Window A and B
    // Use the variable window1 to refer to Window A and the
    // variable window2 to refer to Window B
    java.awt.Frame window1 = new java.awt.Frame("Window A");
    java.awt.Frame window2 = new java.awt.Frame("Window B");
  
    // Make Window A a wide window in the upper-left of the screen
    window1.setSize(500, 50);
    window1.setLocation(0, 0);
  
    // Make Window B a tall window below Window A
    window2.setSize(50, 200);
    window2.setLocation(5, 60);
  
    // Show both windows
    window1.show();
    window2.show();
  
    // Wait for five seconds
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the two windows
    window1.dispose();
    window2.dispose();
  }
}

Things to note:

Now, let's do something weird. In the middle of the program, we're going to swap window1 and window2, so that window1 will refer to Window B and window2 will refer to Window A

public class MyProgram
{
  public static void main(String args[])
  {
    // Create two Frame objects for Window A and B
    // Use the variable window1 to refer to Window A and the
    // variable window2 to refer to Window B
    java.awt.Frame window1 = new java.awt.Frame("Window A");
    java.awt.Frame window2 = new java.awt.Frame("Window B");
  
    // Swap window1 with window2
    window1 = window2;
    window2 = window1;

    // Make Window A a wide window in the upper-left of the screen
    window1.setSize(500, 50);
    window1.setLocation(0, 0);
  
    // Make Window B a tall window below Window A
    window2.setSize(50, 200);
    window2.setLocation(5, 60);
  
    // Show both windows
    window1.show();
    window2.show();
  
    // Wait for five seconds
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the two windows
    window1.dispose();
    window2.dispose();
  }
}

Unfortunately, the above piece of code does the swap improperly. Here's what happens. When the first line of the swap is executed, both window1 and window2 end up referring to the same object.

    window1 = window2;

[Picture of window1 and window2 referring to the same object]

So now when you set window2 to window1, window2 gets set to refer to the same object that window1 refers to. Since window refers to the same object that window2 refers to, there is no change.

    window2 = window1;

[Picture of window1 and window2 referring to the same object]

You may notice now that no variable refers to Window A anymore. Window A is now lost. There is no way to access or to send commands to the Window A object anymore. This is perfectly fine. If you don't want to use Window A anymore, then there is nothing wrong. This is actually a rather common thing to do in Java. When you've finished using an object, just leave it stranded. In fact, although it is sometimes a good idea to be aware of when you don't want to use an object anymore and purposely go about abandoning it, it is usually second-nature to do this anyway, so it's probably more of a hindrance to actually stop and think about this while programming than it is to just go ahead and blindly program. Note that other languages, such as Pascal or C++, don't have what are known as garbage collectors. Abandoning objects this way will result in what is known as a memory leak and is considered a bug.

So let's do the swap correctly now. Like in any swap, correctly doing the swap requires three variables.

public class MyProgram
{
  public static void main(String args[])
  {
    // Create two Frame objects for Window A and B
    // Use the variable window1 to refer to Window A and the
    // variable window2 to refer to Window B
    java.awt.Frame window1 = new java.awt.Frame("Window A");
    java.awt.Frame window2 = new java.awt.Frame("Window B");
  
    // Swap window1 with window2
    java.awt.Frame windowSwap = window1;
    window1 = window2;
    window2 = windowSwap;

    // Make Window B a wide window in the upper-left of the screen
    window1.setSize(500, 50);
    window1.setLocation(0, 0);
  
    // Make Window A a tall window below Window B
    window2.setSize(50, 200);
    window2.setLocation(5, 60);
  
    // Show both windows
    window1.show();
    window2.show();
  
    // Wait for five seconds
    long startTime = java.lang.System.currentTimeMillis();
    long elapsedTime = 0;
    while (elapsedTime < 5000)
    {
      elapsedTime = java.lang.System.currentTimeMillis() - startTime;
    }
  
    // Close the two windows
    window1.dispose();
    window2.dispose();
  }
}

Things to note:

Here is one final example that will hopefully make the distinction between reference variables and primitive variables a little clearer. Compare the following two code snippets:

Code Snippet 1:

    // Create a Frame object
    java.awt.Frame window1 = new java.awt.Frame();
    java.awt.Frame window2 = window1;
  
    // Show the window
    window2.show();
  
    // Now clear away the window
    window1.dispose();

Things to note:

Code Snippet 2:

    // Two integers
    int integer1 = 5;
    int integer2 = integer1;
  
    // Add 3 to integer2
    integer2 += 3;
  
    // Print out both numbers
    System.out.println(integer1);
    System.out.println(integer2);

Things to note:

In code snippet 1, window1 and window2 are reference variables that both refer to the same Frame object. Because of this, you can send a show() command to one and a dispose() command to the other, and the commands will be sent to the same object.

In code snippet 2, integer2 is initially set to be integer1. Then 3 is added to integer2. Because integer1 and integer2 are primitive variables and not reference variables, integer2 and integer1 are two distince pieces of data. When 3 is added to integer2, only integer2 is modified; hence, when their values are printed out, integer1 is still 5 while integer2 is now 8.

[A diagram here would probably make things more clear]

Again, although all this reference variable stuff may seem complicated now, for simple Java programming, it really isn't too important to know all these details. For now, it simply suffices to be aware that a lot of subtle stuff is happening behind the scenes and to let the principles sink in later. In fact, it's probably best to treat all of section 5.6 as an aside.

[Prev] [Next]

[Home]


Last updated November 14, 1998.
Maintained by Ming-Yee Iu
.

Objects are, in fact, rather simple to understand in theory. There are just three basic concepts. But there are a lot of details in the implementation of different languages and various conventions and practices that can only be learnt through programming.