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.