E-Book - PDF - Java Handbook 2 (3,355,756 Bytes) PDF
E-Book - PDF - Java Handbook 2 (3,355,756 Bytes) PDF
E-Book - PDF - Java Handbook 2 (3,355,756 Bytes) PDF
HANDBOOK
Anthony Potts
David H. Friedel, Jr.
Chapter
5
Java Classes
and Methods
Java Classes
and Methods
Classes are the key Java components that
give the language its object-oriented
personality. 5
If you have some experience programming in a language like C++, you are
probably familiar with the power and flexibility that classes provide. They are
ideal for plugging general information into a template-like structure for reusing
over and over. For example, if you are developing an interactive drawing pack-
age, you could create standard classes for some of the fundamental drawing
operations and then use those classes to create more sophisticated drawing tasks.
If you are new to the world of object-oriented programming (OOP), you’ll soon
discover that classes are the essential building blocks for writing OOP applica-
tions. At first glance, Java classes look and operate like C++ classes; but there are
some key differences which we’ll address in this chapter.
We’ll start by looking at the basics of classes. You’ll quickly learn how classes are
defined and used to derive other classes. The second half of the chapter covers
methods—the components used to breathe life into classes.
Understanding Classes
In traditional structured programming languages like C or Pascal, everything
revolves around the concepts of algorithms and data structures. The algorithms
are kept separate from the data structures, and they operate on the data to per-
form actions and results. To help divide programming tasks into separate units,
components like functions and procedures are defined. The problem with this
programming paradigm is that it doesn’t allow you to easily create code that can
be reused and expanded to create other code.
115
116 Chapter 5
Declaring a Class
If you recall from Chapter 2, we created a class named TickerTape, which con-
trolled how text scrolled across the screen. Let’s take a step back and look at the
full declaration used to define classes in Java:
Of course, keep in mind that you won’t always use all of the clauses, such as Doc
Comment, Modifier, extends, and so on. For example, here’s an example of the
world’s smallest class definition:
class Atom_ant {
int a = 1;
}
Java Classes and Methods 117
This class has an identifier, Atom_ant, and a body, int a = 1;. Of course, don’t
try to compile this at home as is because it will only result in an error. Why?
Well, even though it is a valid class, it is not capable of standing on its own. (You
would need to set it up as an applet or a main program to make it work.)
A class declaration provides all of the information about a class including its
internal data (variables) and functions (methods) to be interpreted by the Java
compiler. In addition, class declarations provide:
• Programmer comments
• Specifications of the other classes that may reference the class
• Specifications of the superclass the class belongs to (the class’s parent)
• Specifications of the methods the class can call
Using a Class
Before we move on and look at all of the other components used to declare
classes, let’s return to our simple class declaration to see how classes are used in
Java programs. Once a class has been declared, you need to use it to create an
object. This process is called making an “instance of” a class. In a Java program
it requires two steps. First, you declare an object variable using a syntax that
looks just like a variable declaration, except the class name is used instead of the
name of a primitive data type. For example, this statement would use the
Atom_ant class we defined earlier to declare an object from the class definition:
Atom_ant crazyant;
Once the object has been declared, in this case crazyant, you then create an
instance of it in a Java application by using the new operator:
Now the object crazyant can access all of the components in a Atom_ant class,
thus making it an instance of an Atom_ant class. To see how this works in
context, let’s expand our example:
The main class, Bug, creates an instance of the Atom_ant class—the crazyant
object. Then it uses the object to access the data member, a, which is assigned a
value in the Atom_ant class. Notice that the dot operator (.) is used to access a
member of a class.
Documentation Comment
The Doc Comment clause of the class declaration is provided as an aid to help
other programmers who might need to use your class. It allows you to write your
documentation while you’re writing the code. The comments you include as
part of this clause can easily be converted into easy to read HTML pages. How-
ever, keep in mind that your HTML pages will only be as good as your com-
ments. (To brush up on how to write comments for Java programs, make sure
you read Chapter 3.)
Let’s look at an example to see how the Doc Comment feature works. This class
definition
/**
* Atom ant is the world's smallest super hero,
so we gave him a class by himself.
* @author Dave Friedel
*/
class Atom_ant {
int i = 1;
}
uses Doc Comment style comments to produce the HTML page shown in Figure
5.1. Notice how the comments are formatted and used to document the class.
In this case, Atom_ant is a subclass under the java.lang.Object class—the de-
fault parent for all classes.
In case you’re wondering, the @author notation is a special type of comment tag
that allows you to personalize your class. These tags are explained in more detail
in Chapter 3.
Class Modifiers
Modifiers define the rules for how classes are used in Java applications. They
determine how other packages, or classes of other groups can interact with
the current class. There are three kinds of modifiers that can be used in a
class declaration:
• public
• abstract
• final
120 Chapter 5
Figure 5.1
The HTML documentation created for the Atom_ant class.
If you don’t use one of these modifiers when declaring a class, Java will auto-
matically decide that only other classes in the current package may access the
class. Let’s look at how each of these modifiers are used.
PUBLIC CLASS
The public modifier is used to define a class that can have the greatest amount
of access by other classes. By declaring a class as public, you allow all other
classes and packages to access its variables, methods, and subclasses. However,
Java Classes and Methods 121
only one public class is allowed in any single Java applet or a single source code file.
You can think of the one public class in an applet as serving the role that the
main() function does in a C/C++ program.
The source code for an applet must be saved as ClassName.java, where ClassName
is the name of the single public class defined in the applet. Recall that when we
created the TickerTape applet in Chapter 2, the single public class was defined as
// Filename: Atom_ant.java
public class Atom_ant {
public static void main (String args[]) {
System.out.println("Hello World");
}
}
In this case, Atom_ant is the name of the class and the filename for the applet is
Atom_ant.java.
ABSTRACT CLASS
The abstract modifier is used to declare classes that serve as a shell or place-
holder for implementing methods and variables. When you construct a hierar-
chy of classes, your top most class will contain the more general data definitions
and method implementations that represent your program’s features. As you
work your way down the class hierarchy, your classes will start to implement
more specific data components and operations. As you build your hierarchy,
you may need to create more general classes and defer the actual implementation
to later stages in the class hierarchy. This is where the abstract class comes in.
This approach allows you to reference the operations that you need to include
without having to restructure your entire hierarchy.
The technique of using abstract classes in Java is commonly referred to as single
inheritance by C++ programmers. (By the way, limited multiple inheritance tech-
niques can also be implemented in Java by using interfaces. We’ll cover this
topic in more detail in Chapter 6.)
122 Chapter 5
Any class that is declared as an abstract class must follow certain rules:
• No objects can be instantiated from an abstract class
• Abstract classes must contain at least one declaration of an abstract method
or variable
• All abstract methods that are declared in an abstract class must be imple-
mented in one of the subclasses beneath it
• Abstract classes cannot be declared as final or private classes
Let’s look at an example of how an abstract class is defined and used to help
create other classes:
Here, the class Quark is declared as an abstract class and it contains two meth-
ods that are declared as abstract methods. The subclassesAparticles and Bparticles
are located beneath the class Quark in the hierarchy of classes. Each one defines
a method based on one of the abstract methods found in the Quark class. A
compile-time error would occur if we had failed to define both of the abstract
methods in the Quark class. All abstract methods must be defined in the sub-
classes that are derived from abstract classes.
Java Classes and Methods 123
FINAL CLASS
The final modifier is used to declare a class that will not be used to derive any
other classes. The final class is like the last station on a railway line. By its posi-
tion in a class hierarchy, a final class cannot have any subclasses beneath it. In
final class declarations, you cannot use the extends clause because the Java com-
piler always assumes that a final class cannot be extended. Here’s an example of
what would happen if you tried to declare a final class and then use it in another
class declaration:
Compiling...
E:\java\jm\element.java
E:\java\jm\element.java:12: Can't subclass final classes: class
Moleculeclass Atom_ant extends Molecule { ^1 errorsCompile Ended.
In this case, Molecule has been defined as a final class. But notice that the sec-
ond class definition, Atom_ant, attempts to use Molecule as its parent. The Java
compiler catches this illegal declaration and provides the appropriate warning.
124 Chapter 5
Class Identifiers
Each class you define in a Java program must have its own unique identifier. The
class’s identifier or name directly follows the class keyword. The rules for nam-
ing classes are the same as those used to name variables. To refresh your memory,
identifiers should always begin with a letter of the alphabet, either upper or
lower case. The only exception to this rule is the underscore symbol (_) and the
dollar sign ($), which may also be used. The rest of the name can be defined
using characters, numbers, and some symbols.
Since class names are also used as file names, you need to create names that will
not cause problems with your operating system or anyone who will be using
your program.
Extending Classes
In most Java applets and programs you write, you will have a number of classes
that need to interact each other—in many cases classes will be derived from other
classes creating hierarchies. The keyword that handles the work of helping you
extend classes and create hierarchies is named appropriately enough, extends.
In a class hierarchy, every class must have a parent—except the class that is at
the top. The class that serves as a parent to another class is also called the super-
class of the class it derives—the class that takes the position immediately above
the class. Let’s look at an example. As Figure 5.2 indicates, the classes 911, 944,
and 928 all belong to the superclass Porsche. And Porsche belongs to the super-
class sportscar, which in turn belongs to the superclass automobile.
When you derive a class from a superclass, it will inherit the superclass’s data and
methods. (For example, 911 has certain characteristics simply because it is derived
from Porsche.) To derive a class from a superclass in a class declaration hierarchy,
you will need to use the extend clause followed by the name of the superclass. If no
superclass is defined, the Java compiler assumes that you are deriving a class using
Java’s top-level superclass named Object. Here is an example:
Automobile
Sports car
Porsche
Figure 5.2
A sample class hierarchy.
}
}
In this class declaration section, the top-level class defined is Element. Notice
that it is derived or “extended” from Object—the built-in Java class. The first
line of the declaration of Element could have also been written as
since the Java compiler will assume that a class is automatically derived from the
Object class if the extends clause is omitted. The second class, Molecule, is
derived from Element and the third class, Atom_ant, is derived from Molecule.
As Figure 5.3 shows, both Molecule and Atom_ant inherit the components of
the Element class.
126 Chapter 5
Element
Molecule Atom_ant
Figure 5.3
Using the extends keyword to derive a series of classes.
Java Classes and Methods 127
class Atom_ant extends Molecule implements Protons, Neutrons, Electrons {
static int proton = 45378444;
void Proton_function() {
... // definition of the Proton_function()
}
void Neutron_function() {
... // definition of the Neutron_function()
}
void Electron_function() {
... // definition of the Electron_function()
}
}
Here we are making the assumption that the interfaces Protons, Neutrons, and
Electrons only have one method declared in each of the interfaces. For example,
Protons may be set up as follows:
As you can see, setting up the interface is a two step process. The class where the
methods are defined uses the implements clause to indicate which interfaces
can have access to the methods. Then, interface statements are used to declare
the method that will be used.
If you recall from Chapter 2, the TickerTape class implemented the interface
Runnable from the package java.lang. The Runnable interface has only one
method declared in it, which is run(). This method is then defined in the class
that is implementing it. In this case, the applet TickerTape has defined run() to
instruct the thread to sleep, call the setcoord() method, and rerun the paint()
method every time the applet calls the run() method. This happens in situations
where the screen is resized or, in this case, where the applet is instructed to move
the text across the screen and the run() method is called.
// TickerTape Applet
import java.applet.*;
import java.awt.*;
128 Chapter 5
// TickerTape Class
public class TickerTape extends Applet implements Runnable {
...
public void run() {
while(ttapeThread != null){ // verifies the thread is still active
try {Thread.sleep(50);} catch (InterruptedException e){}
setcoord(); // changes the placement of the text
repaint(); // repaints the screen by activating the paint()
// method
}
}
...
} // End TickerTape
This allows the ability to effectively encapsulate(hide) the classes and all its meth-
ods that actually support the run() method. Interfaces allow for distinct behav-
iors, defined by the programmer, to be used without exposing the class(es) to
everyone. We’ll discuss these techniques in more detail in Chapter 6.
Class Body
The class body contains the code that implements the class. This is where you
provide the detail for the actions the class needs to perform (methods) and the
data it needs to use (variables). The body can also contain constructors (special
methods) and initializers. The basic format for a class body is:
{
Variable-declarations;
Method-declarations;
}
The variable declarations can be any standard Java declaration (see Chapter 3
and the material presented at the end of this chapter if you need a review). Later
in this chapter we’ll discuss how methods are declared and used. Here’s an ex-
ample of a class with a body:
NAME SPACE
Every method and variable defined in a class is recorded into an area called a
name space. This name space is then inherited by the other classes in a class
hierarchy which are derived from the class. If a variable or method has been
previously defined elsewhere in the structure with the same name, a shadowing
effect occurs for that level. To access the value of a variable that supersedes the
current value, you need to put the prefix clause super in front of the variable
name. This clause instructs the expression to take the value of the superclass.
To access the value of the current variable, you use the prefix this. Let’s look at
an example:
In this example the House class is derived from the standard Object class. Then,
the Room class is derived from House. Now notice that each class defines a
variable named tvamount and assigns it a value. In the second assignment state-
ment in Room, the variable Child is assigned the value 5 because this is used to
access the class’s local copy of the tvamount variable. In the next assignment
statement, notice how super is used to access the value tvamount was assigned
in House—the superclass.
130 Chapter 5
Methods
As we’ve seen, the mechanisms used to implement operations in classes are called
methods. This terminology is borrowed directly from object-oriented languages
like Smalltalk and C++. Methods define the behavior of a class and the objects
created from the class. A method can send, receive, and alter information to
perform a task in an application. Java requires that every method be defined
within a class or interface, unlike C++ where methods (functions) can be imple-
mented outside of classes.
Let’s refer to the car class hierarchy we presented earlier in this chapter to get a
better understanding of the role methods play. All of the cars we introduced
have doors and we could define two methods to operate on these doors: open
and close. These same methods could be designed to perform operations on
other car components such as windows, trunks, hoods, and so on. A component
like a door can be viewed as an object. Of course, a car would be made up of
many objects and many methods would be required to process all of the objects.
As a programmer, it would be up to you to decide how to arrange the objects
you need and what methods must be implemented.
Declaring a Method
If you recall from Chapter 2, our TickerTape applet included a number of meth-
ods. The first one defined was the init() method, which was responsible for
initializing the applet upon loading. Let’s take a step back and look at the full
declaration used to define a Java method:
The Modifier and Throws clauses are optional. They are used to specify how the
method needs to be accessed and which exceptions should be checked for. (For
more information on exceptions and how to catch errors, refer to Chapter 7.)
Method Modifiers
Earlier in this chapter, you learned that a set of modifiers are available for defin-
ing how classes can be accessed. Methods also can be defined using modifiers,
although the method modifiers only affect how methods are used, not the class
they are defined in. Java provides eight modifiers for defining methods, but only
one modifier from each of the groups listed next may be used in a method
declaration. For example, you cannot use a public and private modifier in the
same declaration. Here is the complete set of method modifiers:
• public, protected, private
• static
• abstract, final, native, synchronized
Keep in mind that it doesn’t make sense to use some modifiers in one group with
modifiers from another group. For example, a method that is defined using the
private and abstract modifiers contradicts itself. An abstract method is one that
requires its actual code to be defined in the subclasses that follow, whereas a private
method is one that can only be accessed in the class it is defined in. The rule of
thumb when choosing and combining modifiers is that you need to make sure
that they are complementary rather than contradictory. If a modifier is not used,
the method may be accessed only by the classes that are in the current package.
PUBLIC METHOD
A method declared as public can be accessed by any class in the same package. It
can also be accessed by other classes from other packages. This modifier gives a
method the most freedom.
PROTECTED METHOD
A method declared as protected can only be used by other classes within the
same package. All the subclasses beneath the class the method is defined in may
access the method unless shadowing occurs. Shadowing involves naming a method
using a name that already exists in a superclass above the class the method is
defined in.
132 Chapter 5
PRIVATE METHOD
A method declared as private is one that can only be accessed by the class it is
defined in. This modifier gives a method the least amount of freedom.
STATIC METHOD
A method declared as static is one that cannot be changed. This type of method
is also referred to as a class method, because it belongs explicitly to a particular
class. When an instance of the class that defines the method is created, the static
method cannot be altered. For this reason, a static method can refer to any other
static methods or variables by name. Limitations of static methods to keep in
mind are that they cannot be declared as final, and they cannot be overridden.
ABSTRACT METHOD
A method declared as abstract is one that must be defined in a subclass of the
current class. However, an abstract method must be declared in the current class
with a (;) semicolon in place of the method’s block of code. Methods that are
declared abstract are not required to be implemented in every subclass.
FINAL METHOD
A method declared as final is one that ends the hierarchical tree. No methods
having the same name can be defined in subclasses that exist below the class that
declares the method as final.
NATIVE METHOD
A method declared as native is one that will be implemented using outside code—
code that is written in another language, to be used in conjunction with your
current program. This limits you to a specific platform and restricts you from
creating Java applets. Native methods are declared by leaving out the method
body and placing a semicolon at the end of the method declaration.
SYNCHRONIZED METHOD
A method declared as synchronized limits it from being executed by multiple
objects at the same time. This is useful when you are creating Java applets and you
could have more than one thread running at the same time accessing one central
piece of data. If the method is static (e.g., a class method), the whole class would
be locked. If you just declare a particular method as synchronized, the object con-
taining the method would only be locked until the method finishes executing.
Java Classes and Methods 133
Method Throws
The throws clause is used to specify the type of error(s) that will be handled within
a method. In effect, it is used to help you set up an automatic error-handler. In the
event of an error, the error must be assignable to one of the exceptions in either the
Error, RunTimeException, or Exception classes. (These are special classes that
Java provides for catching compile-time and run-time errors. We’ll cover them in
more detail in Chapter 7.) Each method you declare does not need to use the
throws clause in its declaration, but in the event of an error, the omission of this
clause will leave the error handling up to the Java compiler or the Java interpreter.
Let’s look at an example of how the throws clause is used.
134 Chapter 5
At some point main() will try to access a location outside the legal range of the
array arr[]. When this happens, an exception will be “thrown” and the catch
clause will handle it. Also notice the use of the try clause which is needed to
specify which code in the method should be tested. In our case, we want to
check each iteration of the while loop.
Method Body
All executable code for Java classes is contained in the body of the methods.
Unless a method is declared as abstract, native, or is declared in the body of an
interface, the code for the method is placed between a pair of curly braces. This
code can be any valid Java statements including variable declarations, assign-
ment statements, method calls, control statements, and so on.
Here’s an example of how a basic method is defined:
In this example, this.Proton references the local variable Proton defined in the
class Quark. But take a look at the second method call in the Count() method.
Here, the variable Neutron, which is also declared in Quark, is referenced with-
out the use of the this keyword. What gives? Actually, since both of these vari-
ables are defined within Quark, the this keyword is not really needed.
As for the two following lines of code, they each reference the Number vari-
able declared in the Atom_ant class, which serves as the parent to the Quark
class. Notice that the keyword super is placed in front of the variable Number
to allow it to be accessed. This is the same as using the superclass name in the
statement Atom_ant.Number to reference the value of Number. Superclass
names can be referenced further up the hierarchical tree but the super key-
word can only be used to access class members that reside one level above the
current class. If the Molecule class contained a variable named M1, and we
wanted to reference it from the Quark class, a statement like this would be
required:
Proton = Molecule.M1;
Proton = super.M1;
the Java compiler would return an error because it would try to locate the M1
variable in the class that is directly above the Quark class.
Java Classes and Methods 137
...
}
}
Here we’ve declared two classes: Atom_ant and Quark. Atom_ant serves as the
superclass. The method that is overridden is Count(). It is first introduced as a
protected method in the Atom_ant class. Notice that it is declared here as taking
two parameters: Astring and Number. Because Atom_ant is declared as a pro-
tected method, it is restricted from being called by other classes outside of the
package Atom_ant is declared in.
138 Chapter 5
The Quark class, which is derived from Atom_ant, provides two new variations
of the Count() method, each one being overridden from the base method de-
fined in Atom_ant. Notice that each of the overridden methods uses different
parameters and/or return types than the original method.
To see how the different versions of the Count() method can be called, let’s
expand the Quark class a little:
void check() {
Atom_ant.Count("Hello", 5); //Correct refer to superclass method
super.Count("GoodBye", 5); //Correct same as previous
Molecule.Count("Hello World"); //Correct as long as it exists
Count(5, "World"); //Correct same as this.Count
}
}
The first two calls to the Count() method result in calling the Count() method
defined in Atom_ant. For the third call, we are making the assumption that the
class Molecule, which Atom_ant is derived from, contains a Count() method. If
it doesn’t, a compiler error will occur. The last call to Count() accesses the method
of the same name defined in Quark.
As with the other declarations we’ve introduced in previous sections, only the
identifier and body are necessary. Both the modifier and the throws clause are
optional. The identifier is the name of the constructor; however, it is important
to remember that the name of the constructor must be the same as the class
name it initializes. You may have many constructors (of the same name) in a
class, as long as each one takes a different set of parameters. (Because the differ-
ent constructors in a class must have the same name, the type, number, and
order of the parameters being passed are used as the distinguishing factors.) For
example, all constructors for a class named Atom_ant, must be named Atom_ant,
and each one must have different set of parameters.
In addition to having a unique declaration from that of a method, a special
format is used for calling a constructor:
Typename([ParameterList]);
The only required element is Typename, which names the class containing
the constructor declaration. Here’s an example of a constructor, with the
class Atom_ant and a constructor that uses the new operator to initialize
instance variables:
class Atom_ant {
String superhero;
int height;
void printatom_ant() {
System.out.print("Up and attam, " + superhero);
System.out.println("! The world's only " + height +
" inch Superhero!");
}
Notice that each constructor call is combined with the new operator. This op-
erator is responsible for making sure a new instance of a class is created and
assigned to the object variable a.
class Atom_ant2 {
String superhero;
int height;
Boolean villain;
void printatom_ant() {
System.out.print("Up and attam, " + superhero);
System.out.println("! The world's only " + height +
" inch Superhero!");
}
Because no constructor is defined for this example program, the Java compiler
will initialize the class variables by assigning them default values. The variable
superhero is set to null, height is initialized to zero, and villain is set to false.
The variable a, in the main() method, could have been initialized at the time the
constructor was called by substituting the code a = new Atom_ant2(); for
Atom_ant2 a = new Atom_ant2();. Either statement provides an acceptable
means of creating an instance of a class—the object a. Once this object is in
hand, the method printatom_ant() can be called.
The output for this program looks like this:
CONSTRUCTOR MODIFIERS
Java provides three modifiers that can be used to define constructors:
• public
• protected
• private
These modifiers have the same restrictions as the modifiers used to declare stan-
dard methods. Here is a summary of the guidelines for using modifiers with
constructor declarations:
• A constructor that is declared without the use of one of the modifiers may
only be called by one of the classes defined in the same package as the construc-
tor declaration.
• A constructor that is declared as public may be called from any class that has
the ability to access the class containing the constructor declaration.
• A constructor that is declared as protected may only be called by the sub-
classes of the class that contains the constructor declaration.
• A constructor that is declared as private may only be called from within the
class it is declared in.
144 Chapter 5
class Atom_ant2 {
String superhero;
int height;
String villain;
int numberofsuperheros;
Atom_ant2() {
this("Dudley Do Right", 60);
}
void printatom_ant() {
System.out.print("Up and attam, " + superhero);
System.out.println("! The world's only " + height +
" inch Superhero!");
}
public static void main(String args[]) {
Atom_ant2 a;
a = new Atom_ant2();
a.printatom_ant();
// Compile-time Error
a = new Atom_ant2("Atom Ant", 1 , "Dudley Do Right");
a.printatom_ant();
}
}
In this example, the Atom_ant2 class uses constructors with all three of the
modifiers: public, protected, and private. In addition, a constructor is declared
that does not use a modifier. Notice how the constructors are called from the
Molecule_mole class. Each constructor type is both defined and called using a
different parameter configuration. (This is how the Java compiler knows which
constructor to use.)
The first constructor call, Atom_ant2(), produces a compiler error because of
Java’s scoping rules—the declaration of this constructor is outside of the range of
the Molecule_mole class, and the constructor was not declared as public or pro-
tected. Also notice that the call to the fourth constructor produces a compiler
error. In this case, the constructor was declared in the Atom_ant class as private,
which limits the constructor from being called by the class it is declared in.
As this example illustrates, you need to make sure you understand the restric-
tions that modifiers can place on method declarations. For example, here is an
example of a compile-time error you will encounter if you try to access a con-
structor from another class when its modifier has been declared as private:
Compiling...
E:\java\jm\Molecule_mole.java
E:\java\jm\Molecule_mole.java:8: No constructor matching _
Atom_ant2(java.lang.String, int, java.lang.String) found in class Atom_ant2.
a = new Atom_ant2("Atom ant",5,"Dudley");
^1 error
Compile Ended.
146 Chapter 5
Constructor Body
The body of the constructor is essentially the same as the body of a method. The
only difference occurs in the first statement. If the constructor is going to call
“itself” (an alternate constructor for the same class having the same name) or call
the constructor of its superclass, it must do this in the first statement. To access its
own class, the this() statement is used as a placeholder for the class’s identifier. To
refer to the class’s superclass, the super() statement is used. Following each of the
clauses are parentheses containing the parameter list to be passed to the construc-
tor, identified by the keyword. Here is an example of how both the this() and
super() statements are used within the constructors defined for Atom_ant2:
Atom_ant2() {
this("Atom Ant", 1); // Call another Atom_ant2() constructor
}
a = new Atom_ant2();
a.printatom_ant();
System.out.println ("------") ;
}
}
When the program runs, the call to Atom_ant2() results in the first constructor
defined in the Atom_ant2 class being called. Then, the first constructor calls the
second constructor defined in the class. This process is illustrated in Figure 5.4.
In the first constructor, this() is used so that the constructor can directly call one
of Atom_ant2’s other constructors. How does the compiler know which one to
use? It looks for a match between the parameters based on this(“Atom Ant”, 1)
and one of the other Atom_ant2(...) constructors. Since the this() statement
passes a string and an integer, the actual constructor that is called is the second
one defined in the Atom_ant2 class.
In the third constructor declaration, the super() statement performs a similar
operation except this time it searches the immediate superclass’s constructor for
Class Atom_ant2 {
. . .
A call second
Atom_ant2( )
call first A constructor
constructor Atom_ant2(s, h)
h)
a= new Atom_ant2(
A )
. . .
Figure 5.4
The chain of constructor calls in the Atom_ant2 example.
148 Chapter 5
class Foo {
int variableNow = variableLater + 10;
int variableLater = 20;
}
Object Creation
There are two ways to create an instance of a class: use a literal, specific to the
String class or use the new operator. The new operator is placed in front of the
constructor. The parameter list of the constructor determines what constructor
is used to create an instance of an object.
...
public static void main(String args[]) {
Atom_ant2 a;
a = new Atom_ant2();
a.printatom_ant() ;
System.out.println ("------");
}
...
Here, the new operator initializes Atom_ant2 with an empty parameter list, initial-
izes the variable to create an instance of the class Atom_ant2, and assigns it to a.
Only the Type and Identifier components are necessary. The modifiers are optional.
As with all the identifiers we’ve used throughout this chapter, the variable iden-
tifier simply names the variable. However, you can name any number of vari-
ables in the declaration by naming them in the identifier position and separating
them with commas. If you decide to declare multiple variables, also realize that
the modifiers and Type apply to all the variables that are named. For example, in
these declarations
the variables paul, david, and kelly are declared as integers, and the variables
henry and diana are declared as static strings.
VARIABLE MODIFIERS
Java provides seven different modifiers for declaring variables within classes. How-
ever, you can only use two of them—one from each group—in a declaration.
Also, you can’t use two modifiers that contradict each other in the same declara-
tion. The two groups of modifiers are:
• public, protected, private
• static, final, transient, volatile
The public, protected, and private modifiers are discussed under the modifiers
sections of class, method, and constructors.
STATIC MODIFIERS
A static variable is also known as a class variable. This is because there is only one
variable of that name, no matter how many instances of the class are created.
Here’s an example of how the static modifier can be used:
Atom_ant2() {
static int Doug = 9;
this("Atom Ant", 1);
}
150 Chapter 5
...
public static void main(String args[]) {
Atom_ant2 a, b, c, d;
a = new Atom_ant2();
b = new Atom_ant2();
c = new Atom_ant2();
d = new Atom_ant2();
a.printatom_ant() ;
System.out.println("------") ;
}
...
Here, no matter how many objects we create, there is exactly one variable Doug
for every instance of Atom_ant().
FINAL MODIFIER
When a variable is assigned final, it acts as a constant throughout the instance of
the class. They must be declared at time of initialization of the class or method.
TRANSIENT MODIFIER
This is a modifier that has been reserved by Java virtual machine language for
low level segments that do not pertain to the persistent state of an object. Other
implementations will follow for this modifier in future versions.
VOLATILE MODIFIER
These are modifiers that are processed through the multi-processor in an asyn-
chronous manner. The variables are reloaded from and stored to memory every
time the variables are used.
int i;
short s;
Java Classes and Methods 151
s = 10;
i = (int) s;
(Classname)reference
The Classname is the name of the class you wish to cast to the receiving object.
The reference specifies the object that is to receive the cast. When applying a
narrowing effect to a class, as you will read about later, this type of cast is re-
quired by the Java compiler. Figure 5.5 illustrates this concept.
If a superclass attempts to cast an instance of itself to a subclass beneath it, a
runtime error will occur even though this type of cast will be accepted by the
Java compiler. The technique of passing object references down a class hierarchy
is referred to as widening. As a class is located at lower levels in a hierarchy it
becomes more specific and thus it contains more information than the classes
above it in the hierarchy. Superclasses, on the other hand, are usually more gen-
eral than the classes beneath them. Conversions that occur when you pass the
references up the hierarchy are thus referred to a narrowing because not all the
information is passed along to the receiving object. Furthermore, all instance
variables of the same name in the receiving object are set to the class variables
that are being casted.
Not Allowed:
Objects Classes
Widening
Parent
Child
Allowed:
Narrowing
Parent
Child
Figure 5.5
Widening and narrowing an instance of a class by using casts.
Here is an example of how you can cast references to objects between class types:
void print() {
System.out.print (superhero + " is " + height + "\n");
}
atom_ant a1;
a1 = new atom_ant();
a1.print();
electron_enemy e1;
e1 = (electron_enemy) p2; // Compile-time error due to casting to a
// sibling class
e1.print(); // Unable to execute because of the previous line
atom_ant a2;
a2 = (atom_ant) p2;
a2.print();
}
}
proton_pal() {
}
void print() {
System.out.print (superhero + " is " + height + "\n");
}
}
electron_enemy() {
}
void print() {
System.out.print (superhero + " is " + height + "\n");
}
}
Here we’ve modified our previous atom_ant class to illustrate the basics of cast-
ing. Notice that two of the casts used will produce a runtime and compile-time
error, respectively. (Thus, don’t try to compile the code unless you remove the
two illegal casts.) The first cast used in the main() method, p1 = (proton_pal)
a1, produces a widening effect. Although this statement will compile, it pro-
duces a runtime error because the object a1 cannot be expected to grow to ac-
commodate the new variables and methods it references in proton_pal. The
second casting statement used is a sibling cast: e1 = (electron_enemy) p2. It
generates a compile-time error because an illegal reference to a sibling class,
electron_enemy is used. This is due to the fact that the classes can have com-
pletely different variables and methods not related to each other. The last form
of casting that is addressed in the atom_ant class produces a narrowing effect. In
the statement, (a2 = (atom_ant) p2), the object p2 references variables that are
defined in the class, atom_ant, that is being casted. The reference is then past to
the variable a2.
Chapter
6
Interfaces and
Packages
Interfaces and
Packages
If you’re ready to move beyond the stages of writ-
ing applets and simple standalone applications and
applets, you’ll find that Java’s flexible interfaces
and packages provide a welcome relief. 6
After writing a few applets and applications, you’ll probably notice that the
directory your classes are written to will start to become obscenely large. This is
the downside of the way Java processes classes; but the good news is that Java
provides two key features called interfaces and packages to help you organize your
code. We put these two topics in a chapter by themselves instead of covering in
detail in the previous chapter to emphasize how important they are. (Many Java
books simply lump interfaces and packages in with classes, or they just skim
over them—shameful!) As you start to work more with interfaces and packages,
you’ll discover a myriad of important program design issues that come into play
which you’ll need to master to use interfaces and packages effectively.
In this chapter you’ll learn about:
• The basics of interfaces
• Techniques for implementing interfaces
• The hierarchical structure related to interfaces themselves
• Techniques for using casts with interfaces
• The basics of packages
• Techniques for creating packages
• Techniques for using Java’s predefined packages
The underlying goal of this chapter is to help you transition from writing small
standalone Java applications and applets to creating classes that can be used over
157
158 Chapter 6
and over. As you start to adopt this style of programming, you’ll need the flex-
ibility that interfaces and packages provide.
Understanding Interfaces
An interface is a collection of methods and variables that are declared as a unit
but they are not implemented until a later stage. Basically this means that the code
declarations placed in an interface serve as a shell so that you can create a truly
abstract class. The goal behind an abstract class is to provide a mechanism so that
you can define the protocols for a class—how a class should essentially communi-
cate with other classes—early on in the development cycle. The upshot is that
when you create your interfaces or abstract classes, you don’t have to specify all of
the details of how they will be implemented. This is saved for a later stage.
Before we jump in and start writing Java code for declaring interfaces, let’s ex-
plore a few conceptual examples. The concept of abstract classes and interfaces
is tricky to grasp at first. In fact, many experienced object-oriented program-
mers will tell you that they didn’t quite master the concepts until they had writ-
ten a number of programs. Fortunately, we can help you understand and use the
techniques much quicker by providing the background information and con-
ceptual models you’ll need to apply them.
The simplest form of an interface involves adding methods and/or variables that
are necessary to a particular class, but would disrupt the hierarchy of the class
structure you are currently building for an application. If you chose to actually
implement these elements in your class, they could limit how you planned to
use the class to derive other classes. To make your classes more flexible, you can
add interfaces to your classes in your hierarchy early on, so that the interfaces
can be used in multiple ways to help construct the “behavior” of other classes
that appear elsewhere in your class hierarchy. (If this discussion sounds like we
are talking in circles—welcome to the world of interfaces! Hopefully these fine
points will start to make sense to you in a moment when we look at a specific
example.)
Let’s assume that we need to develop an application that processes information
about different forms of transportation. Figure 6.1 shows the hierarchy that
could be used along with the list of components that could be implemented as
interfaces.
Interfaces and Packages 159
Class Hierarchy
Transportation
Solar Gas
Interfaces
Figure 6.1
The hierarchy of classes for the transportation example.
As with typical class hierarchies, the classes shown in Figure 6.1 become more
specific as they appear further down in the hierarchy tree. The interface compo-
nents are advantageous when you have operations that are to be performed in
one section of the hierarchy and not in the other areas. For example, the class
Car has two subclasses: Solar and Gas. Let’s assume you need to calculate the
liters of gas that a gas car will use. You could include the methods and variables
for performing this operation in the Car superclass, or even better, up two levels
in the Transportation class, so that the Powered|Boats and Powered|Airplanes classes
could use this code also.
Unfortunately, when you consider the scope of the application and all of the
subclasses that inherit this useless information, you’d probably agree that this
design approach is flawed. After all, the Solar|Car class would never calculate the
liters of gas used and neither would the Sail|Boats or Gliders|Airplanes classes. A
class that handles the gas calculating operation would be an incredible pain to
160 Chapter 6
incorporate at the Transportation level so that it could be designed into the hier-
archy, and thus forcing all the subclasses to inherit all of its methods. If we were
creating a small application that only required a few classes, this approach could
be used. But if you are building an application that uses lots of classes from the
beginning or you are expecting to expand the application in the future, this
approach could quickly become a programmer’s nightmare because limitations
could arise from placing such restrictions early on.
In applications that have class hierarchies like our transportation example, inter-
faces become priceless because they allow us to “mix-in” classes into the applica-
tion, adding them only where they become absolutely necessary. Another feature
that enhances the interface’s capabilities is the use of multiple implementations
of interfaces per class. For example, in our transportation application, theoreti-
cally the Car class would be interested in the Gasoline interface, but the Tire
interface could also be of use. An abstract class could incorporate both of these
interfaces (the methods and variables that define them) at the Transportation
level, but the Boat class would also be forced to inherit them. The Boat class
never would have any use for the Tire’s methods or variables.
Declaring an Interface
Let’s look at the basic declaration for an interface and then we’ll show you the
syntax for implementing an interface. After that, we’ll introduce some code to
illustrate how the transportation example we presented in the previous section
could be set up. The basic syntax for declaring an interface looks similar to the
syntax used for defining a Java class:
In this case, however, the class keyword is not used; the keyword interface takes its
place. The InterfaceName serves as the interface indentifier name and the rules for
specifying this name are the same as those used to name classes. The body of the
interface declaration simply consists of the declaration of static variables and the
names of one or more methods. Here’s an example of an interface declaration:
Note that the variable Feet_in_Miles is declared as both static and final. This is
required because all variables in interfaces cannot be changed. This type of declara-
tion essentially turns the variable into a constant. If you leave out the static and
final keywords, Java will force the variable to be declared as a constant. The two
methods listed include both the method name and the method’s parameter list.
The actual code for the method will come when the interface is implemented.
Implementing an Interface
Declaring an interface is only half of the work. At some point, the interface
must be implemented. This is accomplished by using the interface definition (or
abstract class) to create a class. In a sense, a class can be “derived” using the
interface shell. The syntax for implementing an interface is:
162 Chapter 6
With these interfaces in hand, we’re ready to create the two classes—Gas and
Powered—each one will implement some of the interfaces in different ways. They
will also show you how multiple interfaces can be used in a class definition:
int Feet_Traveled;
int Miles_Traveled = 20;
int Feet_Traveled;
int Miles_Traveled = 20;
Notice that the Gas class is extended from the superclass Car and implements the
interfaces Gasoline, Batteries, and Tires. In the class body of Gas, the methods
Interfaces and Packages 165
declared for these interfaces are coded as well as other variables that the class
needs, such as Feet_Traveled and Miles_Traveled. The Boat class, on the other
hand, only implements two interfaces: Gasoline and Batteries. Notice that the
Boat class implementation for the gas_type() method (declared in the Gasoline
interface) differs from the version implemented in the Gas class.
Let’s break down what is going on here so that you can better understand some
of the important and subtle Java programming techniques that are being used.
Our example is only missing one thing that is not shown in the code—a method
named makeGasCar() that creates and returns an object. Line 3 shows that an
object is returned from the makeGasCar() method and is named aCar of type
Gas. By assigning the returned value of makeGasCar() to an object variable of
the type Gas, the object inheirits all the methods pertaining to the Gas class.
This means it acquires all the methods relating to the class, its superclass, and the
interfaces the class implements. In line 4, we acquire an object from the
makeGasCar() method, but this time we cast it as type Gasoline from the inter-
face Gasoline. This means that the object, aGasCar, inheirits all the methods
that relate to the Gas class, its superclass, and only the methods and variables
declared in the interface Gasoline. As we’ll see in a second, this means no meth-
ods or variables from the other interfaces are available for the object to reference.
The next line does the same as the previous line, but the Tires interface is used
in place of Gasoline.
Lines 7 and 8 both have the object aGasCar call the methods gas_type() and
liters(), which were originally declared in the Gasoline interface. These method
calls are valid because the correct parameters are used and the object aGasCar
has access to both of these methods because of the cast that was used. In line 10,
the aTireCar object references the diameter() method which is also valid
Interfaces and Packages 167
because this object was created using the (Tires) cast and the diameter() method
is declared within the Tires interface. But in line 11, the aTireCar object tries to
call a method that is declared in the Gasoline interface. This produces a com-
pile-time error because the object does not implement the interface Gasoline.
Only the methods declared in the Tires interface are available from the object.
In the last section of the Gas class, lines 13 through 16, the object aCar may call
any of the methods available to the interfaces because this object is an instance
of the class Gas and is not casted to any particular class. This shows you the
versatility possible in creating objects using interfaces.
// TickerTape Class
public class TickerTape extends Applet implements Runnable{
...
// Change coordinates and repaint
public void run(){
while(ttapeThread != null){
try {Thread.sleep(50);} catch (InterruptedException e){}
setcoord();
repaint();
}
}
...
}
This is a powerful feature for creating methods and variables in classes that can
be set up with interfaces for future use, as long as the interface explains how
information will be transferred to and from it. You don’t need to allow others
access to your original classes.
168 Chapter 6
single group. Usually, classes that share a common goal are combined in a class.
For example, if you were creating a set of classes to handle drawing-related func-
tions for a design application, you might create a package called Draw and place
all of the related classes in this package.
You might have noticed back in Chapter 2 that some of the methods we imple-
mented in the ticker tape applet were borrowed from classes or interfaces be-
longing to other packages. For example, one of the packages used was the Applet
package—a package that Java provides, which contains all the necessary classes
for creating an applet. A package is introduced to a class by using the import
keyword in the beginning of a source code file. This will be covered in more
detail later in the chapter. As you will see, classes and packages are segregated
according to the functions they perform. This reduces the risk of having meth-
ods that share the same name interfere with each other. Here is a simple example
of how you can implement methods that belong to different packages into a
common class:
// TickerTape Applet
import java.applet.*;
import java.awt.*;
// TickerTape Class
public class TickerTape extends Applet implements Runnable {
...
public void init(){
...
}
public void start(){
...
}
public void run(){
...
}
public void graphics() {
...
}
public void stop(){
...
}
...
} // End TickerTape
170 Chapter 6
This is the same applet that was used in Chapter 2. All of the methods declared
in this example come from somewhere other than the current class. They have
been overridden to perform a certain function specific to the operation of this
applet. For example, the methods init(), start(), and stop() are defined in the
Applet class that is contained in the java.applet package. The run() method is
defined in the Runnable interface contained in the package java.lang.
java
lang
io
net
util
awt
peer
image
Figure 6.2
A graphical image of the hierarchy of java.awt.image and a call to the (import)
java.awt.image on the other side.
Interfaces and Packages 171
package PackageName;
Each class defined in the source file will automatically be added to the package
having the name specified by PackageName. The PackageName will be created
under the subdirectory you have defined in the CLASSPATH variable set in
your environment. (The instructions for setting this environment variable are
presented in the sidebar, Setting Your CLASSPATH Environment Variable.) As an
example, assume that you have a source file that contains a set of classes that
implement different types of airplanes. These classes could be combined into a
single package named airplanes by placing the package statement at the begin-
ning of each source file that defines a public class:
172 Chapter 6
The period sets the current directory you are compiling from.
The first directory listed in the CLASSPATH also specifies where
your package structure will begin.
Using Packages
The one feature that makes the Java language very powerful is that it lets you use
the same code (classes) over and over countless times. This is accomplished by
referencing classes that are contained in packages. To use classes that have al-
ready been created by you or other Java programmers, you need to reference the
package(s) the classes are grouped in. You can do this in one of three ways:
Interfaces and Packages 175
• Specify the full package reference each time a class is used that is defined in
an outside package. This approach is the most cumbersome and least often
used. Here’s an example:
In this case, the object variable twin is declared and initialized as an instance of
a Twin_engine class which is included in the airplanes package. With this ap-
proach, each time a Twin_engine class is accessed, its corresponding package
name must also be included.
• Import the actual class needed from the package it is defined in. As an ex-
ample, we could rewrite the previous example by using this code:
import airplanes.Twin_engine;
...
Twin_engine twin = new Twin_engine("Beach", 1100);
Notice that once the desired class is imported, the name of the airplanes pack-
age is not needed to reference the Twin_engine class.
• Import all of the classes defined in a package. The syntax for doing this is
illustrated with this statement:
import airplanes.*;
In this case, all of the public classes combined in the airplanes class, such as
Glider, Single_engine, and Twin_engine, would be included.
Every class defined in an external package that you want to reference by a class in
your Java application or applet must be called directly or with a wild card (*) in
176 Chapter 6
the immediate directory. For example, if you refer back to our ticker tape applet
presented in Chapter 2, we called an instance of the class FontMetrics that is
contained in the java.awt package (directory). The Applet class imports the
java.awt package with a wild card in the beginning of the code (e.g., import
java.awt.*;). The wild card tells the Java compiler to import all of the public
classes in the java.awt directory into the TickerTape class. The compiler won’t,
however, import any of the classes that are contained in the peer or image direc-
tories beneath java.awt. To include the classes in those directories, you must
reference the directories directly (e.g., import java.awt.peer.*; or import
java.awt.image.*;).
// TickerTape Applet
import java.applet.*;
import java.awt.*;
// TickerTape Class
public class TickerTape extends Applet implements Runnable {
import PackageName;
The PackageName represents the hierarchy tree separating the directories of the
package with decimals. The java.lang package is automatically imported into
every class that is created. If you look at the ticker tape applet presented in
Chapter 2, you will notice that it does not import the java.lang package but uses
many of the classes that are contained in the package. The classes String, Inte-
ger, and Thread are just a few of the classes that are called from this package.
Interfaces and Packages 177
// TickerTape Class
public class TickerTape extends Applet implements Runnable {
// Declare Variable
String inputText;
String animSpeedString;
int xpos;
int fontLength;
int fontHeight;
int animSpeed;
boolean suspended = false;
...
}
181
182 Chapter 7
Understanding Exceptions
Exceptions catch your errors and handle them gracefully so that your programs
can continue to operate. In Java, this process is called throwing an error. This
type of error handling can greatly benefit both you and the user of your applica-
tion. After all, nobody likes an application that just crashes out of the blue.
Unlike other languages, such as C, C++, and Pascal, where error detection and
reporting can often double and even triple the size of an application, Java pro-
vides the means to detect and handle errors and at the same time reduce the
overall size of your applications. The best part is that error handling in Java
replaces the multiple “if this occurs then do this” statements so often found in
programs written in languages like C.
Java’s exceptions allow you to effectively code the main sections of your applica-
tions without you having to spend too much time writing code to detect and
handle potential errors. As you’ll learn in this chapter, exceptions create an ob-
ject when an error occurs. The exception, which is a subclass of the Throwable
class, throws an object, which is passed up through the hierarchy of the calling
classes. The object will continue up through the classes until an exception han-
dler—a method that deals with the exception—catches the object. This process
is illustrated in Figure 7.1. If no exception handler is defined, a default excep-
tion handler is used to handle the error. This causes the error to be printed to the
command line and the program will cease running.
import java.lang.Throwable;
Having error checking and error handling features in Java is important because
Java programs, especially applets, run in multitasking environments. Often when
an applet is executed in a Web browser like Netscape 2, other applets will be
running at the same time. Each applet will have its own thread that the system
Java Exceptions 183
...
method throw method
try{
call method( );
}
catch(Exception);
throw
method throw
method throws
throw
throw new Exception
message
...
Figure 7.1
The process of throwing and catching an error in Java.
will control. If one applet causes a fatal error, the system could crash. With
exceptions, on the other hand, critical errors are caught; and the Java runtime
environment will know how to handle each thread that it must manage.
For example, assume you have created a class to write data to a disk file. As your
program is running, a number of errors could occur such as your hard disk
being full, a file being corrupted, and so on. If you didn’t have a way to catch
errors like these at some point, the program might crash, leaving the user with
nothing except a cryptic error message. Here’s a Java program that performs a
critical file operation but doesn’t provide any error handling:
WriteAFile(String s) {
write(s);
}
// Writes to a file
public void write(String s) { // I/O errors could occur here
FileOutputStream writeOut = null;
DataOutputStream dataWrite = null;
(Actually, this program won’t compile just yet because the Java compiler ex-
pects to find an exception named IOException. We’ll explain this in a mo-
ment.) The part of the code that could get you into trouble is the write()
method. This method creates a new file output stream and attempts to write a
character string to the stream. If the operation fails for one reason or another,
a runtime error would occur, although an exception has not been setup to
handle such an error.
Java Exceptions 185
Notice that two changes have been made. First, the entire block of code has
been placed in a try { } clause. Essentially, this tells the Java environment to be
on the “lookout” for errors that might occur as each method call is executed.
The second change is the addition of the catch() method. This block of code
performs the job of handling an I/O error that could occur with any of the calls
contained in the try section. In our example, we are letting Java handle the work
of processing an I/O error on its own by using the built-in IOException, and
that’s why no other code is provided with the catch statement.
These changes allow the code to compile and run. Unfortunately, they do not ad-
dress any problems that could arise from actually writing a file to disk. In a perfect
world, this code would be sufficient for our needs, but we don’t live in a perfect
world. For example, what if an error occurred while we were opening the file to be
written because the disk is full or not even present? And even if the file could be
opened, what would happen if an error occurred while we were writing the data to
the file. All of these conditions are valid exceptions to writing a file to a disk. Unfortu-
nately, you or others who use your classes might not detect them until it is too late.
Remember, the advantage of using a language like Java or other flexible object-ori-
ented languages is the ability to create robust code that can be reused by others.
Now, let’s change the WriteAFile class once more to make it more robust. Don’t
worry about the syntax right now, we will discuss the details of implementing
exceptions in the sections to follow.
186 Chapter 7
// Writes to a file
public void write(String s) {
FileOutputStream writeOut = null;
DataOutputStream dataWrite = null;
try {
writeOut = new FileOutputStream(s);
dataWrite = new DataOutputStream(writeOut);
}
catch (Throwable e) {
System.out.println("Error in opening file");
return;
}
try {
dataWrite.writeChars("This is a Test");
dataWrite.close();
}
catch(IOException e) {
System.out.println("Error in writing to file");
}
}
This time around, we’ve included two try clauses. The first one checks the methods
used to open the file, and the second one tests the methods used to write to the
file and close the file. Notice how each of the catch statements specifies the type
of object that it will catch or the exception that is thrown. We’ll show you how to
create custom error-handling routines later when we discuss the topic of catch-
ing. For now it is important to realize that we have separated the possible errors
we want to catch into two separate cases, opening and writing. By catching these
errors, we have prevented the program from crashing as a result of not being able
to open or write to a file. If errors like these are found, we could possibly ask the
user to change disks or try again instead of having the user loose his or her data.
In our case, we have simply written a message to the command-line telling the
user where the operation has failed if an error occurs.
try {
statement;
Java Exceptions 187
statement;
}
catch (Throwable-subclass e) {
statement;
statement;
}
For every try section, you must include at least one catch block that follows the
try section. If an exception is thrown in the try section during the execution of
the code, control flow is transferred to the matching section defined in the catch
statement. If no match is found, the exception is passed up through the hierar-
chy of method calls. This allows each level to either handle the exception or pass
it on. We’ll cover this more when we present exception throws.
import java.io.*;
ReadAFile(String s) {
String line;
FileInputStream fileName = null;
BufferedInputStream bufferedInput = null;
DataInputStream dataIn = null;
try {
fileName = new FileInputStream(s);
bufferedInput = new BufferedInputStream(fileName);
dataIn = new DataInputStream(bufferedInput);
}
catch(FileNotFoundException e) {
System.out.println("File Not Found");
return;
}
catch(Throwable e) {
System.out.println("Error in opening file");
return;
}
try {
while ((line = dataIn.readLine()) != null) {
System.out.println(line + "\n");
}
fileName.close();
}
catch(IOException e) {
System.out.println("Error in reading file");
}
}
Here, the try block instructs the code to watch for an exception to be thrown
from one of the methods contained in the block. The initializer that creates an
instance of the class type FileInputStream named fileName is capable of throw-
ing an exception in the event of an error. More specifically, the method con-
tained in the class FileInputStream declares that an exception is to be thrown to
the calling method. The topic of throwing exceptions will be covered later in the
chapter, but for now you just need to know that you are required to address all
Java Exceptions 189
exceptions thrown by handling them or passing them on. You handle the excep-
tion being thrown by placing exception handlers, declared in catch statements
that the errors are then compared to. In the event of an error, the code will break
from the normal flow of the code and immediately jump to the first exception
handler that matches the class type defined in the catch. In the ReadAFile()
method, the first catch identifies the FileNotFoundException class as a type
that may be thrown upon instance of an error. This is followed by another catch
identifying the Throwable class, which will act as a “catch all” for the exceptions
being thrown. This match occurs because all exception classes are derived from
the Throwable parent class.
try {
statement;
statement;
}
catch (Exception Handler) {
statement;
statement;
}
finally {
statement;
statement;
}
import java.io.*;
WriteAFile(String s) {
write(s);
}
// Writes to a file
public void write(String s) {
FileOutputStream writeOut = null;
DataOutputStream dataWrite = null;
try {
writeOut = new FileOutputStream(s);
dataWrite = new DataOutputStream(writeOut);
dataWrite.writeChars("This is a Test");
dataWrite.close();
}
catch(IOException e) {
System.out.println("Error in writing to file");
}
catch(Throwable e) {
System.out.println("Error in writing to file");
}
finally {
System.out.println("\n\n.....creating a backup file.");
try {
writeOut = new FileOutputStream("MyBackup.sav");
dataWrite = new DataOutputStream(writeOut);
dataWrite.writeChars("This is a Test");
dataWrite.close();
}
catch (IOException e) {
System.out.println("Error in writing backup file");
}
}
}
// Where execution begins in a stand-alone executable
public static void main(String args[]) {
new WriteAFile(args[0]);
}
}
Throwable
Errors Exception
RunTimeException
Figure 7.2
The Hierarchy of the Throwable class.
egory consists of the more common exceptions that you will want to “catch.”
The Errors category, on the other hand, consists of the low level exceptions that
most programmers won’t need to deal with.
The next major split occurs with the Run-Time Exception category, which is a
subclass of Exception. Sun has arranged the hierarchy like this because they real-
ized that by separating commonly used exceptions from specific exceptions, pro-
grammers would not be forced to include tons of handlers in their code.
ERROR CLASS
The exceptions included in the Error class are problems such as Linkage Error,
ThreadDeaths, and other catastrophes that result in fatal errors. For the most part,
these exceptions will not be handled by most applications. They are reserved for
lower level programming tasks that require you to get into the internal workings of
the language. For that reason, it is not a good idea to derive your own exception
classes from Error unless you have a good working knowledge of Java. Table 7.1
provides a list of the key exceptions that are provided. All of the exceptions are
defined in the Java Language Package java.lang, expect for AWTError, which is
defined in the Advanced Windowing Toolkit Package, java.awt.
192 Chapter 7
EXCEPTION CLASS
The exceptions included in the Exception class represent the most common
errors that a programmer will want to deal with. For the most part, these excep-
RUNTIME CLASS
The exceptions included in the Runtime class are thrown during the execution
of Java code. All of these exceptions are exempt from the restrictions of handling
the exception at compile time. These exceptions are optional because of the
need to keep Java code compact and easy to read. Table 7.3 provides a list of the
key exceptions that are provided in the Runtime class. These exceptions are
defined in the Language Package (java.lang).
The throws clause may list as many exceptions as will be thrown to it by separat-
ing each of them with a comma. For an example, let’s take our ReadAFileAFile
class to the next level and introduce a throws method:
import java.io.*;
String fileName;
}
catch(FileNotFoundException e) {
System.out.print ("Procedure to get another name and try again\n");
// Procedure to get another name and try again
}
catch(IOException e) {
System.out.print ("Procedure to try again\n");
// Procedure to try again
}
finally {
System.out.print ("Perform any cleanup\n" );
// Perform any cleanup
}
}
try {
fileName = new FileInputStream(s);
bufferedInput = new BufferedInputStream(fileName);
dataIn = new DataInputStream(bufferedInput);
}
catch(FileNotFoundException e) {
System.out.println("File Not Found");
throw e;
}
Java Exceptions 197
catch(Throwable e) {
System.out.println("Error in opening file");
}
try {
while ((line = dataIn.readLine()) != null) {
System.out.println(line + "\n");
}
fileName .close();
}
catch(IOException e) {
System.out.println("Error in reading file");
throw e;
}
}
}
Notice that we didn’t need to make many changes to the ReadAFile class used in
this application. This class can quickly be made to pass exceptions as well as
handle the ones that apply specifically to the class. The objectmyProgram, which
is an instance of the class wordProcessor, calls the method save(). This method
then calls the ReadAFile() method which declares that it will pass an exception
to the calling method in the event of an error. Because the ReadAFile() method
declares that it throws an exception, save() is required to address the exception
that is being passed to it. If the method will not handle the exception, it must
declare that it passes the particular exception on to the method that derived it:
In our example, this line of code tells the method, ReaAFile(), that two excep-
tions, FileNotFoundException and IOException, can be thrown from the try
block. This requires the save() method to handle them or declare the exceptions
to be passed on to the method main() to deal with them.
Throwing Exceptions
The throw operator declares a particular exception may be thrown from the
current method on to the calling method. This effectively passes the exception
to the next method for it to deal with. In our previous example, the ReadAFile
class declared that the method save() would pass two exceptions. In the code
that follows, the example identifies which exceptions will be thrown.
198 Chapter 7
try {
fileName = new FileInputStream(s);
bufferedInput = new BufferedInputStream(fileName);
dataIn = new DataInputStream(bufferedInput);
}
catch(FileNotFoundException e) {
System.out.println("File Not Found");
throw e;
}
catch(Throwable e) {
System.out.println("Error in opening file");
}
try {
while ((line = dataIn.readLine()) != null) {
System.out.println(line + "\n");
}
fileName .close();
}
catch(IOException e) {
System.out.println("Error in reading file");
throw e;
}
The statement throw e specifies that the exception will be passed on for the
calling method to deal with. Furthermore, much like error codes in other lan-
guages, messages can be passed along with the object to identify particular de-
tails to help process the exception. The following line of code shows how to
throw an exception with a message attached:
To reference the message in the calling method, you could simply call a
getMessage() method to read the message attached to the file. The following
code presents an example of this method:
catch(FileNotFoundException e) {
System.out.println("The file " + e.getMessage +
" was unable to be located.");
}
to our WriteAFile example, you’ll see that we deal with a couple of exceptions.
One of them caught an error that occurs in the event of an IOException by
printing a message to the command line. This notifies the user of an error when
writing to a file; but suppose WriteAFile class was a subclass in the hierarchy of
the class wordProcessor. Here is a new version of our example that has been
expanded to handle this:
import java.io.*;
// Writes to a file
public void write(String s) throws IOException {
FileOutputStream writeOut = null;
DataOutputStream dataWrite = null;
try {
writeOut = new FileOutputStream(s);
dataWrite = new DataOutputStream(writeOut);
}
catch (Throwable e) {
System.out.println("Error in opening file");
return;
}
try {
dataWrite.writeChars("This is a Test");
dataWrite.close();
}
catch(IOException e) {
System.out.println("Error in writing to file");
throw e;
}
}
import java.io.*;
wordProcessor() {
System.out.println("Create a backup file");
}
Now, lets suppose we pass a filename to the write() method and it triggers the
IOException. The IOException again writes a message to the command line,
but notice it re-throws the exception to the calling method wordProcessor().
This method then allows for an additional message to be printed, in this case
“Create a backup file.” In place of the message, we could write an additional file
to another location or do some other operation specific to the classwordProcessor.
In addition, any other class could call the method and use it to fit its needs
without being forced to perform an operation specific to wordProcessor.
To create and use your exception classes, follow the same rules as standard classes.
If you need a refresher, refer to Chapter 5. Here is a basic example of an exception:
AVirusDetectedException(String fileName) {
//perform some actions like read in libraries of virus types
while(viruslibrary != null) {
if (virus(fileName)) {
throw new AVirusDetected(NameofVirus);
//code after the throw operator is never executed.
}
}
//this code is only executed if no virus is found
}
Trying to compile the source code will only result in an error. We subclassed the
AVirusDetectedException from the Exception class because it will be triggered in the
event of an I/O operation, but it does not fall under one of the predefined excep-
tions. This is used to demonstrate how an exception would look if it were created by
you. To call this exception in your code, place the following code in your program:
try {
if (file is questioned) {
throw new AVirusDetectedException(fileName);
}
} catch (AVirusDetectedException e) {
System.out.println(e.getMessage + " has been found in " + fileName);
}
This tests whether a file was read from a disk drive, downloaded, and so on. An
exception is then thrown in the event of a virus, as declared in the exception
code above.
Chapter
8
Threads
Threads
To create Java applets and applications that
won’t turn into system resource hogs, you’ll
need to arrange your programs into separate
processes, which are called threads. 8
I magine what our lives would be like if we could only do one thing at a time.
You wouldn’t be able to listen to music and program at the same time; and you
definitely couldn’t cook dinner, watch TV, and carry on a conversation with a
friend. Although programming languages don’t need to perform tasks like these,
newer operating systems and environments like the Web are placing greater de-
mands on programs, requiring them to handle multiple processes at the same time.
Java offers an advantage over most other languages because it was designed from
the ground up to support multiple processes. When a Java applet runs in an
environment like a Web browser, the browser can determine which parts of the
program are separate processes and manage them to keep the program from
draining the available system resources. As you gain more experience writing
Java programs, you’ll learn how to structure your programs to take advantage of
the flexibility that multiple processes provide.
In this chapter we’ll examine how threads are used to create multiple processes
in Java programs. You’ll learn how to create threads using either the pre-defined
Thread class or the Runnable interface.
What Is a Thread?
One of the key jobs performed by the Java runtime system is to be able to handle
programs that contain multiple processes called threads. If you’ve done any pro-
gramming for an operating system such as Windows 95 or Windows NT, you’ve
205
206 Chapter 8
probably come across the concept called multithreading. The idea is to create
applications that can handle different tasks at the same time, or at least be able
to convince the user that multiple tasks are being performed. For example, a
multithreaded version of an application that monitors the stock market would
be able to download data from a central computer network, perform calcula-
tions in the background, and accept input from the user. Although only one
thread can be executed at a time, the operating system that runs the program
expertly divides up the different processes or threads, runs pieces of them, and
jumps from thread to thread.
If you have ever loaded a Web page that contains multiple applets, you can see the
process of multithreading at work. Assuming each applet is coded properly, your
Web browser will make it look like each one is running at the same time. Of
course, since most computers have only a single processor, the Web browser must
be able to juggle each process so that each one gets its share of processing time.
To better understand how threads are coded, let’s start with a simple example
that contains a single process. Then we’ll add to it so that you can see the effect
that using threads has on the execution of the program. In the following
Hi3Person class, the code executes in a linear fashion until the last line is reached,
and the process ends:
people.hi("Person");
people.hi("Person 2");
people.hi("Person 3");
System.out.println("Hello Everyone");
}
Code execution begins by creating an instance of the class Hi3Person. Next, the
three hi() methods are called. Each of these is executed one at a time, returning
Threads 207
control back to the main body of the code. The final statement in main() writes
the text “Hello Everyone” before the program ends.
As we introduce the concept of threads to Hi3Person, the linear path of execu-
tion will be disrupted. The program will be split into multiple processes, each
responsible for writing to the screen. Let’s look at the new version of our code to
see what is going on behind the scenes:
int i = 0;
(For now, don’t worry about the syntax used to create the threads that are used.
We’ll explain the techniques for implementing threads a little later in this chap-
ter.) Notice that the Hi3People class initiates two threads that run concurrently
as our application continues on. After each thread has been created, the start()
208 Chapter 8
method of the thread is called, which tells the Java interpreter to begin process-
ing this thread. The main() method is responsible for setting up each thread and
determining when the threads are finished. This is necessary because our pro-
gram needs to know when it is safe to execute the code starting with the line:
System.out.println(i + "\n");
Otherwise, the program will end before the threads have finished and it will
hang. In this case, we have placed a while loop to count continuously during the
execution of the threads:
If you compile and run this example, you will notice that the value stored in the
variable i will change after each execution of the code. This variable stores the
number of times the while loop repeats during the life of both threads. The fact
that this value changes illustrates the control that Java can have as it executes
programs that are divided up into separate processes. Running a single- or multi-
threaded program is not the only task that the Java runtime system must per-
form. Java also has its own internal threads that it must perform to manage tasks
such as garbage collection.
Process Process
Processor
Process
Figure 8.1
The technique of managing multiple processes.
210 Chapter 8
Creating a Thread
Before you can create a thread, you must set up a class to handle the thread. This
is done in either of two ways: extending a class (subclassing the Thread class) or
implementing an interface. As you’ll see in the next two sections, the approach
you use will depend on your own needs.
Here’s an example Java application that utilizes the Thread class as a superclass:
int i =0;
System.out.println("Hello Everyone");
t1.stop(); // End the threads
t2.stop();
}
The class Hiagain subclasses the Thread class and overrides the run() method
defined by the Thread class. Because Hiagain is derived from Thread, it inher-
its all of the methods defined in Thread including start(), run(), and stop().
The original versions of these methods defined in Thread are used except in the
case of the run() method, which has been overridden. Because this method tells
the thread which operations to perform after the thread has been started, it
typically needs to be overridden. The key methods that are defined in theThread
class will be presented later in this chapter.
The advantage of this approach is that you can create a new class that is both
derived from another class and uses the methods defined by the Runnable inter-
face. Of course, you will then be required to go along with the implementation
created by the designers of this interface. Let’s revisit our ticker tape applet in-
troduced in Chapter 2 because it provides a good example of an implementation
of the Runnable interface:
// TickerTape Class
public class TickerTape extends Applet implements Runnable{
....
// Initialize Applet
public void init(){
....
}
....
// Start Applet as thread
public void start(){
if(ttapeThread == null){
ttapeThread = new Thread(this);
212 Chapter 8
ttapeThread.start();
}
}
...
// Change coordinates and repaint
public void run(){
while(ttapeThread != null){
try {Thread.sleep(50);} catch (InterruptedException e){}
setcoord();
repaint();
}
}
....
// Stop thread then clean up before close
public void stop(){
if(ttapeThread != null)
ttapeThread.stop();
ttapeThread = null;
}
} // End TickerTape
As with all applets, you must use the Runnable interface to implement threads.
(You are forced to subclass the Applet class to perform the basic operations of
initializing and starting your applet.) The reason you would want
to implement threads in an applet is to reduce the processor load for perform-
ing operations that occur over and over. One example would be the graphics
routine in our ticker tape applet that updates the screen to make the text appear
as if it floats across the screen. The run() method is coded to redraw the screen
and then set the thread to sleep for a specified amount of time:
The reason for putting the thread to sleep is covered in more detail later in the
chapter. The two methods responsible for moving the text are setcoord() and
repaint(). They are executed as long as the thread exists.
Threads 213
Initializing a Thread
Before you can use a thread, you must initialize it by creating an instance of the
Thread class. The best way to do this is to use the constructor for the Thread
class. The simple form of this constructor is:
Thread(ObjectReference);
Thread(StringName);
Thread(ObjectReference, StringName);
In the first example, a parameter that references the object to be used to create
the thread for is provided. We actually used this type of constructor in theHiagain
class example presented earlier:
The next two constructors allow you to pass a string to create references to
individual threads, which can then be used as symbolic references. We’ll show
you how to use this feature later in this chapter to keep track of multiple threads
created from the same class instance.
If you return to the ticker tape applet outlined above, you’ll see that the thread is
created in the start() method for the applet:
In this case, notice the Thread() constructor is passed the this parameter. Using
this allows us to tell the constructor the name of the class that implements the
Runnable interface. The new thread object that is created is assigned to the
214 Chapter 8
variable ttapeThread. Once the thread has been initialized, the start() method
for the thread can be called by using the statement ttapeThread.start().
int i1 = 0;
int i2 = 0;
aThread.stop();
anotherThread.stop();
}
Both the object name (person) and a unique string is passed to each call to
Thread(). Since both threads are created using the same object, the string is
passed to assign each thread its own unique name. In the run() method of the
program, the getName() method is used to display the name of the current
thread. A companion method named setName() is provided in the Thread class
for setting the name of a thread.
Next, by changing a few lines of code, we converted our while loop to count the
time it takes to process each thread instead of counting the time it takes to
process the two together. You would need to run this code about 10 to 15 times
before running across an instance where the first person beats the second one.
This is due to the fact that Java’s scheduler is still in a beta version. (Hopefully,
Sun will consider implementing a method for determining the order in which
threads are processed.) The scheduler is responsible for determining what threads
may run and which ones must wait in the queue. This process is determined in
either one of two methods: priority or first in first out (FIFO).
Each of these variables holds integer values that specify a thread’s priority level.
For example, MAX_PRIORITY stores a number that indicates the maximum
allowable value for a thread’s priority. To set or retrieve the current priority set-
ting of a thread, the Thread class provides the setPriority() and getPriority()
methods. In setting priorities, you can use one of the three priority instance
variables. For example, the following method call would set a thread’s priority to
the value contained in the NORM_PRIORITY variable:
In this example the start() method checks to see if the thread ttapeThread ex-
ists. If it doesn’t, it creates an instance of the Thread class and assigns the vari-
able ttapeThread to it.
Threads 217
NEW BORN
Runnable
Blocked Running
DEAD
Figure 8.2
The cycle of life pertaining to a thread.
In this example, the run() method makes the process sleep for 50 milliseconds
while the instance of the class named ttapeThread is not equal to null. Then,
the setcoord() method is called followed by the repaint() method.
218 Chapter 8
In the run() method we just presented, the sleep() method is called to allow other
threads to be processed while the ttapeThread is put on hold. This allows the browser
to accept other input and not redraw the screen every instance of the thread.
This line of code states that in the event of a mouse click and the thread is
running, the thread will be suspended from operation. This allows other threads
in the queue to be processed; but as soon as the thread is reactivated, it will
resume its place in the queue as long as a higher priority thread is not executing.
If the thread exists, the setcoord() method is executed followed by the repaint()
method. Then the yield() method is called to permit the next thread in line to
execute. Unfortunately, this is not wise if we are to depend on a scheduled re-
paint(). We could fall victim to the mercy of the threads that will be placed
before the current thread that is moved to the end of the queue.
In the event that the end of the process is reached, this method is called to clean
up after the thread and perform any final procedures before closing out.
220 Chapter 8
In the event that the stop() method of the applet is called, the thread ttapeThread
will be destroyed and no further lines of code for that object will be executed.
Synchronizing Revisited
If you recall from Chapter 5, we showed you how to declare a synchronized
method. If you don’t remember, here is the syntax.
The synchronized modifier is used to declare a method of which only one ob-
ject can execute at any one time. This is accomplished by the Java Virtual Ma-
chine setting up an object monitor for every portion of code that declares itself
as synchronized. In order for the code to run, the object must attain this moni-
tor. In the event that a thread wants to run a synchronized section of code, it is
Threads 221
blocked until the thread ahead of it finishes executing the particular section of
code. Let’s look at an example of how the synchronized techniques works:
import java.awt.*;
import java.lang.*;
MyApp2() {
// Calls the parent constructor Frame(string title)
// Same as setTitle("Duck Duck Goose");
super("Counting example");
pack();
show();
}
int i = 0;
person1.start();
person2.start();
}
222 Chapter 8
switch(evt.id) {
case Event.WINDOW_DESTROY: {
System.exit(0);
return true;
}
default:
return false;
}
}
}
The above code initiates two threads that cycle through the synchronized run()
method. When you compile this program, you will see the first thread, per-
son1, count up to 99, followed by the next thread, person2, count up to 99
and end. The thread person2 must wait until the monitor is released by the
previous thread before executing. While this process is occurring, notice that
the counter timing the execution of the synchronized threading event is run-
ning alongside.
any one time. This is easily remedied by using the wait() method, which causes
the currently executing method to release the monitor to the next thread. The
thread that released the monitor can then reacquire the monitor when the no-
tify() method is called from within the same method. The thread waiting then
picks up right from the point where it began waiting. Let’s modify our previous
example MyApp2 to utilize the wait() and notify() methods:
After compiling the class again and running it, you will notice that the first
thread counts to 50. The thread person1 then releases the monitor to the next
thread, person2. The thread then counts up to 99 and notifies the previous
thread to begin executing from where it left off.
a class just like the one the threads are derived from. You can create a
ThreadGroup the same way you initialize any class in Java:
This allows for quick subgrouping of like threads. There are three main advan-
tages to subgrouping threads:
• Controlling the states of all the threads contained within the group without
having to individually set each one.
• Retrieving all the threads in the group easily so that you can identify a thread
quickly.
• Setting the priority of all the threads within the group with one command
to the group.
Note: Setting the priority of the ThreadGroup only effects the threads of less
priority than the calling method. If a thread is currently set at a high prior-
ity, it will continue at this level until it dies.
Chapter
9
The Java AWT
The Java
AWT
If you’re wondering where to look for infor-
mation on creating interface components for
Java programs, you’ve come to the right place.
The AWT provides a treasure chest of power-
ful interface classes.
9
No one would use a programming language these days if it did not have built-
in support for common user interface objects like windows, menus, dialogs, and
buttons. Fortunately, the designers of Java did not overlook this. They created a
package called the Abstract Window Toolkit or AWT, which allows Java program-
mers to build GUIs very easily. Although AWT is very flexible and powerful, its
shear size will overwhelm you until you understand how it is organized and the
basics for using it.
To help you get more out of the AWT, we’ll look at how the AWT is arranged.
Then we’ll present each of the key AWT classes. We’ll show you how to use the
layout manager, and we’ll present the basics for creating interface components
such as menus. If we tried to cover the AWT in a lot of detail, we could easily
turn this chapter into an entire book. However, since Java is still a very young
language and much of the AWT is still being solidified, we will only cover enough
of this library to get you started with the AWT so that you can use it effectively.
You’ll want to keep your browser tuned to Sun’s Java site for the latest informa-
tion on this powerful package.
227
228 Chapter 9
braries. This is because Java is a cross-platform language, and the tools provided
with any Java library must be designed so that they can work with all systems.
As you build more complex applets and applications, you will find it difficult to
not use the AWT because of its extreme flexibility. If a component such as a
window or menu doesn’t do what you need, you can simply subclass it and add
your own custom features.
To use the AWT in a Java applet or program, you must first import the AWT
package by using the import statement as shown here:
The asterisk (*) is used with the import statement to tell the Java compiler to
include all classes in the immediate subdirectory. Once you include this pack-
age, you can use any of the AWT controls or packages to derive your own. With
just a little bit of programming effort, you’ll be amazed at the types of interface
components you can create for your Java applications—everything from scrollable
windows to fully functional pop-up menus.
Here’s an example of a simple Java program that displays a window that contains
a text message:
AWT controls are descendants from the Component class, they all share some of
the same key methods such as createImage(), disable(), and hide(). Figure 9.1
presents a tree that illustrates the class hierarchy for the controls of the AWT and
Table 9.1 lists the complete set of classes.
If you have done any graphics or interface programming before, some of these
class names should be somewhat familiar to you. Instead of reinventing the wheel,
the developers of Java used traditional user interface components—windows,
dialogs, scrollbars, and so on—to build up the AWT. Of course, you’ll find that
the AWT heavily embraces object-oriented programming techniques.
• Component
♦ Button
♦ Canvas
♦ Checkbox
♦ Choice
♦ Container
• Panel
• Window
◊ Dialog
◊ Frame
♦ Label
♦ List
♦ Scrollbar
♦ TextComponent
• TextArea
• TextField
Figure 9.1
The class hierarchy of the AWT.
The Java AWT 231
available in this class. However, there are a few methods that are important, and
you will probably use them for all the controls that subclass the Component
class. We’ll introduce these methods next, and we’ll examine some of the key
event handling methods in Chapter 10.
BOUNDS()
This method returns the current rectangular bounds of the component.
DISABLE()
This method disables a component.
ENABLE([BOOLEAN])
This method enables a component. You can pass zero arguments, or a Boolean
argument to enable or disable a control. Here’s a few examples of how this method
can be called:
myComponent.enable();
myComponent.enable(x==1);
GETFONTMETRICS()
This method gets the font metrics for the component. It returns null if the
component is currently not on the screen.
GETGRAPHICS()
This method gets a graphics context for the component. This method returns
null if the component is currently not on the screen. This method is an absolute
necessity for working with graphics.
GETPARENT()
This method gets the parent of the component.
HANDLEEVENT(EVENT EVT)
This method handles all window events. It returns true if the event is handled
and should not be passed to the parent of the component. The default event
handler calls some helper methods to make life easier on the programmer. This
method is used to handle messages from the operating system.
The Java AWT 233
HIDE()
This method hides the component. It performs the opposite operation of show().
INSIDE(INT X, INT Y)
This method checks to see if a specified x,y location is “inside” the component.
By default, x and y are inside a component if they fall within the bounding box
of that component.
ISE NABLED()
This method checks to see if the component is enabled. Components are ini-
tially enabled.
ISSHOWING()
This method checks to see if the component is showing on screen. This means
that the component must be visible, and it must be in a container that is visible
and showing.
ISVISIBLE()
This method checks to see if the component is visible. Components are initially
visible (with the exception of top level components such as Frame).
LOCATE(INT X, INT Y)
This method returns the component or subcomponent that contains the x,y
location. It is very useful for checking for mouse movement or mouse clicks.
LOCATION()
This method returns the current location of the component. The location will
be specified in the parent’s coordinate space.
MOVE(INT X, INT Y)
This method moves the component to a new location. The x and y coordinates
are in the parent’s coordinate space.
REPAINT([TIME])
This method repaints the component. This will result in a call to the update()
method as soon as possible. You can specify a time argument so that Java knows that
you want the component repainted within a specified number of milliseconds. You
234 Chapter 9
can also update just a certain portion of a control by sending the x and y coordi-
nates that specify where you want to start the update and a width and height
that specify how much to update. Here are some examples:
// Regular update
myComponent.update();
// Update rectangle
myComponent.update(50, 50, 200, 200);
myComponent.resize(300, 200);
SETFONT(FONT)
This method sets the font of the component. The argument passed is a Font
object. For example, this method call
would change the font of myComponent to a Helvetica type face with no bolding
or italics or underline and a point size of 12.
SHOW([BOOLEAN])
This method “shows” the component. By calling this method you make a
control visible or not. It can also be passed a conditional statement. Here are a
few examples:
myComponent.show();
myComponent.show(x==1);
The Java AWT 235
SIZE()
This method returns the current size of the component. The size is returned in
dimensions of width and height.
Figure 9.2
A simple windowed Java application.
In the main() method we use our class’s constructor to create our object named
Test. Then we call the object’s show() method to make the window frame visible
(frames are invisible by default). If you were running this Java program in Win-
dows 95, you’d see a window that looks like the one shown in Figure 9.2.
As you can see, the window is quite simple. You need to use several of the Frame
class’s methods to make the frame useful. The other thing you may notice is that
when you try and close the window and terminate the program, nothing hap-
pens! That’s because you have not told Java to do it. You need to add an event
handling method to catch windows messages. In this case, we are looking for the
WINDOW_DESTROY call from the operating system. Here is the extended
code that sets the sizes of the frame, gives it a title, and catches messages:
import java.awt.*;
public winTest1() {}
Figure 9.3
A fully functioning application using a frame.
We are gong to discuss event handling in more detail in the next chapter, so
don’t get worried if you do not understand that part of the above code.
What you should notice is the two new calls to two of the frames methods:
setTitle() and resize(). These methods perform the function they are named
after; they set the title of our application and resize it respectively.
Let’s look at the methods that are specific to the Frame class.
GETICONIMAGE()
This method returns the icon image for the frame.
GETMENUBAR()
This method gets the menu bar for the frame.
GETTITLE()
This method gets the title of the frame.
238 Chapter 9
ISRESIZABLE()
This method returns true if the user can resize the frame.
REMOVE(MENUCOMPONENT M)
This method removes the specified menu bar from the frame.
SETCURSOR(IMAGE IMG )
This method sets the current cursor image that will be used while the cursor is
within the frame.
SETICONIMAGE(IMAGE IMG)
This method sets the image to display when the frame is iconized. Note that not
all platforms support the concept of iconizing a window. The icon will also be
displayed in the title window in Windows 95.
SETMENUBAR(MENUBAR MB)
This method sets the menu bar for the frame to the specified MenuBar.
SETRESIZABLE(BOOLEAN BOOL)
This method sets the resizable flag.
SETTITLE(STRING TITLE)
This method sets the title for the frame to the specified title.
Let’s look at an example. Assume you have a frame that you want to fill with a
text field in the upper part of the frame, and three buttons lined up along the
bottom. If you only used a single layout class for the entire form, you would not
have enough control to do this. Figure 9.4 illustrates what we want the frame to
look like. Figure 9.5 and 9.6 shows the best you can achieve using a single layout
class. This is not bad, but if you resize the frame the layout gets pretty ugly.
What we need to be able to do is use one type of layout class for the upper part
of the frame, and another for the bottom. We can do this by using a pair of
panels, one for the top using a border style layout and another panel for the
bottom using a flow style layout. Now, when we add our controls, we add them
to their respective panels instead of the frame, and everything is taken care of for
Figure 9.4
Creating a window using the Panel class.
Figure 9.5
A close approximation with a single layout class.
Figure 9.6
Resizing the Panel.
240 Chapter 9
us. The user can resize the control all they want and our controls will stay where
we placed them originally. Here is the code that performs this new configura-
tion. The output is shown in Figure 9.7.
import java.awt.*;
public mixLayout() {
super("Mixed Layout Demo");
setLayout(new BorderLayout());
Panel top = new Panel();
Panel bottom = new Panel();
top.setLayout(new BorderLayout());
top.add("Center", new TextArea("HelloWorld", 15, 5));
bottom.setLayout(new FlowLayout());
bottom.add(new Button("Load"));
bottom.add(new Button("Save"));
bottom.add(new Button("Quit"));
add("Center", top);
add("South", bottom);
resize(300, 200);
show();
}
public static void main(String args[]) {
mixLayout test = new mixLayout();
}
Figure 9.7
The new two-panel program with different layout methods.
SETLAYOUT(LAYOUT MANAGER)
As you have already seen, the setlayout() method is used to define which layout
manager will be used to place controls on the panel. If you do not set a layout
manager, the panel control defaults to flowLayout().
We can also assign the text string to an object variable like this:
Table 9.2 shows the three ways you can declare a Label class.
GETALIGNMENT()
This method returns the current alignment of the label.
GETTEXT()
This method does what it sounds like—it returns the text the label is displaying.
SETALIGNMENT(INT)
This method changes the alignment of the label. The argument is the same as
the one used with Label.LEFT, Label. CENTER, and Label.RIGHT (see Table
9.2 for more information).
Figure 9.8 shows a few labels with different alignments. Here is the code used to
produce them:
Figure 9.8
The Label component.
SETTEXT(STRING)
This method sets or changes the displayed text.
Button Class
The Button class is one of the most often used classes, for obvious reasons.
How often do you see Windows or Mac programs without some sort of
button somewhere?
Buttons are UI components that trigger actions when they are pressed. They
have multiple states to provide feedback to the user. The neat thing about but-
tons (and all the UI elements for that matter) is that a button you create for a
Java program will change its appearance depending on the operating system.
That’s one of the benefits of cross-platform. A button on your application or
applet will look like a standard Windows button on a PC. Or, it will look like a
standard Mac button on a Mac. The disadvantage here is that if you create other
elements that are dependent on the size and/or shape of the graphics for your
button, then you will run into trouble.
Figure 9.9 illustrates a few different buttons. Notice that the size of the buttons
depends on the length of the caption.
Figure 9.9
A few Button components.
GETLABEL()
This method returns the current caption of the button.
SETLABEL()
This method changes the caption of the button.
The real power behind buttons is realized when you handle the events a button
triggers. This is usually handled in the handleEvent() method that we will be
showing you how to use in the next chapter.
new Canvas();
import java.awt.*;
public testMe() {
super("Checkbox Demo");
Panel P1 = new Panel();
Panel P2 = new Panel();
CheckboxGroup G1 = new CheckboxGroup();
setLayout(new GridLayout(1,2));
add(P1);
add(P2);
P1.setLayout(new FlowLayout());
P1.add(new Checkbox("E-Mail Tom"));
P1.add(new Checkbox("E-Mail Jack"));
P2.setLayout(new FlowLayout());
246 Chapter 9
new Checkbox();
new Checkbox(String);
Constructs a checkbox with the specified label, no checkbox group, and initial-
izes it to a false state.
Figure 9.10
A few iterations of the Checkbox component.
The Java AWT 247
new Checkbox(String, boolean);
Constructs a checkbox with the specified label, no checkbox group, and initial-
izes it to a specified boolean state.
Constructs a checkbox with the specified label, specified checkbox group, and
initializes it to a specified boolean state.
GETCHECKBOXGROUP()
This method returns the checkbox group that this checkbox belongs to.
GETLABEL()
This method gets the label of the button.
GETSTATE()
This method returns the boolean state of the checkbox.
SETCHECKBOXGROUP(CHECKBOXGROUP)
This method sets the CheckboxGroup of the check box.
SETLABEL(STRING)
This method changes the label of the checkbox.
SETSTATE(BOOLEAN)
This method sets the checkbox to the specified boolean state.
Here is the code that creates the Choice component shown in Figures 9.11
and 9.12:
import java.awt.*;
public testMe() {
super("Choice Demo");
Choice C1 = new Choice();
setLayout(new FlowLayout());
add(C1);
C1.addItem("You");
C1.addItem("Me");
C1.addItem("Them");
C1.addItem("Us");
C1.addItem("Everyone");
resize(300, 200);
show();
}
new Choice();
Figure 9.11
The Choice component without the focus.
Figure 9.12
The Choice component with the focus.
ADDITEM(STRING )
This method adds an item to the list of choices.
COUNTITEMS ()
This method returns the number of items.
GETITEM(INT)
This method returns the item at the specified index.
GETSELECTEDINDEX()
This method returns the index of the currently selected item.
GETSELECTEDITEM()
This method returns a string representation of the current choice.
SELECT(INT)
This method selects the item with the specified index position.
250 Chapter 9
SELECT(STRING)
This method selects the item with the specified String if present.
import java.awt.*;
public testMe() {
super("List Demo");
List L1 = new List();
setLayout(new FlowLayout());
add(L1);
L1.addItem("You");
L1.addItem("Me");
L1.addItem("Them");
L1.addItem("Us");
L1.addItem("Everyone");
resize(300, 200);
show();
}
Figure 9.13
Create lists with the List class.
new List();
Creates a scrolling list initialized with no visible lines and multiple selections
disabled.
Creates a new scrolling list initialized with the specified number of visible lines
and a boolean stating if multiple selections are allowed or not.
ADDITEM(STRING )
This method adds the specified item to the end of list.
ALLOWSMULTIPLESELECTIONS()
This method returns true if the list allows multiple selections.
CLEAR()
This method clears the list.
252 Chapter 9
COUNTITEMS ()
This method returns the number of items in the list.
DELITEM(INT)
This method deletes an item from the list at the specified index.
This method deletes multiple items from the list. Items are deleted from the
index position specified by the first parameter to the index position specified by
the second parameter.
DESELECT(INT)
This method deselects the item at the specified index.
GETITEM(INT)
This method gets the item associated with the specified index.
GETROWS()
This method returns the number of visible lines in the list.
GETSELECTEDINDEX()
This method returns the selected item in the list or -1 if no item is selected.
GETSELECTEDINDEXES()
This method returns the selected indexes in the list in the form of an array.
GETSELECTEDITEM()
This method returns the selected item in the list or null if no item is selected, or
it returns the first selected item if multiple items are selected.
GETSELECTEDITEMS()
This method returns the selected items in the list into an array of strings.
GETVISIBLEINDEX()
This method gets the index of the item that was last made visible by the method
makeVisible().
The Java AWT 253
ISSELECTED(INT)
This method returns true if the item at the specified index has been selected;
false otherwise.
MAKEVISIBLE(INT)
This method forces the item at the specified index to be visible. The method
automatically scrolls the list to display the specified index.
MINIMUMSIZE()
This method returns the minimum dimensions needed for the list.
MINIMUMSIZE(INT)
This method returns the minimum dimensions needed for the number of rows
in the list.
PREFERREDSIZE()
This method returns the preferred dimensions needed for the list.
PREFERREDSIZE(INT)
This method returns the preferred dimensions needed for the list with the speci-
fied amount of rows.
SELECT(INT)
This method selects the item at the specified index.
SETMULTIPLESELECTIONS(BOOLEAN)
This method sets up a list to allow for multiple selections or not.
95 user, the components even support the right mouse button. If you right-click
within a text field or text area, a pop-up menu will be displayed like the one
shown in Figure 9.14.
new TextField();
new TextField(int);
TextField(String)
Figure 9.14
Right-clicking on a TextField component to display a pop-up menu.
The Java AWT 255
new TextField(String, int);
Creates a new TextField initialized with the specified text and number of columns.
new TextArea();
Creates a new TextArea with the specified number of rows and columns.
new TextArea(String);
Creates a new TextArea with the specified text and the specified number of rows
and columns.
GETSELECTIONEND()
This method returns the selected text’s end position.
GETSELECTEDTEXT()
This method returns the selected text contained in the text component.
GETSELECTIONSTART()
This method returns the start position of the selected text. If no text is selected,
the method returns -1.
GETTEXT()
This method returns the text contained in the text component.
256 Chapter 9
ISE DITABLE()
This method returns a boolean value that tells us if the text component is editable
or not. Text components are editable by default.
SELECT(INT, INT)
This method selects the text found between the specified start and end loca-
tions.
SELECTALL()
This method causes all of the text in the text component to be selected.
SETEDITABLE(BOOLEAN)
This method sets whether or not this text component can be edited.
SETTEXT(STRING)
This method changes the text of the text component to the specified text.
Now, let’s look at a few methods that are specific to the TextField component:
ECHOCHARISSET()
This method returns true if the TextField has a character set for echoing. Echo-
ing is used for situations where you do not want the text people are typing to be
displayed.
GETCOLUMNS()
This method returns the number of columns in the TextField.
GETECHOCHAR()
This method returns the character to be used for echoing. The character is not
returned in a String format, just a simple char.
MINIMUMSIZE()
This method returns the minimum size dimensions needed for the TextField in
columns.
MINIMUMSIZE(INT)
This method is used to request a minimum size for the text box. The parameter
specifies the number of columns for the text box. The method returns the mini-
The Java AWT 257
mum size dimensions needed for the TextField with the specified amount of
columns.
PREFERREDSIZE()
This method returns the preferred size dimensions needed for the TextField class.
PREFERREDSIZE(INT)
This method returns the preferred size dimensions needed for the TextField
with the specified amount of columns being passed to it.
SETECHOCHARACTER(CHAR)
This method sets the echo character for the TextField. Most often you’ll want to
set this character to the asterisk symbol, especially if you are working with pass-
word boxes.
Now, we need to look at the methods specific to the TextArea class:
GETCOLUMNS()
This method returns the number of columns in the TextArea.
GETROWS()
This method returns the number of rows in the TextArea.
INSERTTEXT(STRING, INT)
This method inserts the specified text at the specified position. The position tells
Java the number of characters it needs to move over before it inserts the string.
PREFERREDSIZE()
This method returns the preferred size dimensions of the TextArea.
PREFERREDSIZE(INT, INT)
This method returns the row and column dimensions of the TextArea.
MINIMUMSIZE()
This method returns the minimum size dimensions of the TextArea.
MINIMUMSIZE(INT, INT)
This method returns the specified minimum size dimensions of the TextArea.
258 Chapter 9
Figure 9.15
A typical Java scrollbar.
The Java AWT 259
Figure 9.16
A Scrollbar control and a Textfield control with linked values.
And, here is the code for the entire application. Type it in and give it a try:
import java.awt.*;
Keep in mind that the scrollbar, like all the other controls, will change its ap-
pearance to match the operating system. Obviously, you would not want Win-
dows 95 style scrollbars being displayed on a Macintosh. That would sure cause
a commotion!
new Scrollbar();
new Scrollbar(int);
Constructs a new Scrollbar with the specified orientation. You can specify
Scrollbar.HORIZONTAL or Scrollbar.VERTICAL. Scrollbars are vertical
by default.
Creates a new Scrollbar with the specified orientation, current value, large change
size, minimum value, and maximum value.
GETMAXIMUM()
This method returns an integer representing the maximum value of the scrollbar.
GETMINIMUM()
This method returns an integer representing the minimum value of the scrollbar.
The Java AWT 261
GETORIENTATION()
This method returns an integer that gives us the orientation for the scrollbar.
You can check the returned integer against Scrollbar.HORIZONTAL and
Scrollbar.VERTICAL to determine the scrollbar’s orientation.
GETVALUE()
This method returns an integer representing the current value of the scrollbar.
GETVISIBLE()
This method returns the visible amount of the scrollbar.
SETVALUE(INT)
This method sets the value of the scrollbar to the specified value. If you try to set
the current value to a number that is greater than the maximum or less than the
minimum, the number becomes the new maximum or minimum, respectively.
Building Menus
Menus in Java are as easy to build and manage as the other visual components.
Every part of a menu, from the menu bar to individual items is represented as a
separate class, each having specialized properties and methods. Let’s start our
investigation of menus with the main component—the menu bar. Then, we’ll
work our way down into the other more specialized components, such as a menu
itself and menu items.
262 Chapter 9
new MenuBar();
COUNTMENUS()
This menu returns an integer representing the number of menus on the
menu bar.
GETHELPMENU()
This method returns the name of the menu component on the current menu
bar that has been designated as the “Help” menu. Help menus are discussed in
the next section in more detail.
The Java AWT 263
GETMENU(INT)
This menu gets the specified menu. Input is an integer representing the index
position of a menu and it returns a Menu object.
REMOVE(INT)
This method removes the menu located at the specified index from the menu bar.
REMOVE(MENU)
This method removes the specified menu from the menu bar.
SETHELPM ENU(MENU)
This method sets the current help menu to the specified menu on the menu bar.
Figure 9.17
Examples of menus created with the Menu class.
264 Chapter 9
new Menu(String);
Constructs a new Menu with the specified string as the label. This menu will
not be able to be “torn off.” Tear-off menus are menus that will still appear on
the screen after the mouse button has been released.
Constructs a new Menu with the specified label. The menu will be able to be
torn off if the boolean value is set to true.
ADD(MENUITEM )
This method adds the specified item to the menu.
ADD(STRING)
This method adds an item with the specified label to the menu.
ADDSEPARATOR()
This method adds a separator line to the menu at the current position.
COUNTITEMS ()
This method returns the number of elements in the menu as an integer.
GETITEM(INT)
This method returns the menu item located at the specified index of the menu.
ISTEAROFF()
This method returns true if the menu is a tear-off menu.
REMOVE(INT)
This method deletes the item at the specified index from the menu.
The Java AWT 265
REMOVE(MENUITEM)
This method deletes the specified item from the menu.
import java.awt.*;
Figure 9.18
Creating cascading menus using Menus as subclasses.
except that it provides the ability to be “checked” or “unchecked” when the user
clicks on a menu item. Figure 9.19 shows an example of this component.
new MenuItem(String);
Figure 9.19
Using the CheckboxMenuItem to check and uncheck menu items.
The Java AWT 267
This class constructs a new MenuItem with the specified String displayed as the
menu component’s label. Note that the hyphen symbol (-) is reserved to mean a
separator between menu items. Separators should do nothing except delineate
different sections of a menu.
DISABLE()
This method makes the menu item “unselectable” by the user and grays it out.
ENABLE()
This method makes the menu item “selectable” by the user. The user is given a
visual cue when the menu is disabled because it is grayed out.
ENABLE(BOOLEAN)
This method conditionally enables a component.
GETLABEL()
This method gets the label for the menu item. The value is returned as a string.
ISE NABLED()
This method checks to see if the menu item is enabled. The return value is a
boolean value.
SETLABEL()
This method sets the label to be the specified string.
The following two methods are used only with the CheckboxMenuItem component.
GETSTATE()
This method returns a boolean value that represents the state of the menu item.
SETSTATE(BOOLEAN)
This method sets the state of the menu item.
268 Chapter 9
import java.awt.*;
You my notice that we used two different methods for creating the two separa-
tors in the “File” menu. The addSeparator() method is probably easier. How-
ever, if using the standard add() method with the hyphen character, you can
create a full-fledged menu item that you can then change options for and set up
so that it can respond to mouse clicks. Now that you’ve seen the basics for
creating menus and GUI objects, you’ll need a way to position them within the
frames you build. And that’s where the layout manager comes in.
Figure 9.20
Menu test app view #1.
270 Chapter 9
Figure 9.21
Menu test app view #2.
Figure 9.22
Menu test app view #3.
• FlowLayout
• BorderLayout
• GridLayout
• GridBagLayout
• CardLayout
The layout manager is actually just an Interface. You then create classes that
implement the LayoutManager interface. These classes are used by the AWT
and your program to get the look and feel you want for the user. Let’s look at
each of the layout manager classes in detail.
Any component that is a container in Java can use a different layout. So, you
could have a Frame that uses one class to lay out two panels which each have
their own layouts, and so on.
Figure 9.23
Using the FlowLayout class to lay out some buttons.
Figure 9.24
The same panel resized so that the buttons wrap to the next row.
import java.awt.*;
LayoutFrame() {
super("Layout Test");
setLayout(new FlowLayout());
add(new Button("Button 1"));
add(new Button("Button 2"));
add(new Button("Button 3"));
add(new Button("Button 4"));
add(new Button("Button 5"));
resize(300,200);
show();
}
The Java AWT 273
public static void main(String args[]) {
LayoutFrame lf = new LayoutFrame();
}
}
Here we call the setLayout() method of the Frame we have extended, sending it
a new instance of the FlowLayout class. The frame will then query the FlowLayout
object where to position each component. This query happens whenever the
window needs to be refreshed, such as when it is resized or uncovered.
LAYOUTCONTAINER(CONTAINER)
This method lays out the container. It will actually reshape the components in
the target container to satisfy the constraints of the FlowLayout object.
MINIMUMLAYOUTSIZE (CONTAINER)
This method returns the minimum dimensions needed to lay out the compo-
nents contained in the specified target container. These dimensions are extremely
useful because they can help you ensure that the user will not shrink the con-
tainer to such a small size that it forces some of the UI components to slip off the
visible screen.
PREFERREDLAYOUTSIZE(CONTAINER)
This method returns the preferred dimensions for this layout given the compo-
nents in the specified target container. The return value is a Dimension variable
consisting of two values representing the width and height of the layout.
TOSTRING()
This method returns a string representation of this FlowLayout’s values, includ-
ing: (in this order) X position, Y position, container dimensions, layout class
being used, whether or not the container can be resized, and the title of
the container.
274 Chapter 9
LayoutFrame() {
super("Layout Test");
setLayout(new BorderLayout());
add("North", new Button("North"));
add("East", new Button("East"));
add("South", new Button("South"));
add("West", new Button("West"));
add("Center", new Button("Center"));
resize(300,200);
show();
}
The first change is obviously the switch to specifying the BordeLayout() class as
our layout scheme. The other changes occur in the add() method. What are
Figure 9.25
The BorderLayout() class in action.
The Java AWT 275
those extra strings doing there? They specify which side of the container to place
the new control. In this case, we are using buttons with labels that match the
position names (North, East, South, West, and Center). We used buttons here
for clarity sake, but you would probably not use them for any real projects.
Panel components are probably the best for this type of layout. You would specify
a few panels using a border style layout and then use a different layout scheme
for the individual panels. Since panels are for design purposes mostly—they do
not show up since they default to the same color as the background of the frame—
they blend in perfectly and bring the whole thing together.
new BorderLayout();
Constructs a BorderLayout with the specified gaps. The first integer represents
the horizontal gap to be placed between components and the second integer
represents the vertical gap to be used.
ADDLAYOUTCOMPONENT(STRING, COMPONENT)
This method adds the specified named component to the layout. The String
argument gives us a name to refer to the component within the layout. The
component can be any type of interface component we want to add.
LAYOUTCONTAINER(CONTAINER)
This method lays out the specified container. It will actually reshape the compo-
nents in the specified target container to satisfy the constraints of the
BorderLayout object.
276 Chapter 9
MINIMUMLAYOUTSIZE(C ONTAINER)
This method returns the minimum dimensions needed to lay out the compo-
nents contained in the specified target container. The return value is a dimen-
sion variable.
PREFERREDLAYOUTSIZE(CONTAINER)
This method returns the preferred dimensions for the layout given the compo-
nents in the specified target container. The method also returns a dimension
style variable.
REMOVELAYOUTCOMPONENT(COMPONENT)
This method removes the specified component from the layout.
TOSTRING()
This method returns the string representation of the BorderLayout’s values. At
this point in the development of Java, this method only returns the size of the
horizontal and vertical gaps.
Figure 9.26
Using the GridLayout() class to create a sample frame.
The Java AWT 277
Creates a grid layout with the specified rows, columns, horizontal gap, and ver-
tical gap.
ADDLAYOUTCOMPONENT(STRING, COMPONENT)
This method adds the specified named component to the layout. The String
argument gives us a name to refer to the component within terms of the layout.
The component can be any interface component you want to add.
LAYOUTCONTAINER(CONTAINER)
This method lays out the specified container. It will actually reshape the compo-
nents in the specified target container to satisfy the constraints of theGridLayout
object.
MINIMUMLAYOUTSIZE(CONTAINER)
This method returns the minimum dimensions needed to lay out the components
contained in the specified target container. The return value is a dimension variable.
278 Chapter 9
PREFERREDLAYOUTSIZE(CONTAINER)
This method returns the preferred dimensions for this layout given the compo-
nents in the specified target container. It also returns a dimension style variable.
REMOVELAYOUTCOMPONENT(COMPONENT)
This method removes the specified component from the layout.
TOSTRING()
This method returns the string representation of the GridLayout’s values. At
this point in the development of Java, this method only returns the size of the
horizontal and vertical gaps.
• fill Used when the component’s display area is larger than the component’s
requested size to determine whether (and how) to resize the component.
• ipadx, ipady Specifies the internal padding. Padding represents the amount
of space to add to the minimum size of the component. The width of the
component will be at least its minimum width plus ipadx*2 pixels (since the
padding applies to both sides of the component). Similarly, the height of the
component will be at least the minimum height plus ipady*2 pixels.
• insets Sets the external padding of the component—the minimum amount
of space between the component and the edges of its display area.
• anchor Used when the component is smaller than its display area to deter-
mine where to place the component. Valid values are:
Figure 9.27
Sample program using the GridBagLayout class.
280 Chapter 9
It is probably easiest to give you an example. Figure 9.27 shows the layout we
wish to end up with. Following it is the code that we used to create it:
import java.awt.*;
import java.util.*;
GridBagTest() {
super("GridBag Test");
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
setFont(new Font("Helvetica", Font.PLAIN, 14));
setLayout(gridbag);
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
makebutton("Button1", gridbag, c);
makebutton("Button2", gridbag, c);
makebutton("Button3", gridbag, c);
c.gridwidth = GridBagConstraints.REMAINDER; //end row
makebutton("Button4", gridbag, c);
c.weightx = 0.0; //reset to the default
makebutton("Button5", gridbag, c); //another row
c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row
makebutton("Button6", gridbag, c);
c.gridwidth = GridBagConstraints.REMAINDER; //end row
makebutton("Button7", gridbag, c);
c.gridwidth = 1; //reset to the default
c.gridheight = 2;
c.weighty = 1.0;
makebutton("Button8", gridbag, c);
c.weighty = 0.0; //reset to the default
c.gridwidth = GridBagConstraints.REMAINDER; //end row
c.gridheight = 1; //reset to the default
makebutton("Button9", gridbag, c);
makebutton("Button10", gridbag, c);
resize(300, 100);
show();
}
new GridBagLayout();
DUMPCONSTRAINTS(GRIDBAGCONSTRAINTS)
This method prints the layout constraints to the System object. It is useful for
debugging.
GETCONSTRAINTS(C OMPONENT)
This method returns a copy of the GridBagConstraints object for the specified
component.
LAYOUTCONTAINER(CONTAINER)
This method lays out the specified container. This method will actually reshape
the components in the specified target container to satisfy the constraints of the
GridBagLayout object.
LOOKUPCONSTRAINTS(COMPONENT)
This method retrieves the constraints for the specified component. The return
value is not a copy, but is the actual constraints class used by the layout mecha-
nism. The object returned by this method can then be altered to affect the looks
of the component.
MINIMUMLAYOUTSIZE(CONTAINER)
This method returns the minimum dimensions needed to lay out the compo-
nents contained in the specified target container. The return value is a dimen-
sion variable.
282 Chapter 9
PREFERREDLAYOUTSIZE(CONTAINER)
This method returns the preferred dimensions for this layout given the compo-
nents in the specified target container. It also returns a dimension style variable.
SETCONSTRAINTS(COMPONENT, GRIDBAGCONSTRAINTS)
This method sets the constraints for the specified component.
TOSTRING()
This method returns the string representation of the GridBagLayout’s values.
At this point in the development of Java, this method only returns the size of the
horizontal and vertical gaps.
new CardLayout();
// Creates a new card layout.
new CardLayout(int, int);
Creates a card layout with the specified horizontal and vertical gaps.
ADDLAYOUTCOMPONENT(STRING, COMPONENT)
This method adds the specified named component to the layout. The String
argument gives us a name to refer to the component within terms of the layout.
The component can be any interface component you want to add.
FIRST(CONTAINER)
This method flips to the first card. The argument is the parent container that
you assigned the layout style to.
LAST (CONTAINER)
This method flips to the last card of the specified container.
LAYOUTCONTAINER(CONTAINER)
This method lays out the specified container. This method will actually reshape
the components in the specified target container to satisfy the constraints of the
CardLayout object.
MINIMUMLAYOUTSIZE(CONTAINER)
This method returns the minimum dimensions needed to layout the compo-
nents contained in the specified target container. The return value is a dimen-
sion variable.
NEXT(CONTAINER)
This method flips to the next card in the stack.
PREFERREDLAYOUTSIZE(CONTAINER)
This method returns the preferred dimensions for the layout given the com-
ponents in the specified target container. This also returns a dimension style
variable.
PREVIOUS(CONTAINER)
This method flips to the previous card.
REMOVELAYOUTCOMPONENT(COMPONENT)
This method removes the specified component from the layout.
284 Chapter 9
SHOW(CONTAINER, STRING)
This method flips to the specified component name in the specified container.
This method is best used when you cannot use any of the previous four methods
and/or you want to switch directly to a specified card. The Container argument
specifies the owner of the card layout and the string is the name of the compo-
nent you wish to switch to.
TOSTRING()
This method returns the string representation of the CardLayout’s values. At
this point in the development of Java, this method only returns the size of the
horizontal and vertical gaps.
Index
parameters, 39
A passing information, 367
Abstract classes, 33, 121, 158 sounds, 297
Abstract methods, 132 tags, 39
Abstract Window Toolkit, 32 threading, 51
Action( ) method, 294 ticker tape sample, 22
Add method, 274 vs. applications, 21
Addition, 98 Appletviewer, 7
Addressing Applications
Internet, 353 command line arguments, 86
Animation defined, 21
buffering, 40 networking, 353
speed, 26 sample menu, 268
API documentation, 64 vs. applets, 21
Applet class Architecture natural, 5
hierarchy, 288 Arguments
methods available, 288 accessing, 88
methods derived, 290 indexing, 89
Applets, 5, 6 numeric, 89
browser interaction, 294 passing, 87
class, 287 reading, 87
closing, 51 Arrays, 16, 82
compiling, 53 accessing data, 86
defined, 21 declaring, 82
drawbacks, 291 elements, 83
file access, 292 indexing, 85
file execution, 292 multidimensional, 85
fonts, 43 sizing, 83
images, 298 Assignment boolean operators, 102
navigation sample, 293 Assignment operators, 93, 95
network communication, 292 Audio clips, 297
package, 31 AWT, 31, 227
AWTError, 191
403
404 Index