Lab 2: Editing, Compiling, and Testing Java Programs

Example: Airplanes

Instances of our first class represent airplanes. Such objects might be useful in flight simulation or air traffic control programs. We will name our class Airplane. By convention, Java class names begin with an upper case letter.

We declare the Airplane class in a file named Airplane.java. All Java classes must be declared in files with the .java extension. A .java file may contain several class declarations. The name of the file is taken from the name of the most important class in the file. In our example the Airplane class is the only class in the Airplane.java file, so the choice of names was easy. Be careful, the class name begins with an uppercase 'A', so the file name must also begin with an uppercase 'A'.

Editing

Any text editor can be used to create a .java file. (In our examples we use TextPad. A shareware editor available for home use at www.textpad.com. Shareware means if you like it, then you should buy it. Currently, the cost of TextPad is about $40.)

A ,java file usually begins with a file comment containing the name of the file, the version number, the creation date, and the name of the programmer. Following the file comment is a list of common package import statements. A package is a collection of pre-defined classes and sub-packages. A package import statement allows programmers to refer to classes defined in a package by their unqualified names. For example, the Java Development Kit (JDK) contains a package called java. Inside the java package is a sub-package called util. Inside the util sub-package is a class called Date. If a programmer wants to create an instance of this class, he must qualify the class name with its sub-package name:

java.util.Date date = new java.util.Date(); However, if the programmer imports all of the classes declared in the java.util sub-package: import java.util.*; then the programmer can subsequently refer to the Date class without qualification: Date date = new Date(); Although our Airplane class doesn't actually use any of the classes in some of the packages we import, it is common practice to include import statements for the most commonly used packages.

Here is the beginning of Airplane.java:

/*
* Class: Airplane.java
* Version: 1.0
* Date: June 1, 2000
* Programmer: Bart Simpson
*/

// imports:
import java.util.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
import javax.swing.event.*;

Next comes the declaration of the Airplane class. It begins with a class comment saying what instances of the class represents. We are following the (somewhat controversial) Sun Java coding style convention, which is documented at: java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html Our class declaration begins with private instance variables representing altitude and airspeed, followed by zero or more public constructors. The instance variables can be initialized where they are declared or by the constructor. All instance variables should be initialized in one of these two places: /**
* Instances of this class represent airplanes.
*/
public class Airplane
{
   /*****************************
    * variable declarations:
    *****************************
    */

   private double altitude = 0; // feet
   private double airspeed = 0; // knots/hour

   /*****************************
    * constructor declarations:
    *****************************
    */

   public Airplane()
   {
      System.out.println("an airplane is being constructed");
   }

Next, we add public method declarations. Our Airplane methods include takeoff(), fly(), and land(). Conventionally, method and instance variable names begin with lowercase letters. We also provide a public method called toString() that returns a formatted string describing the current altitude and airspeed of an Airplane object. When the Java compiler sees an Airplane object occurring in a place where a string is expected, it will automatically call our toString() method to convert the Airplane object into a string. For example, our takeoff() method appends this, the implicit parameter, to the end of the string "an airplane is taking off". But this refers to an Airplane object. It doesn't make sense to append an airplane to a string, so the Java compiler will automatically replace this by this.toString().   /*****************************
   * method declarations:
   *****************************
   */

   public void takeoff()
   {
      altitude = 30000;
      airspeed = 500;
      System.out.println("an airplane is taking off: " + this);
   }

   public void fly()
   {
      System.out.println("an airplane is flying ...");
   }

   public void land()
   {
      altitude = 0;
      airspeed = 0;
      System.out.println("an airplane is landing: " + this);
   }

   public String toString()
   {
      String s;
      s = "[airspeed = " + airspeed + " kph, altitude = " + altitude + " feet]";
      return s;
   }

Every class should include a static, public test driver named main(). Normally, main() creates a few instance of the class, then calls some methods:    /** Test driver. */
   public static void main(String[] args)
   {
      // print test banner:
      System.out.println("Programmer: Bart Simpson");
      System.out.println("Date: " + new Date());
      System.out.println("Testing class Airplane ... ");

      // make some objects:
      Airplane obj1 = new Airplane();
      Airplane obj2 = new Airplane();
      Airplane obj3 = new Airplane();

      // call some methods:
      obj1.takeoff();
      obj1.fly();
      obj1.land();

      obj2.takeoff();
      obj2.fly();
      obj2.land();

      System.out.println("done");

   } // main

} // Airplane

Problem 1: Create a directory called lab2. Use a text editor to create the file Airplane.java just described. Place this file in the lab2 directory.

Compiling

The Java Software Development Kit (SDK) comes with packages and tools. We have already seen some of the packages. Two important tools are the compiler and the virtual machine. The compiler can be invoked from a command console prompt as follows:

D:\jlab> javac Airplane.java If all goes well, the DOS prompt should reappear, and the compiler should have created a file named Airplane.class in your working directory. The Airplane.class file contains a translation of our Java code into virtual machine code which can be executed by the Java virtual machine. (Java uses a virtual machine instead of a real machine to achieve platform independence.)

Problem 2: Compile the Airplane.java file. Verify that the file Airplane.class has been created in the lab2 directory. Is Airplane.class bigger or smaller than Airplane.java, and by what percent?

Testing

The command:

java Airplane starts the Java virtual machine, locates and loads the file Airplane.class, then calls the main() method of this class. If the file Airplane.class can't be found, then we would get an error message like this: D:\jlab>java Airplane
Exception in thread "main" java.lang.NoClassDefFoundError: Airplane
If we forgot to include a public static method named main() in the Airplane class, then we would get an error message like this: D:\jlab>java Airplane
Exception in thread "main" java.lang.NoSuchMethodError: main
In our case we should see the output produced by main(): D:\jlab>java Airplane
Programmer: Bart Simpson
Date: Thu Aug 24 10:24:16 PDT 2000
Testing class Airplane ...
an airplane is being constructed
an airplane is being constructed
an airplane is being constructed
an airplane is taking off: [airspeed = 500.0 kph, altitude = 30000.0 feet]
an airplane is flying ...
an airplane is landing: [airspeed = 0.0 kph, altitude = 0.0 feet]
an airplane is taking off: [airspeed = 500.0 kph, altitude = 30000.0 feet]
an airplane is flying ...
an airplane is landing: [airspeed = 0.0 kph, altitude = 0.0 feet]
done
Problem 3: Test Airplane.class. Copy the output produced by main() into a text file named demo. Print this file.

Multi-Class Programs

An Airplane object in a more detailed flight simulator program might include component objects representing the airplane's engine and wings:

public class Airplane
{
   /*****************************
    * variable declarations:
    *****************************
    */

   private double altitude = 0; // feet
   private double airspeed = 0; // knots/hour
   private Engine engine;
   private Wing leftWing, rightWing;

Of course engine, leftWing, and rightWing are only object names. The Airplane constructor must create some engine and wing objects for these names to refer to:    public Airplane()
   {
      System.out.println("an airplane is being constructed");
     engine = new Engine();
      leftWing = new Wing();
      rightWing = new Wing();
   }
Assume that engines have start() and stop() methods and that wings have raiseFlaps() and lowerFlaps() methods. We can now add more detail to the takeoff() and land() methods of our Airplane class. For example, when an airplane take off, it should first start its engine and raise the flaps of its wings for added lift. After the airplane is airborne, it should lower the flaps of its wings:    public void takeoff()
   {
     engine.start();
      leftWing.raiseFlaps();
      rightWing.raiseFlaps();
      altitude = 30000;
      airspeed = 500;
     leftWing.lowerFlaps();
      rightWing.lowerFlaps();
      System.out.println("an airplane is taking off: " + this);
   }
Before landing an airplane should again raise the flaps of its wings. After the landing the engine should be stopped:    public void land()
   {
     leftWing.raiseFlaps();
      rightWing.raiseFlaps();
      altitude = 0;
      airspeed = 0;
     engine.stop();
      System.out.println("an airplane is landing: " + this);
   }
We can add declarations of the Wing and Engine classes to the Airplane.java file. For example, the Wing class begins with a class comment, declares a private instance variable called flapAngle that represents the angle in degrees of the wing's flap, and declares a do-nothing constructor: /**
* Instances of this class represent airplane wings.
*/
class Wing
{
   /*****************************
    * variable declarations:
    *****************************
    */

   private double flapAngle = 0; // in degrees

   /*****************************
    * constructor declarations:
    *****************************
    */

   public Wing()
   {
      System.out.println("a wing is being constructed");
   }

Notice that the word "public" doesn't appear in front of the Wing class as it did in front of the Airplane class. The Java compiler only allows the most important class in a .java file to be declared public. Since the file is named Airplane.java, this means only the Airplane class can be declared public. Only public classes can be used by classes located in other packages.

The raiseFlap() method sets flapAngle to 30 degrees, the lowerFlaps() method sets flapAngle back to 0 degrees. Both methods print the implicit parameter, this, which is automatically converted to a string using the toString() method:

   /*****************************
   * method declarations:
   *****************************
   */

   public void raiseFlaps()
   {
      flapAngle = 30;
      System.out.println("raising flaps: " + this);
   }

   public void lowerFlaps()
   {
      flapAngle = 0;
      System.out.println("lowering flaps: " + this);
   }

   public String toString()
   {
      return "[flap angle = " + flapAngle + " degrees]";
   }

As usual, a static, public test driver named main() creates a few Wing objects and calls a few Wing methods:    /** Test driver. */
   public static void main(String[] args)
   {
      // print test banner:
      System.out.println("Programmer: Bart Simpson");
      System.out.println("Date: " + new Date());
      System.out.println("Testing class Wing ... ");

      // make some objects:
      Wing obj1 = new Wing();
      Wing obj2 = new Wing();
      Wing obj3 = new Wing();

      // call some methods:
      obj1.raiseFlaps();
      obj1.lowerFlaps();

      obj2.raiseFlaps();
      obj2.lowerFlaps();

      System.out.println("done");

   } // main

} // Wing

Assume we also add an Engine class to Airplane.java using the Wing class as a guide.

Let's recompile Airplane.java:

D:\jlab> javac Airplane.java Here's the output produced by calling Airplane's main() method: D:\jlab>java Airplane
Programmer: Bart Simpson
Date: Thu Aug 24 10:52:20 PDT 2000
Testing class Airplane ...
an airplane is being constructed
an engine is being constructed
a wing is being constructed
a wing is being constructed
an airplane is being constructed
an engine is being constructed
a wing is being constructed
a wing is being constructed
an airplane is being constructed
an engine is being constructed
a wing is being constructed
a wing is being constructed
an engine is starting: [engine speed = 6000.0 rpm]
raising flaps: [flap angle = 30.0 degrees]
raising flaps: [flap angle = 30.0 degrees]
lowering flaps: [flap angle = 0.0 degrees]
lowering flaps: [flap angle = 0.0 degrees]
an airplane is taking off: [airspeed = 500.0 kph, altitude = 30000.0 feet]
an airplane is flying ...
raising flaps: [flap angle = 30.0 degrees]
raising flaps: [flap angle = 30.0 degrees]
an engine is stopping: [engine speed = 0.0 rpm]
an airplane is landing: [airspeed = 0.0 kph, altitude = 0.0 feet]
an engine is starting: [engine speed = 6000.0 rpm]
raising flaps: [flap angle = 30.0 degrees]
raising flaps: [flap angle = 30.0 degrees]
lowering flaps: [flap angle = 0.0 degrees]
lowering flaps: [flap angle = 0.0 degrees]
an airplane is taking off: [airspeed = 500.0 kph, altitude = 30000.0 feet]
an airplane is flying ...
raising flaps: [flap angle = 30.0 degrees]
raising flaps: [flap angle = 30.0 degrees]
an engine is stopping: [engine speed = 0.0 rpm]
an airplane is landing: [airspeed = 0.0 kph, altitude = 0.0 feet]
done
Although we placed the declarations of Engine and Wing in Airplane.java, the Java compiler created three .class files: Airplane.class, Engine.class, and Wing.class. We can confirm this by listing the working directory: D:\jlab>dir
Volume in drive D has no label.
Volume Serial Number is E479-0BB6

Directory of D:\jlab

08/24/00 11:21a <DIR> .
08/24/00 11:21a <DIR> ..
08/24/00 10:52a 1,904 Airplane.class
08/24/00 10:52a 4,934 Airplane.java
08/24/00 10:52a 1,347 Engine.class
06/28/00 04:48p 964 Expression.class
08/24/00 10:52a 1,344 Wing.class

Because we included a main test driver for the Wing and Engine classes, we can test them separately: D:\jlab>java Wing
Programmer: Bart Simpson
Date: Thu Aug 24 11:28:11 PDT 2000
Testing class Wing ...
a wing is being constructed
a wing is being constructed
a wing is being constructed
raising flaps: [flap angle = 30.0 degrees]
lowering flaps: [flap angle = 0.0 degrees]
raising flaps: [flap angle = 30.0 degrees]
lowering flaps: [flap angle = 0.0 degrees]
done

D:\jlab>java Engine
Programmer: Bart Simpson
Date: Thu Aug 24 11:28:19 PDT 2000
Testing class Engine ...
an engine is being constructed
an engine is being constructed
an engine is being constructed
an engine is starting: [engine speed = 6000.0 rpm]
an engine is stopping: [engine speed = 0.0 rpm]
an engine is starting: [engine speed = 6000.0 rpm]
an engine is stopping: [engine speed = 0.0 rpm]
done
 
 

Problem 4: Add the declaration of the Wing class to your Airplane.java file. Using the Wing class as a guide, add a declaration of an Engine class. An engine encapsulates a member variable representing the engine's speed in rotations per minute. Also make the modifications to the Airplane class shown above. Compile and test Airplane.java. Copy the output produced by the test into a text file and print it.

Multi-File Programs

If a .java file contains too many classes, then the file is difficult to read and it is difficult to reuse the classes it contains. For this reason it's probably a better idea to place the declaration of the Engine class in a file called Engine.java and the declaration of the Wing class in a file called Wing.java. If we do this, then we can declare Engine and Wing to be public classes. This means these classes can be used by classes in other packages.

As an experiment, let's place a static block near the top of each class declaration. A static block is a Java block statement that begins with the word static. A static block doesn't occur inside of any method declaration, and is executed when the Java virtual machine loads the class (but before any instances of the class are created).

For example, here are the static blocks we add to our three classes:

public class Engine
{
   static { System.out.println("loading class Engine"); }
   // etc.
} // Engine

public class Wing
{
   static { System.out.println("loading class Wing"); }
   // etc.
} // Wing

public class Airplane
{
   static { System.out.println("loading class Airplane"); }
   // etc.
} // Airplane

When we compile Airplane.java: D:\jlab>javac Airplane.java the compiler is smart enough to notice the references to Wing and Engine, and automatically locates and compiles Wing.java and Engine.java.

Here's the output produced by testing Airplane.class:

D:\jlab>java Airplane
loading class Airplane
Programmer: Bart Simpson
Date: Thu Aug 24 11:36:02 PDT 2000
Testing class Airplane ...
an airplane is being constructed
loading class Engine
an engine is being constructed
loading class Wing
a wing is being constructed
a wing is being constructed
an airplane is being constructed
an engine is being constructed
a wing is being constructed
a wing is being constructed
an airplane is being constructed
an engine is being constructed
a wing is being constructed
a wing is being constructed
an engine is starting: [engine speed = 6000.0 rpm]
raising flaps: [flap angle = 30.0 degrees]
raising flaps: [flap angle = 30.0 degrees]
lowering flaps: [flap angle = 0.0 degrees]
lowering flaps: [flap angle = 0.0 degrees]
an airplane is taking off: [airspeed = 500.0 kph, altitude = 30000.0 feet]
an airplane is flying ...
raising flaps: [flap angle = 30.0 degrees]
raising flaps: [flap angle = 30.0 degrees]
an engine is stopping: [engine speed = 0.0 rpm]
an airplane is landing: [airspeed = 0.0 kph, altitude = 0.0 feet]
an engine is starting: [engine speed = 6000.0 rpm]
raising flaps: [flap angle = 30.0 degrees]
raising flaps: [flap angle = 30.0 degrees]
lowering flaps: [flap angle = 0.0 degrees]
lowering flaps: [flap angle = 0.0 degrees]
an airplane is taking off: [airspeed = 500.0 kph, altitude = 30000.0 feet]
an airplane is flying ...
raising flaps: [flap angle = 30.0 degrees]
raising flaps: [flap angle = 30.0 degrees]
an engine is stopping: [engine speed = 0.0 rpm]
an airplane is landing: [airspeed = 0.0 kph, altitude = 0.0 feet]
done
Notice the output produced by the static blocks. The message "loading class Airplane" appears immediately. This is to be expected, since the class must be loaded before its test driver, main(), can be called. The message "loading class Engine" appears just before the first Engine object is created and the message "loading class Wing" appears just before the first Wing object is created. In other words, the Java virtual machine loads .class files as they are needed.

If the Java compiler can't find the Engine.java file, then we would see an error message like this:

D:\jlab>javac Airplane.java
Airplane.java:41: Class Engine not found.
Engine engine;
       ^
If the Java virtual machine can't find the Engine.class file, then we would see an error message like this: D:\jlab>java Airplane
loading class Airplane
Programmer: Bart Simpson
Date: Thu Aug 24 11:57:45 PDT 2000
Testing class Airplane ...
an airplane is being constructed
Exception in thread "main" java.lang.NoClassDefFoundError: Engine
at Airplane.<init>(Airplane.java:48)
at Airplane.main(Airplane.java:96)
Both the compiler and the virtual machine will search the working directory as well as any directories listed on the PATH or CLASSPATH environment variables for the .java and .class files they need.

Problem 5: Place the Engine and Wing classes in separate .java files. Add the static blocks as indicated above. Compile and test. Copy the output produced by the test into a text file and print it.
 
 

Problem 6: The test harness of an ATM (Automatic Teller Machine) creates and commits a transaction. A transaction contains a source account and a destination account. Committing a transaction means withdrawing a specified amount of money from the source account and depositing it in the destination account. An account has a balance, password, and owner, as well as deposit and withdraw methods. An owner is an instance of the Person class. A person has a name, address, phone number, and PIN number.

Create the files ATM.java, Transaction.java, Account.java, and Person.java. These files should contain the declarations of the ATM, Transaction, Account, and Person classes, respectively. Each class should have its own test driver. Compile and test each file. Copy the output produced by your test drivers into a text file. Print this file.