Java Programming Language Handbook 2
Java Programming Language Handbook 2
HANDBOOK
Anthony Potts
David H. Friedel, Jr.
Chapter
Java Classes
and Methods
Java Classes
and Methods
Classes are the key Java components that
give the language its object-oriented
personality.
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 package, 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), youll soon
discover that classes are the essential building blocks for writing OOP applications. At first glance, Java classes look and operate like C++ classes; but there are
some key differences which well address in this chapter.
Well start by looking at the basics of classes. Youll quickly learn how classes are
defined and used to derive other classes. The second half of the chapter covers
methodsthe 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 perform 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 doesnt allow you to easily create code that can
be reused and expanded to create other code.
115
116 Chapter 5
As youll learn in this chapter, the techniques for defining and using Java classes are
adapted from techniques found in the C++ language. In some cases, the Java syntax will look very similar to C++ syntax, but in other cases youll find a number of
differences, including new keywords that have been added to Java for declaring
classes and methods; restrictions, such as the elimination of pointers; and different
scoping rules that determine how classes can be used in an application.
Declaring a Class
If you recall from Chapter 2, we created a class named TickerTape, which controlled how text scrolled across the screen. Lets take a step back and look at the
full declaration used to define classes in Java:
[Doc Comment] [Modifier] class Identifier
[extends Superclassname]
[implements Interfaces] {
ClassBody;
}
Of course, keep in mind that you wont always use all of the clauses, such as Doc
Comment, Modifier, extends, and so on. For example, heres an example of the
worlds smallest class definition:
class Atom_ant {
int a = 1;
}
117
This class has an identifier, Atom_ant, and a body, int a = 1;. Of course, dont
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 classs 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, lets 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:
crazyant = new Atom_ant();
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, lets expand our example:
class Atom_ant {
int a = 1;
}
// Simple class
118 Chapter 5
public class Bug {
int i = 10;
Atom_ant crazyant;
// Declare an object
The main class, Bug, creates an instance of the Atom_ant classthe 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.
119
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 youre writing the code. The comments you include as
part of this clause can easily be converted into easy to read HTML pages. However, keep in mind that your HTML pages will only be as good as your comments. (To brush up on how to write comments for Java programs, make sure
you read Chapter 3.)
Lets 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 classthe default parent for all classes.
In case youre 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 dont use one of these modifiers when declaring a class, Java will automatically decide that only other classes in the current package may access the
class. Lets 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,
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
public class TickerTape extends Applet implements Runnable {...
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 placeholder for implementing methods and variables. When you construct a hierarchy of classes, your top most class will contain the more general data definitions
and method implementations that represent your programs 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 techniques can also be implemented in Java by using interfaces. Well 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:
Lets look at an example of how an abstract class is defined and used to help
create other classes:
abstract class Quark extends Atom_ant {
...
abstract void abstract_method1();
abstract void abstract_method2();
void normal_method();
...
}
public class Aparticles extends Quark {
public void abstract_method1() {
... // Definition of the method
}
}
public class Bparticles extends Quark {
public void abstract_method2() {
... // Definition of the method
}
}
Here, the class Quark is declared as an abstract class and it contains two methods 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 subclasses that are derived from abstract classes.
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 position 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 compiler always assumes that a final class cannot be extended. Heres an example of
what would happen if you tried to declare a final class and then use it in another
class declaration:
final class Molecule extends Element {
static String neutron = "molecule";
}
class Atom_ant extends Molecule {
static String proton = "atom_ant";
}
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 second 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
classs identifier or name directly follows the class keyword. The rules for naming 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 otherin 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 parentexcept the class that is at
the top. The class that serves as a parent to another class is also called the superclass of the class it derivesthe class that takes the position immediately above
the class. Lets 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 superclass sportscar, which in turn belongs to the superclass automobile.
When you derive a class from a superclass, it will inherit the superclasss 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
Javas top-level superclass named Object. Here is an example:
public class Element extends Object {
public static void main() {
Atom_ant ATOMOBJ = new Atom_ant();
Molecule MOLEOBJ = new Molecule();
System.out.println(ATOMOBJ.proton);
125
Automobile
Sports car
Porsche
911
944
928
Figure 5.2
A sample class hierarchy.
}
}
class Molecule extends Element {
static String neutron = "molecule";
}
class Atom_ant extends Molecule {
static String proton = "atom_ant";
}
In this class declaration section, the top-level class defined is Element. Notice
that it is derived or extended from Objectthe built-in Java class. The first
line of the declaration of Element could have also been written as
public class Element {
...
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
Figure 5.3
Using the extends keyword to derive a series of classes.
Atom_ant
127
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:
Public interface Protons {
void Proton_function(); // declares the method that will be used
}
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 methods that actually support the run() method. Interfaces allow for distinct behaviors, defined by the programmer, to be used without exposing the class(es) to
everyone. Well 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 well discuss how methods are declared and used. Heres an example of a class with a body:
public class TickerTape extends Applet implements Runnable {
// Beginning of class body
String inputText;
String animSpeedString;
Color color = new Color(255, 255, 255);
129
int xpos;
...
// Methods
public void paint(Graphics g) {
paintText(osGraphics);
g.drawImage(im, 0, 0, null);
}
...
// End of Class 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. Lets look at
an example:
public class House extends Object {
void main() {
Room();
}
}
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 statement in Room, the variable Child is assigned the value 5 because this is used to
access the classs local copy of the tvamount variable. In the next assignment
statement, notice how super is used to access the value tvamount was assigned
in Housethe superclass.
130 Chapter 5
Methods
As weve 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 implemented outside of classes.
Lets 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 methods. The first one defined was the init() method, which was responsible for
initializing the applet upon loading. Lets take a step back and look at the full
declaration used to define a Java method:
[Modifier] ReturnType Identifier([ParameterList]) [Throws]
{
MethodBody;
}
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.)
131
Method Modifiers
Earlier in this chapter, you learned that a set of modifiers are available for defining 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:
Keep in mind that it doesnt 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 methods 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 containing the method would only be locked until the method finishes executing.
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. Well 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.
Lets 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, assignment statements, method calls, control statements, and so on.
Heres an example of how a basic method is defined:
public int SimpleMethod(int Number) {
// The integer variable Number is assigned whatever is passed to it
int lowrange = 1;
135
136 Chapter 5
class Quark extends Atom_ant {
int Proton;
int Neutron;
String Electon = "Negative attraction";
...
void Count() {
System.out.println(this.Proton + " is the number of Protons"); // Correct
System.out.println(Neutron + " is the number of Neutrons"); // Correct
System.out.println(super.Number + " is the number of Atoms"); // Correct
System.out.println(Atom_ant.Number + " is the number of Atoms");
// Correct
...
}
}
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 without the use of the this keyword. What gives? Actually, since both of these variables are defined within Quark, the this keyword is not really needed.
As for the two following lines of code, they each reference the Number variable 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 keyword 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;
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.
137
// Correct
Here weve 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 protected 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 defined 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, lets
expand the Quark class a little:
class Atom_ant extends Molecule {
int Number;
protected void Count(String Astring, int Number) {
...
}
}
class Quark extends Atom_ant {
int Proton;
...
public void Count(int Number, String Astring) { // Correct
...
}
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 doesnt, a compiler error will occur. The last call to Count() accesses the method
of the same name defined in Quark.
139
4 Door(integer) Falcon(String)
3 Door(integer) Pinto(String)
2 Door(integer) Mustang(String), which is the default.
We could just say 2, 3, or 4 doors, but the FrameCreation team insists on a certain
format for each. The Falcon requires (integer Doors, String Name), the Pinto requires (String Name, integer Doors), and the Mustang doesnt require any values
(). When you pass these values, known as types to the FrameCreation team, they
immediately know which frame to create, or initialize, by the arrangement of the
information passed to them (data types and number of parameters). By passing the
information in a distinct pattern FrameCreation(Doors, Name), FrameCreation(Name,
Doors), or FrameCreation() to create an object, we are using a constructor.
A constructor is a special method that determines how an object is initalized
when created. The constructor is named the same as the class it follows. The
code for our example could be written like this:
140 Chapter 5
class FrameCreation extends BodyShop {
// ** Initializing the object newcar **
FrameCreation newcar = FrameCreation(4 , Falcon);
// ** The Beginning of the Constructor **
FrameCreation {
// ** An example of Overloading the Constructor **
FrameCreation(int, String) {
// Creates the FALCON
}
// ** An example of Overloading the Constructor **
FrameCreation(String, int) {
// Creates the Pinto
}
FrameCreation() {
// ** An example of Overloading the Constructor **
// Creates the Mustang
}
// ** The End of the Constructor **
}
141
As with the other declarations weve 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 different 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. Heres 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;
Atom_ant(String s, int h) {
superhero = s;
height = h;
}
// Declare a constructor
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_ant a;
142 Chapter 5
a = new Atom_ant("Atom Ant" , 1); // Call the constructor
a.printatom_ant();
System.out.println("------");
a = new Atom_ant("Grape Ape", 5000);
a.printatom_ant();
System.out.println("------");
}
}
Notice that each constructor call is combined with the new operator. This operator is responsible for making sure a new instance of a class is created and
assigned to the object variable a.
143
a = new Atom_ant2();
a.printatom_ant();
System.out.println("------") ;
}
}
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 classthe object a. Once this object is in
hand, the method printatom_ant() can be called.
The output for this program looks like this:
Up and attam, The world's only 0 inch Superhero!
------
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 standard 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 constructor 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 subclasses 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
145
// Correct
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
Javas scoping rulesthe declaration of this constructor is outside of the range of
the Molecule_mole class, and the constructor was not declared as public or protected. 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 restrictions 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 constructor 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 classs identifier. To
refer to the classs superclass, the super() statement is used. Following each of the
clauses are parentheses containing the parameter list to be passed to the constructor, 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:
class Atom_ant2 extends Quark {
String superhero;
int height;
String villain;
int numberofsuperheros;
Atom_ant2() {
this("Atom Ant", 1);
}
147
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_ant2s 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 superclasss constructor for
Class Atom_ant2
. . .
A
Atom_ant2( )
call first
constructor
A
Atom_ant2(s, h)
h)
a= new Atom_ant2(
)
A
. . .
}
Figure 5.4
The chain of constructor calls in the Atom_ant2 example.
call second
constructor
148 Chapter 5
a match. It is important to remember that when using either of these statements, you may not directly call instance variables of the object being created.
Furthermore, an instance variable cannot be dependent upon another variable
that has not yet been defined, or is defined after it.
Heres an example:
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, initializes the variable to create an instance of the class Atom_ant2, and assigns it to a.
149
Only the Type and Identifier components are necessary. The modifiers are optional.
As with all the identifiers weve used throughout this chapter, the variable identifier simply names the variable. However, you can name any number of variables 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
int paul, david, kelly;
static String henry, diana;
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. However, you can only use two of themone from each groupin a declaration.
Also, you cant use two modifiers that contradict each other in the same declaration. The two groups of modifiers are:
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.
Heres 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 asynchronous manner. The variables are reloaded from and stored to memory every
time the variables are used.
151
s = 10;
i = (int) s;
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 required 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 general 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.
152 Chapter 5
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:
public class atom_ant {
String superhero = "Atom Ant";
int height = 10;
153
atom_ant() {
}
void print() {
System.out.print (superhero + " is " + height + "\n");
}
public static void main(String arg[]) {
atom_ant a1;
a1 = new atom_ant();
a1.print();
proton_pal p1, p2;
p1 = (proton_pal) a1; // Runtime error due to casting error
p1.print(); // Unable to execute because of the previous line
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();
}
}
class proton_pal extends atom_ant {
String superhero = "Proton Pal";
int height = 1;
proton_pal() {
}
void print() {
System.out.print (superhero + " is " + height + "\n");
}
}
class electron_enemy extends atom_ant{
String superhero = "Electron Enemy";
int height = -1;
154 Chapter 5
electron_enemy() {
}
void print() {
System.out.print (superhero + " is " + height + "\n");
}
}
Here weve modified our previous atom_ant class to illustrate the basics of casting. Notice that two of the casts used will produce a runtime and compile-time
error, respectively. (Thus, dont 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 produces a runtime error because the object a1 cannot be expected to grow to accommodate 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 completely 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
Interfaces and
Packages
Interfaces and
Packages
If youre ready to move beyond the stages of writing applets and simple standalone applications and
applets, youll find that Javas flexible interfaces
and packages provide a welcome relief.
After writing a few applets and applications, youll 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 themshameful!) As you start to work more with interfaces and packages,
youll discover a myriad of important program design issues that come into play
which youll need to master to use interfaces and packages effectively.
In this chapter youll learn about:
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, youll need the flexibility 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 classhow a class should essentially communicate with other classesearly on in the development cycle. The upshot is that
when you create your interfaces or abstract classes, you dont 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, lets explore a few conceptual examples. The concept of abstract classes and interfaces
is tricky to grasp at first. In fact, many experienced object-oriented programmers will tell you that they didnt quite master the concepts until they had written a number of programs. Fortunately, we can help you understand and use the
techniques much quicker by providing the background information and conceptual models youll 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 circleswelcome 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.)
Lets 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.
159
Class Hierarchy
Transportation
Automobiles
Truck
Car
Solar
Boats
Sail
Powered
Airplanes
Gliders
Powered
Gas
Interfaces
Battery
battery_life
weight
Tires
Gasoline
liters
gas_type
diameter
brand_name
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 components 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. Lets 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, youd 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 hierarchy, 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 programmers nightmare because limitations
could arise from placing such restrictions early on.
In applications that have class hierarchies like our transportation example, interfaces become priceless because they allow us to mix-in classes into the application, adding them only where they become absolutely necessary. Another feature
that enhances the interfaces capabilities is the use of multiple implementations
of interfaces per class. For example, in our transportation application, theoretically 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 Tires methods or variables.
Design Issues with Interfaces
Interfaces will usually fall into a class hierarchy without any problems when you are creating small scale applications. They also
help separate the design process from the implementation process because they keep you from having to combine the more
abstract design issues with implementation details in one component. They also allow you to derive classes without relying on
the more limited technique of single inheritance. If you recall
from Chapter 5, a single inheritance model requires you to create class hierarchy trees by deriving one class from a single
parent or superclass. Each class in the tree is created by using
only data and operations that were defined in the levels above
the current class.
Interfaces help you build class hierarchies that use more powerful object-oriented techniques like multiple inheritance. With interfaces, you can define classes that have multiple parents. You
can incorporate interfaces into a hierarchical class tree to include new methods and variables without having to worry about
disrupting your current implementation tree.
Declaring an Interface
Lets look at the basic declaration for an interface and then well show you the
syntax for implementing an interface. After that, well 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:
public interface InterfaceName {
StaticVariables;
AbstractMethods;
}
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. Heres an example of an interface declaration:
public interface Gasoline {
// This variable is defined as a constant
public static final int Feet_in_Miles = 7245;
// A Method that is to be defined in a class
void gas_type(String Name);
// Another method to be defined later
void liters(int Amount);
}
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 declaration 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 methods 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
modifier class Identifier extends Superclass
implements InterfaceName [, InterfaceList ] {
ClassBody;
}
With these interfaces in hand, were ready to create the two classesGas and
Poweredeach 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:
public class Gas extends Car implements Gasoline, Batteries, Tires {
int Feet_Traveled;
int Miles_Traveled = 20;
Feet_Traveled = Miles_Traveled * Feet_in_Miles;
public static gas_type(String Name) {
... // Any functions that are to be performed with gas_type
if(Name.equals("Diesel"))
System.out.println("Ah, good power");
if(Name.equals("Unleaded"))
System.out.println("ok power");
if(Name.equals("Leaded"))
System.out.println("eh, clogged injectors");
}
public static liters(int Amount) {
... // Any functions that are to be performed with liters
}
public static battery_life(int Time) {
... // Any functions that are to be performed with battery_life
}
164 Chapter 6
public static weight(int Amount) {
... // Any functions that are to be performed with weight
}
public static diameter(int Distance) {
... // Any functions that are to be performed with diameter
}
public static brand_name(int Name) {
... // Any functions that are to be performed with brand_name
}
}
public class Powered extends Boat implements Gasoline, Batteries {
int Feet_Traveled;
int Miles_Traveled = 20;
Feet_Traveled = Miles_Traveled * Feet_in_Miles;
public static gas_type(String Name) {
... // Any functions that are to be performed with gas_type
if(Name.equals("Diesel"))
System.out.println("Required");
if(Name.equals("Unleaded"))
System.out.println("Not applicable");
if(Name.equals("Leaded"))
System.out.println("Not applicable");
}
public static liters(int Amount) {
... // Any functions that are to be performed with liters
}
public static battery_life(int Time) {
... // Any functions that are to be performed with battery_life
}
public static weight(int Amount) {
... // Any functions that are to be preformed with weight
}
}
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
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.
166 Chapter 6
3 Gas
aCar
= makeGasCar();
4 Gasoline aGasCar = (Gasoline) makeGasCar();
// Use cast
5 Tires
aTireCar = (Tires) makeGasCar();
// Use cast
6
7
aGasCar.gas_type(Diesel);
// Valid
8
aGasCar.liters(5.8);
// Valid
9
10 aTireCar.diameter(6.9);
// Valid
11 aTireCar.gas_type(Unleaded);
// Not Valid
12
13 aCar.gas_type(Diesel);
// Valid
14 aCar.weight(12.7);
// Valid
15 aCar.diameter(6.9);
// Valid
16 aCar.brand_name(Bridgestone);
// Valid
17
18 . . .
// Any functions that you would perform on the Cars created
19}
Lets 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 codea 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 interface 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 well see in a second, this means no methods 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
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 compile-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.
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 dont 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 functions 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 implemented in the ticker tape applet were borrowed from classes or interfaces belonging to other packages. For example, one of the packages used was the Applet
packagea 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 methods 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.
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.
package developed by Sun Microsystems. (Of course, as with every programming language, Java provides certain exceptionsone being the guideline for
naming and referencing packages. For example, java.io.File was developed by
Sun Microsystems, but this package is intended to be implemented by other
companies as a foundation for building additional I/O packages.) The sections
listed beneath the company name reference subdirectories that further specify
where the class is located. For example java.io.File is a subdirectory that contains
classes that relate to the input/output functions of Java. The extension .class has
been omitted from the reference to the File class because interfaces and classes
are the only format contained in a package and both end in the .class extension.
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 beginning of each source file that defines a public class:
172 Chapter 6
package airplanes;
package airplanes;
package airplanes;
174 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 already 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:
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. Heres an example:
airplanes.Twin_engine twin = new airplanes.Twin_engine("Beach", 1100);
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 approach, 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 example, 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 package 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.
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 wont,
however, import any of the classes that are contained in the peer or image directories 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 {
// Draw background and text on buffer image
public void paintText(Graphics g){
...
FontMetrics fmetrics = g.getFontMetrics();
...
}
}
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, Integer, and Thread are just a few of the classes that are called from this package.
...
}
Package
Description
java.lang
Contains essential Java classes for performing basic functions. This package is automatically
imported into every class that is created in Java.
java.io
java.util
java.net
Contains classes that aid in connecting over networks. These classes can be used in
conjunction with java.io to read/write information to files over a network.
java.awt
Contains classes that let you write platform-independent graphics applications. It includes
classes for creating buttons, panels, text boxes, and so on.
java.applet
Contains classes that let you create Java applets that will run within Java-enabled browsers.
Chapter
Java Exceptions
Java
Exceptions
Are you tired of writing applications that
mysteriously crash, leaving the user to give
up in frustration? If so, youll be glad to
learn that Java provides a powerful feature
called exceptions that automates the work of
catching and handling compile-time and
runtime errors.
involves finding and fixing bugs. Fortunately, Java provides some built-in features that lend a hand in the debugging process. As errors occur in a Java program, and we all know they will, you can use Java exceptions to provide special
code for handling them.
Java programs can detect certain errors on their own and instruct the Java runtime system to take some predefined action. If you dont like the default operations that Java performs when it encounters certain errors, you can write your
own custom error handling routines.
In this chapter well start by explaining the basics of exceptions. Then, well
show you
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 application. 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 provides 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.
Javas exceptions allow you to effectively code the main sections of your applications without you having to spend too much time writing code to detect and
handle potential errors. As youll learn in this chapter, exceptions create an object 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 handlera method that deals with the exceptioncatches the object. This process
is illustrated in Figure 7.1. If no exception handler is defined, a default exception handler is used to handle the error. This causes the error to be printed to the
command line and the program will cease running.
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
method
try{
call method( );
}
catch(Exception);
method throw
throw
method throw
method throws
throw
...
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.
184 Chapter 7
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 didnt 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. Heres a Java program that performs a
critical file operation but doesnt provide any error handling:
// This program will not compile because an IOException handler is
// expected by the Java compiler
import java.io.*;
public class WriteAFile extends Object {
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;
// Begin to Write file out
writeOut = new FileOutputStream(s);
dataWrite = new DataOutputStream(writeOut);
dataWrite.writeChars("This is a Test");
dataWrite.close();
}
// Where execution begins in a stand-alone executable
public static void main(String args[]) {
new WriteAFile(args[0]);
}
}
(Actually, this program wont compile just yet because the Java compiler expects to find an exception named IOException. Well explain this in a moment.) 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.
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
thats why no other code is provided with the catch statement.
These changes allow the code to compile and run. Unfortunately, they do not address 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 dont 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. Unfortunately, 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-oriented languages is the ability to create robust code that can be reused by others.
Now, lets change the WriteAFile class once more to make it more robust. Dont
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, weve 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. Well show you how to
create custom error-handling routines later when we discuss the topic of catching. 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.
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 hierarchy of method calls. This allows each level to either handle the exception or pass
it on. Well cover this more when we present exception throws.
188 Chapter 7
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");
}
}
// Where execution begins in a stand-alone executable
public static void main(String args[]) {
new ReadAFile(args[0]);
}
}
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 throwing an exception in the event of an error. More specifically, the method contained 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
exceptions thrown by handling them or passing them on. You handle the exception 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.
190 Chapter 7
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 wont 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 realized that by separating commonly used exceptions from specific exceptions, programmers 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
Table 7.1
Exception
Description
AbstractMethodError
This exception is thrown when your code attempts to call an abstract method.
AWTError
This exception is thrown when an error occurs in the Advanced Windowing Toolkit.
ClassCircularityError
ClassFormatError
IllegalAccessError
InternalError
This exception is thrown when an internal error occurs in the Java Virtual Machine.
LinkageError
This exception is thrown when the current class is dependant on another class, but
the other class is not compatible with the current class.
NoClassDefFoundError
This exception is thrown when a class cannot be found by checking the path
specified by the CLASSPATH environment variable or the current directory.
NoSuchFieldError
NoSuchMethodError
This exception is thrown when a particular method cannot be found in the current
class or one of its superclasses.
OutOfMemoryError
This exception is thrown in the event that no more memory can be allocated.
StackOverflowError
ThreadDeath
UnknownError
UnsatisfiedLinkError
VerifyError
This exception is thrown when the Java compiler is unable to verify if a linkage
between classes is valid.
VirtualMachineError
This exception is thrown when the Virtual Machine has depleted its resources.
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 excepTable 7.2
Exception
ClassNotFoundException
CloneNotSupportedException This exception is thrown when an object attempts to clone an object that does not
want to be cloned.
IllegalAccessException
This exception is thrown when a method is called from a class that does not have
permission to do so. The access is determined by the modifiers used for the class
and methods, resulting in the compiler being able to see or not see the calling
method.
IllegalMonitorStateException This exception is thrown in the event that a monitor is accessed that you do not own.
InstantiationException
InterruptedException
This exception is thrown when a thread has interrupted the currently running
thread.
NoSuchMethodException
This exception is thrown when a method cant be found in the calling class.
Exception
EmptyStackException
NoSuchElementException
Exception
EOFException
FileNotFoundException
IOException
InterruptedIOException
UTFDataFormatException
This exception is thrown when a malformed UTF-8 string has been read in a
DataInput stream.
continued
194 Chapter 7
Table 7.2
Exception
MalformedURLException
ProtocolException
SocketException
This exception is thrown when an error occurs during the use of a socket.
UnknownHostException
This exception is thrown when there is an error in the connection to server from
the client.
UnknownServiceException
Exception
AWTException
This exception is thrown in the event of an error with the Advanced Windowing
Toolkit.
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).
Exception
Description
ArithmeticException
ArrayIndexOutOfBoundsException This exception is thrown when an array is referenced outside the legal
range.
ArrayStoreException
`
ClassCastException
IllegalArgumentException
IllegalThreadStateException
IndexOutOfBoundsException
NegativeArraySizeException
NullPointerException
NumberFormatException
SecurityException
StringIndexOutOfBoundsException This exception occurs when a string is accessed outside the legal length of a
string.
[Modifier] Return-type Identifier ([Parameter List]) [throws
ExceptionName]
{
Body;
}
The throws clause may list as many exceptions as will be thrown to it by separating each of them with a comma. For an example, lets take our ReadAFileAFile
class to the next level and introduce a throws method:
import java.io.*;
public class wordProcessor extends Object {
196 Chapter 7
String fileName;
void save(String fileName) {
System.out.print ("Saving File Procedure\n");
try {
System.out.print ("Saving File " + fileName + "\n");
ReadAFile aFile = new ReadAFile(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
}
}
// Where execution begins in a stand-alone executable
public static void main(String args[]) {
wordProcessor myProgram = new wordProcessor();
myProgram.save(args[0]);
}
}
// Reads from a file
class ReadAFile extends wordProcessor {
ReadAFile(String s) throws FileNotFoundException, IOException {
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");
throw e;
}
Notice that we didnt 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:
ReadAFile(String s) throws
...
FileNotFoundException, IOException {
In our example, this line of code tells the method, ReaAFile(), that two exceptions, 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 languages, messages can be passed along with the object to identify particular details to help process the exception. The following line of code shows how to
throw an exception with a message attached:
throw new FileNotFoundException("MyFile.txt");
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, youll 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.*;
public class WriteAFile extends wordProcessor{
WriteAFile(String s) throws IOException {
write(s);
}
// 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.*;
public class wordProcessor extends Object {
wordProcessor(String s) {
new WriteAFile(s);
}
200 Chapter 7
wordProcessor() {
System.out.println("Create a backup file");
}
// Where execution begins in a stand-alone executable
public static void main(String args[]) throws IOException {
new wordProcessor(args[0]);
}
}
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.
Make sure you derive your new exception from the correct class. For example, if you create an exception that detects the corruption of a file, youd
want to subclass it beneath an IOException. Deriving the new exception
from an exception like ArrayOutOfBoundsException would be pointless.
If your code generates an error condition, you should handle it unless there
is an obvious exception already created. For example, in the ReadAFile class
we coded in this chapter, we used an exception to detect if a file cannot be
found. On the other hand, if you created a class that determines whether a
file has a virus or not, an IOException wouldnt necessarily be a wise choice.
This would be a good place to subclass, however.
Exceptions created in most applications should be derived from the Exceptions class. Only specific (lower-level) situations should require exceptions
that need to be derived from the Errors or RunTime classes.
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:
public class AVirusDetectedException extends 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
}
int virus(String fileName) {
//perform some actions like read in libraries of virus types
//test the byte code against patterns associated to viruses
if (fileName = viruspattern) {
return 1;
}
return 0;
}
}
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 exceptions. 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
Threads
Threads
To create Java applets and applications that
wont turn into system resource hogs, youll
need to arrange your programs into separate
processes, which are called threads.
I magine what our lives would be like if we could only do one thing at a time.
You wouldnt be able to listen to music and program at the same time; and you
definitely couldnt cook dinner, watch TV, and carry on a conversation with a
friend. Although programming languages dont need to perform tasks like these,
newer operating systems and environments like the Web are placing greater demands 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, youll learn how to structure your programs to take advantage of
the flexibility that multiple processes provide.
In this chapter well examine how threads are used to create multiple processes
in Java programs. Youll 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 youve done any programming for an operating system such as Windows 95 or Windows NT, youve
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 calculations 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, lets start with a simple example
that contains a single process. Then well 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:
public class Hi3Person {
public static void main(String args[]) {
Hi3Person people = new Hi3Person();
people.hi("Person");
people.hi("Person 2");
people.hi("Person 3");
System.out.println("Hello Everyone");
}
void hi(String who) {
System.out.println("Hi " + who);
}
}
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 execution will be disrupted. The program will be split into multiple processes, each
responsible for writing to the screen. Lets look at the new version of our code to
see what is going on behind the scenes:
public class Hi3People implements Runnable {
public static void main(String args[]) throws InterruptedException {
int i = 0;
Hi3People person = new Hi3People();
// Create thread #1
Thread aThread = new Thread(person, "Person 1");
// Create thread #2
Thread anotherThread = new Thread(person, "Person 2");
aThread.start();
anotherThread.start();
}
public void run() {
System.out.println("Hi " + Thread.currentThread().getName());
}
}
(For now, dont worry about the syntax used to create the threads that are used.
Well explain the techniques for implementing threads a little later in this chapter.) 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 processing this thread. The main() method is responsible for setting up each thread and
determining when the threads are finished. This is necessary because our program 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:
while ((aThread.isAlive()) || (anotherThread.isAlive())) {
i++;
}
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 multithreaded program is not the only task that the Java runtime system must perform. Java also has its own internal threads that it must perform to manage tasks
such as garbage collection.
Threads
209
Keep in mind that when an application runs, multiple processes dont actually run at the same time. Its the operating
systems job to give the user the impression that everything
happens at once. Even in a multithreading environment like
Unix, processes do not occur at the same time. As Figure 8.1
shows, the illusion of processes running concurrently is created by carefully and quickly cycling instructions through a
channel. The Java Virtual Machine handles its own type of
processor management by determining what executions will
occur and in what order.
Process
When you add multiple threads to your program, you effectively set up an events manager. You must manage how the
instructions from your application are handled. You determine
what process receives more or less time and when to change
the focus of the program. As you will see later in this chapter,
you can make your application appear transparent or painfully slow just by the way you schedule your threads.
Process
Process
Process
Processor
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 youll see in the next two sections, the approach
you use will depend on your own needs.
Heres an example Java application that utilizes the Thread class as a superclass:
public class Hiagain extends Thread {
public static void main(String args[]) {
int i =0;
Hiagain tony = new Hiagain(); // Create a new object
Thread t1 = new Thread(tony); // Create each thread of the object type
Thread t2 = new Thread(tony);
t1.start();
t2.start();
Threads
211
The class Hiagain subclasses the Thread class and overrides the run() method
defined by the Thread class. Because Hiagain is derived from Thread, it inherits 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 interface. Of course, you will then be required to go along with the implementation
created by the designers of this interface. Lets revisit our ticker tape applet introduced 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 performing 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:
// Change coordinates and repaint
public void run() {
while(ttapeThread != null) {
try { Thread.sleep(50); } catch (InterruptedException e) {}
setcoord();
repaint();
}
}
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 Identifier = new Thread();
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:
Hiagain tony = new Hiagain();
Thread t1 = new Thread(tony);
The next two constructors allow you to pass a string to create references to
individual threads, which can then be used as symbolic references. Well 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, youll see that the thread is
created in the start() method for the applet:
// Start Applet as thread
public void start() {
if(ttapeThread == null) {
ttapeThread = new Thread(this);
ttapeThread.start();
}
}
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().
Threads
215
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 Javas 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).
MAX_PRIORITY
NORM_PRIORITY
MIN_PRIORITY
216 Chapter 8
Each of these variables holds integer values that specify a threads priority level.
For example, MAX_PRIORITY stores a number that indicates the maximum
allowable value for a threads priority. To set or retrieve the current priority setting 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 threads priority to
the value contained in the NORM_PRIORITY variable:
Thread aThread = new Thread(person, "Person 1");
aThread.setPriority(aThread.NORM_PRIORITY);
In this example the start() method checks to see if the thread ttapeThread exists. If it doesnt, it creates an instance of the Thread class and assigns the variable 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.
Threads
219
}
suspended = !suspended;
}
return true;
}
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 repaint(). 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 dont remember, here is the syntax.
synchronized ReturnType Identifier([ParameterList]) [Throws]
{
MethodBody;
}
The synchronized modifier is used to declare a method of which only one object can execute at any one time. This is accomplished by the Java Virtual Machine 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 monitor. 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. Lets look at an example of how the synchronized techniques works:
import java.awt.*;
import java.lang.*;
public class MyApp2 extends Frame implements Runnable {
static TextArea t1;
static TextArea t2;
MyApp2() {
// Calls the parent constructor Frame(string title)
// Same as setTitle("Duck Duck Goose");
super("Counting example");
// A new panel to the south that 4 buttons and 1 choice
t1 = new TextArea();
t2 = new TextArea();
add("East", t1);
add("West", t2);
pack();
show();
}
public static void main(String args[]) {
int i = 0;
MyApp2 game = new MyApp2();
Thread person1 = new Thread(game, "duck");
Thread person2= new Thread(game, "goose");
person1.start();
person2.start();
while ((person1.isAlive()) || (person2.isAlive())) {
++i;
t2.setText(Integer.toString(i));
}
t2.appendText("\n Time through the loop \n\nYour It");
person1.stop();
person2.stop();
}
222 Chapter 8
public synchronized void run() {
int d = 0;
int change = 0;
while(d < 100) {
t1.appendText("\n
" " + d );
++d;
}
" + Thread.currentThread().getName() +
}
public boolean handleEvent(Event evt) {
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, person1, 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 running alongside.
Threads
223
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 notify() method is called from within the same method. The thread waiting then
picks up right from the point where it began waiting. Lets modify our previous
example MyApp2 to utilize the wait() and notify() methods:
public synchronized void run() {
int d = 0;
int change = 0;
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.
224 Chapter 8
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:
ThreadGroup parentAuthor = new ThreadGroup( " The Potts ");
This allows for quick subgrouping of like threads. There are three main advantages 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 priority, it will continue at this level until it dies.
Chapter
The Java
AWT
If youre wondering where to look for information on creating interface components for
Java programs, youve come to the right place.
The AWT provides a treasure chest of powerful interface classes.
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 programmers 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, well look at how the AWT is arranged.
Then well present each of the key AWT classes. Well show you how to use the
layout manager, and well 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.
Youll want to keep your browser tuned to Suns Java site for the latest information on this powerful package.
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 doesnt 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:
import java.awt.*;
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 package, you can use any of the AWT controls or packages to derive your own. With
just a little bit of programming effort, youll be amazed at the types of interface
components you can create for your Java applicationseverything from scrollable
windows to fully functional pop-up menus.
Heres an example of a simple Java program that displays a window that contains
a text message:
import java.awt.*;
// Constructor
230 Chapter 9
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 componentswindows,
dialogs, scrollbars, and so onto build up the AWT. Of course, youll 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.
MenuComponent
Button
Font
MenuItem
Canvas
FontMetrics
Panel
CardLayout
Frame
Point
Checkbox
Graphics
Polygon
CheckboxGroup
GridBagConstraints
Rectangle
CheckboxMenuItem
GridBagLayout
Scrollbar
Choice
GridLayout
TextArea
Color
Image
TextComponent
Component
Insets
TextField
Container
Label
Toolkit
Dialog
List
Window
Dimension
MediaTracker
Event
Menu
FileDialog
MenuBar
232 Chapter 9
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. Well introduce these methods next, and well examine some of the key
event handling methods in Chapter 10.
BOUNDS()
This method enables a component. You can pass zero arguments, or a Boolean
argument to enable or disable a control. Heres 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 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.
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 initially 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 parents coordinate space.
MOVE(INT X, INT Y)
This method moves the component to a new location. The x and y coordinates
are in the parents 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 coordinates 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 within 250 milliseconds
myComponent.update(250);
// Update rectangle
myComponent.update(50, 50, 200, 200);
// Update same rectangle within 250 milliseconds
myComponent.update(250, 50, 50, 200, 200);
RESIZE(INT
WIDTH,
INT
HEIGHT)
This method resizes the component to the specified width and height. You
could also pass it a dimension object instead of the two integers. Here are a
few examples:
myComponent.resize(300, 200);
myComponent.show(new dim(300, 200));
SETFONT(FONT)
This method sets the font of the component. The argument passed is a Font
object. For example, this method call
myComponent.setFont(new Font("Helvetica", Font.PLAIN, 12);
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);
235
SIZE()
This method returns the current size of the component. The size is returned in
dimensions of width and height.
// Constructor
236 Chapter 9
Figure 9.2
A simple windowed Java application.
In the main() method we use our classs constructor to create our object named
Test. Then we call the objects show() method to make the window frame visible
(frames are invisible by default). If you were running this Java program in Windows 95, youd 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
classs 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 happens! Thats 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 class winTest1 extends Frame {
public winTest1() {}
public synchronized boolean handleEvent(Event e) {
if (e.id == Event.WINDOW_DESTROY) {
// Has window been destroyed?
System.exit(0);
return true;
}
return super.handleEvent(e);
}
public static void main(String args[]) {
winTest Test = new winTest();
Test.setTitle("Test Window");
Test.resize(300 ,200);
Test.show();
}
}
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
dont 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.
Lets look at the methods that are specific to the Frame class.
This method removes the frame. It must be called to release the resources that
are used to create the frame. This method should be called when you exit a
window in an applet. In an application, you would usually use the System.exit()
method to terminate the program and release all memory used by the application. This method overrides the dispose() method from the Window class.
GETICONIMAGE()
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 title for the frame to the specified title.
Lets 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 configuration. The output is shown in Figure 9.7.
import java.awt.*;
public class mixLayout extends Frame {
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.
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().
242 Chapter 9
We can also assign the text string to an object variable like this:
Label fruitLabel = new Label("Fruits of the world:");
Table 9.2 shows the three ways you can declare a Label class.
This method does what it sounds likeit 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:
add(new Label("Left")); // no need to specify alignment because it
// defaults to left
add(new Label("Center", Label.CENTER));
add(new Label("Right", Label.RIGHT));
Description
Label()
Label(String)
Label(String, int)
This constructor will create a label with the given string as well as define the
alignment of the string. The int part of the declaration is represented by setting
it to Label.LEFT, Label.CENTER, or Label.RIGHT. (These labels should be
pretty self-explanatory.) Remember though, that if you do not assign an
alignment, the label control will default to left-justified.
Figure 9.8
The Label component.
SETTEXT(STRING)
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 buttons (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.
Thats 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.
244 Chapter 9
Figure 9.9
A few Button components.
new Button(); // Empty button
new Button(String); // Button with "String" as the caption
245
246 Chapter 9
P2.add(new Checkbox("Me", G1, true));
P2.add(new Checkbox("You", G1, false));
P2.add(new Checkbox("Them", G1, false));
resize(300, 200);
show();
}
public static void main(String args[]) {
testMe test = new testMe();
}
}
DECLARATION
FOR
CHECKBOX
Constructs a checkbox with the specified label, no checkbox group, and initializes it to a false state.
Figure 9.10
A few iterations of the Checkbox component.
Constructs a checkbox with the specified label, no checkbox group, and initializes it to a specified boolean state.
new Checkbox(String, CheckboxGroup, boolean);
Constructs a checkbox with the specified label, specified checkbox group, and
initializes it to a specified boolean state.
This method returns the checkbox group that this checkbox belongs to.
GETLABEL()
248 Chapter 9
Here is the code that creates the Choice component shown in Figures 9.11
and 9.12:
import java.awt.*;
public class testMe extends Frame {
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();
}
public static void main(String args[]) {
testMe test = new testMe();
}
}
Figure 9.11
The Choice component without the focus.
Figure 9.12
The Choice component with the focus.
ADDITEM(STRING )
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.
251
Figure 9.13
Create lists with the List class.
Creates a scrolling list initialized with no visible lines and multiple selections
disabled.
new List(int, boolean);
Creates a new scrolling list initialized with the specified number of visible lines
and a boolean stating if multiple selections are allowed or not.
252 Chapter 9
COUNTITEMS ()
This method deletes an item from the list at the specified index.
DELITEMS (INT, INT)
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 gets the item associated with the specified index.
GETROWS()
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().
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 specified amount of rows.
SELECT(INT)
254 Chapter 9
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.
Figure 9.14
Right-clicking on a TextField component to display a pop-up menu.
255
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.
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()
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 locations.
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, lets 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. Echoing is used for situations where you do not want the text people are typing to be
displayed.
GETCOLUMNS()
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-
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 youll want to
set this character to the asterisk symbol, especially if you are working with password boxes.
Now, we need to look at the methods specific to the TextArea class:
GETCOLUMNS()
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 row and column dimensions of the TextArea.
MINIMUMSIZE()
This method returns the specified minimum size dimensions of the TextArea.
258 Chapter 9
REPLACETEXT(STRING, INT, INT)
This method replaces text from the indicated start to end positions with the
specified new text.
Figure 9.15
A typical Java scrollbar.
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.*;
public class ScrollTest extends Frame {
TextField text;
Scrollbar scroll;
public ScrollTest() {
super("Scroll-Text Test");
text = new TextField(5);
scroll = new Scrollbar(Scrollbar.VERTICAL, 0, 10, 0, 100);
setLayout(new FlowLayout());
add(text);
add(scroll);
resize(300, 200);
show();
}
public boolean handleEvent(Event evt) {
if (evt.target.equals(scroll)) {
text.setText("" + scroll.getValue());
} else if (evt.target.equals(text))
{scroll.setValue(Integer.parseInt(text.getText()));
} else if (evt.id == Event.WINDOW_DESTROY) {
System.exit(0);
return true;
}
return super.handleEvent(evt);
}
public static void main(String args[]) {
ScrollTest test = new ScrollTest();
}
}
260 Chapter 9
Keep in mind that the scrollbar, like all the other controls, will change its appearance to match the operating system. Obviously, you would not want Windows 95 style scrollbars being displayed on a Macintosh. That would sure cause
a commotion!
Constructs a new Scrollbar with the specified orientation. You can specify
Scrollbar.HORIZONTAL or Scrollbar.VERTICAL. Scrollbars are vertical
by default.
new Scrollbar(int, int, int, int, int);
Creates a new Scrollbar with the specified orientation, current value, large change
size, minimum value, and maximum value.
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.
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 scrollbars orientation.
GETVALUE()
This method returns an integer representing the current value of the scrollbar.
GETVISIBLE()
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.
SETVALUES(INT, INT, INT, INT)
This method changes the values for the scrollbar. The arguments in order of
appearance include:
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. Lets start our
investigation of menus with the main componentthe menu bar. Then, well
work our way down into the other more specialized components, such as a menu
itself and menu items.
262 Chapter 9
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.
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
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.
new Menu(String, boolean);
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.
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 menu item located at the specified index of the menu.
ISTEAROFF()
This method deletes the item at the specified index from the menu.
265
REMOVE(MENUITEM)
266 Chapter 9
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.
Figure 9.19
Using the CheckboxMenuItem to check and uncheck menu items.
This class constructs a new MenuItem with the specified String displayed as the
menu components 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.
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 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 returns a boolean value that represents the state of the menu item.
SETSTATE(BOOLEAN)
268 Chapter 9
You my notice that we used two different methods for creating the two separators in the File menu. The addSeparator() method is probably easier. However, 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 youve seen the basics for
creating menus and GUI objects, youll need a way to position them within the
frames you build. And thats 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. Lets 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.
272 Chapter 9
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.*;
class LayoutFrame extends Frame {
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();
}
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.
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 components contained in the specified target container. These dimensions are extremely
useful because they can help you ensure that the user will not shrink the container 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 components 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 FlowLayouts values, including: (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
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.
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 mostlythey 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.
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.
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 components 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 components contained in the specified target container. The return value is a dimension variable.
PREFERREDLAYOUTSIZE(CONTAINER)
This method returns the preferred dimensions for the layout given the components in the specified target container. The method also returns a dimension
style variable.
REMOVELAYOUTCOMPONENT(COMPONENT)
Figure 9.26
Using the GridLayout() class to create a sample frame.
Creates a grid layout with the specified rows, columns, horizontal gap, and vertical gap.
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 components 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 components in the specified target container. It also returns a dimension style variable.
REMOVELAYOUTCOMPONENT(COMPONENT)
gridx, gridy Specifies the cell in the grid at the upper left of the component. The upper-left-most cell of a container has address gridx=0, gridy=0.
gridwidth, gridheight Specifies the width and height of our component in grid
space terms. You can set either of these to GridBagConstraints.REMAINDER to
make the component be the last one in its row or column.
fill Used when the components display area is larger than the components
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 componentthe 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 determine where to place the component. Valid values are:
GridBagConstraints.CENTER (the default)
GridBagConstraints.NORTH
GridBagConstraints.NORTHEAST
GridBagConstraints.EAST
GridBagConstraints.SOUTHEAST
GridBagConstraints.SOUTH
GridBagConstraints.SOUTHWEST
GridBagConstraints.WEST
GridBagConstraints.NORTHWEST
weightx, weighty Used to determine how to distribute space; this is important for specifying resizing behavior. Unless you specify a weight for at least
one component in a row and column, all the components clump together in
the center of their container. This is because when the weight is zero (the
default), the GridBagLayout puts any extra space between its grid of cells
and the edges of the container.
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.*;
public class GridBagTest extends Frame {
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();
}
protected void makebutton(String name, GridBagLayout gridbag,
GridBagConstraints c) {
Button button = new Button(name);
gridbag.setConstraints(button, c);
add(button);
}
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 mechanism. 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 components contained in the specified target container. The return value is a dimension variable.
282 Chapter 9
PREFERREDLAYOUTSIZE(CONTAINER)
This method returns the preferred dimensions for this layout given the components in the specified target container. It also returns a dimension style variable.
SETCONSTRAINTS(COMPONENT,
GRIDBAGCONSTRAINTS)
Creates a card layout with the specified horizontal and vertical gaps.
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 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 components contained in the specified target container. The return value is a dimension variable.
NEXT(CONTAINER)
This method returns the preferred dimensions for the layout given the components in the specified target container. This also returns a dimension style
variable.
PREVIOUS(CONTAINER)
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 component you wish to switch to.
TOSTRING()
Index
A
Abstract classes, 33, 121, 158
Abstract methods, 132
Abstract Window Toolkit, 32
Action( ) method, 294
Add method, 274
Addition, 98
Addressing
Internet, 353
Animation
buffering, 40
speed, 26
API documentation, 64
Applet class
hierarchy, 288
methods available, 288
methods derived, 290
Applets, 5, 6
browser interaction, 294
class, 287
closing, 51
compiling, 53
defined, 21
drawbacks, 291
file access, 292
file execution, 292
fonts, 43
images, 298
navigation sample, 293
network communication, 292
package, 31
parameters, 39
passing information, 367
sounds, 297
tags, 39
threading, 51
ticker tape sample, 22
vs. applications, 21
Appletviewer, 7
Applications
command line arguments, 86
defined, 21
networking, 353
sample menu, 268
vs. applets, 21
Architecture natural, 5
Arguments
accessing, 88
indexing, 89
numeric, 89
passing, 87
reading, 87
Arrays, 16, 82
accessing data, 86
declaring, 82
elements, 83
indexing, 85
multidimensional, 85
sizing, 83
Assignment boolean operators, 102
Assignment operators, 93, 95
Audio clips, 297
AWT, 31, 227
AWTError, 191
403
404 Index
class hierarchy, 230
components, 229
defined, 32
importing, 228
layout manager, 228
menus, 229
B
Bandwidth considerations, 360
Binary, 97
Binary integer operators, 99
Binary operators, 98
Bitwise complement, 97
Bitwise operators, 99
Blocking, 217
Body (class), 128
Boolean data type, 78
Boolean operators
assignment, 102
evaluation, 101
logical, 100
negation, 100
ternary, 102
BorderLayout class, 274
declaration, 275
methods, 275
Break statement, 110
Browsers
HotJava, 6
Netscape, 26
BufferedInput Stream class, 327
BufferedOutputStream class, 327
Buffering, 40, 45
Button class
declaration, 243
getLabel( ), 244
hierarchy, 243
setLabel( ), 244
Buttons, 32
Byte streams, 321
Byte type, 76
ByteArrayInputStream class, 328
C
Canvas class
declaration, 245
hierarchy, 244
paint( ), 245
CardLayout class, 282
declaration, 282
methods, 282
Case-sensitivity
declarations, 36
package names, 171
parameters, 40
variable names, 36
Casting
interfaces, 165
vs. creating, 151
Casts, 103
Catch statements, 187
Catch( ) method, 185
Catching errors, 186
CGI. See Common Gateway
Interface
Char data type, 79
Character arrays, 16
Character literals, 73
Checkbox class, 245
declaration, 246
getCheckboxGroup( ), 247
getLabel( ), 247
getState( ), 247
hierarchy, 246
setCheckboxGroup( ), 247
setLabel( ), 247
setState( ), 247
Choice class, 247
addItem( ), 249
countItems( ), 249
declaration, 248, 251
getItem( ), 249
Index
getSelectedIndex( ), 249
getSelectedItem( ), 249
hierarchy, 248, 250
methods, 251
select( ), 250
Classes, 5
abstract, 33, 121, 158
advantages, 116
applet, 287
body, 128
bufferedInputStream, 328
bufferedOutputStream, 327
button, 243
byteArrayInputStream, 328
byteArrayOutputStream, 328
canvas, 244
casting, 150
checkbox, 245
choice, 247
component, 290
container, 290
dataInputStream, 330
dataOutputStream, 330
declaring, 116
defined, 32
documenting, 63
error, 191
event, 304
exception, 193
extending, 124
fileInputStream, 333
fileOutputStream, 333
filterInputStream, 335
filterOutputStream, 335
final, 33, 123
flowLayout, 271
frame, 235
fully qualified name, 118
hiding, 177
identifiers, 124
importing packages, 176
InetAddress, 354
inputStream, 325
label, 241
lineNumberInputStream, 337
list, 250
menuItem, 265
modifiers, 33, 119
name space, 34, 129
naming, 124
networking, 353
object, 34
outputStream, 325
panel, 238
pipedInputStream, 339
pipedOutputStream, 339
printStream, 340
private, 33
protocols, 158
public, 33, 120
pushbackInputStream, 342
runtime, 194
scrollbar, 258
sequenceInputStream, 342
socket, 355
stringBufferInputStream, 343
super( ), 142
superclass, 34
System, 321
textArea, 253
textField, 253
throwable, 182
URL, 364
variables, 148
WriteAFile, 185
CLASSPATH, 171, 173, 174
Client, 350
Client/server technology, 350
Code parameter, 27
Color method, 37
Command line arguments, 86
indexing, 89
numeric, 89
passing arguments, 87
reading, 87
Comments, 30
styles, 59
tags, 67
405
406 Index
Common Gateway Interface, 10
Compilers, 7, 53
Component class
bounds( ), 232
disable( ), 232
enable([Boolean]), 232
getFontMetrics( ), 232
getGraphics( ), 232
getParent, 232
handleEvent(Event evt), 232
hide( ), 233
inside(int x, int y), 233
isEnabled( ), 233
isShowing( ), 233
isVisible( ), 233
locate(int x, int y), 233
location( ), 233
move(int x, int y), 233
repaint( ), 233
resize( ), 234
setFont( ), 234
show([Boolean]), 234
size( ), 235
Components, 60
Compound expressions, 104
Compound statements, 106
Constructors, 37, 138
body, 146
calling, 140
declaring, 140
FontMetrics, 48
Java default, 142
modifiers, 143
object creation, 148
protected, 143
public, 143
return type, 139
Container class, 290
Control flow, 106
Control structures
do...while, 108
for, 110
if...else, 106
labels, 111
D
Data types, 35
boolean, 78
byte, 76
casting, 103
char, 79
double, 78
float, 78
int, 71, 77
long, 71, 77
separators, 75
short, 76
string, 79
variables, 76
DataInputStream class, 330
DataOutputStream class, 330
Debugging, 181
Decrement operator, 98
Destroy( ) method, 222
Developers Kit, 17
Directories
Index
search path, 174
Disassembler program, 17
Distributed programming, 6
Distributed software, 10
Division, 98
Do...while, 108
Doc comment clauses, 119
Documenting classes, 63
Double buffering, 45
Double data type, 78
E
Encapsulation, 43
Equal to operators, 102
Error handling, 181
Errors
catching, 186
checking, 323
file not found, 189
input/output, 185
throws, 133
try clauses, 186
Evaluation operators, 101
Event class, 304
methods, 306
variables, 305
Event handling, 53
Events
hierarchy, 313
processing problems, 318
system, 315
types, 304
Exceptions, 15, 181, 182
class, 193
creating, 200
error, 191
file not found, 189
finally statements, 189
handler, 182
IOException, 185
try clauses, 186
URL, 364
Executable content, 10
Export statement, 228
Expressions
assignment, 105
writing, 104
Extending classes, 124
Extends keyword, 34
F
Fatal errors, 191
File
access, 292
execution, 292
input/output, 321
saving, 173
File Transfer Protocol. See FTP
FileInputStream class, 333
FileOutputStream class, 333
FilterInputStream, 335
FilterOutputStream class, 335
Final classes, 33
Final methods, 132
Finally statement, 189
Finger protocol, 349
Float data type, 78
Floating-point, 72
operators, 102
FlowLayout class, 271
declaration, 271
methods, 273
Font metrics, 48
Fonts, 43
For loops, 110
Frame class, 235
declaration, 235
dispose( ), 237
getIconImage( ), 237
getMenuBar, 237
getTitle( ), 237
hierarchy, 235
isResizable( ), 238
remove( ), 238
407
408 Index
setCursor( ), 238
setIconImage( ), 238
setMenuBar( ), 238
setResizeable( ), 238
setTitle( ), 238
FTP, 349
G
Garbage collection, 6, 15, 37
Gateways, 355
Graphical User Interface
button class, 243
canvas class, 244
checkbox class, 245
choice class, 247
component class, 231
frame class, 235
label class, 241
lists, 250
menu class, 263
menu items, 265
menuBar class, 261
panel class, 238
scrollbar class, 258
text areas, 253
text fields, 253
Graphics methods, 46
GridBagLayout class, 278
declaration, 281
methods, 281
variables to customize, 278
GridLayout class, 276
declaration, 277
methods, 277
H
Header files, 13
Height parameter, 27
Helper programs, 17
Hexadecimal format, 71
History of Java, 8
HotJava, 6, 10
HTML. See Hyper Text Markup
Language
applet tags, 39
HTTP, 349
Hyper Text Markup Language, 25
Hyper Text Transfer Protocol. See HTTP
I
Identifiers, 65
class, 118
classes, 124
errors, 67
If...else, 106
Image buffer, 41
Images, 298
Implements clause, 126
Implements keywords, 34
Import statements, 31, 228
Including packages, 31
Increment operator, 98
Index, 84
InetAddress class, 354
Init( ), 130
Input streams, 321, 324
InputStream class, 325
methods, 325
Instanceof operator, 17, 168
Int data type, 77
Integers, 71
literals, 72
operators, 93, 97
Interfaces, 34, 158
casting, 165
class, 126
declaring, 161
design issues, 160
implementation tips, 167
implementing, 161
implements clauses, 126
keyword, 161
Index
layout manager, 271
runnable, 34
tips on using, 165
Internet
addressing, 353
java.net package, 352
Request for Comments, 351
IOException, 324
J
Java language
advantages, 4
benefits, 11
compared to C++, 9
developers kit, 7, 17
history, 8
interfaces, 158
jargon, 5
tools, 8
virtual machine, 6
JAVAC, 7, 53
JAVADOC.EXE, 63
Java-enabled, 7
JAVAP, 17
JavaScript, 7
Just-in-Time compiler, 7
K
Keyboard events, 311
keyDown( ), 311
keyUp( ), 311
Keywords, 68
class, 124
extends, 34, 124
implements, 34, 162
interface, 161
list of keywords, 69
super, 135
this, 50, 135
L
Label class, 241
declaration, 241
getAlignment( ), 242
getText( ), 242
hierarchy, 241
setAlignment( ), 242
setText( ), 243
Labels, 111
Layout manager, 228, 270
borderLayout class, 274
cardLayout class, 282
flowLayout class, 271
gridBagLayout class, 278
gridLayout class, 276
Lexical structures, 58
comments, 59
identifiers, 65
keywords, 68
separators, 75
LineNumberInputStream class, 337
List class, 250
Literals, 71
character, 73
numeric, 71
Logical operators, 100
Long data type, 77
Long integers, 71
M
Main programs, 27
Menu class, 263
declaration, 264
hierarchy, 263
methods, 264
MenuBar class, 262
declaration, 262
hierarchy, 262
methods, 262
MenuItem class, 265
409
410 Index
declaration, 266
hierarchy, 266
methods, 267
Menus, 32
creating, 229
Methods, 7, 38, 130
abstract, 132
action( ), 294
add( ), 274
applet class, 288
body, 134
catch( ), 185
color, 37
constructors, 138
createImage( ), 230
declaring, 130
defined, 28
destroy( ), 222
disable( ), 230
documenting, 63
drawString( ), 48
final, 132
getGraphics( ), 41
getMessage, 198
getParameter( ), 40
graphics, 46
handleEvent( ), 53
hide( ), 230
init( ), 28, 130
main( ), 87
modifiers, 131
native, 132, 292
overloading, 137
overriding, 43, 137, 170
paint( ), 29, 44
parameter lists, 133
parse( ), 89
private, 132
protected, 131
public, 131
resume( ), 220
return type, 133
Run( ), 29, 214
sleep( ), 50
start( ), 29
static, 132
stop( ), 51, 221
suspend( ), 220
synchronized, 132
throwing an exception, 194
throws, 133
valueOf( ), 89
write( ), 184
yield, 221
Modifiers
abstract, 121
constructor, 143
final, 123, 150
method, 131
modifiers, 33, 119
public, 120
transient, 150
volatile, 150
Modulus operator, 99
Mouse events, 304, 307
mouseDown( ), 307
mouseDrag( ), 309
mouseEnter( ), 310
mouseExit( ), 310
mouseMove( ), 309
mouseUp( ), 308
Multidimensional arrays, 85
Multiple inheritance, 14
Multiplication, 98
Multithreading, 7, 208
grouping, 226
synchronizing, 222
N
Name space, 129
Native methods, 132, 292
Negation operator, 97
Netscape
applet, 294
Network communication, 292
Index
Network News Transfer Protocol.
See NNTP
Networking, 347
between applets, 367
classes, 353
client/server, 350
concerns, 360
java.net, 352
ports, 350
protocols, 348
sockets, 355
URLs, 364
New lines, 356
NNTP, 349
Not equal to operators, 102
Numeric literals, 71
O
Object-oriented programming, 12
Objects
arrays, 82
class, 34
creation, 148
declaring, 118
Octal integers, 71
Operators, 74, 93
addition, 98
assignment, 95, 102
binary, 98
binary integer, 99
bitwise, 99
bitwise complement, 97
boolean negation, 100
compound expressions, 104
decrement, 98
division, 98
equal to, 102
evaluation, 101
floating-point, 102
increment, 98
instanceof, 17, 168
integer, 97
P
Packages, 30
applet, 31
awt, 31
case sensitivity, 171
classes, 30
creating, 168
documenting, 63
import keyword, 169
java.io, 322
java.lang, 30
java.net, 352
naming, 170
public classes, 172
standard Java, 177
Paint( ) method, 44
Panel class, 238
declaration, 240
hierarchy, 240
setlayout( ), 241
Parameter lists
constructor, 146
Parameters, 39
code, 27
height, 27
speed, 26
values, 27
width, 27
Parsing, 89
411
412 Index
Performance issues
threading, 51
PipedInputStream class, 339
PipedOutputStream class, 339
Pointers, 13
Ports, 350
Internet, 351
numbers, 350
Precedence (operators), 93
PrintStream class, 340
Private
constructors, 143
methods, 132
Processing parameters, 39
Protected
constructors, 143
methods, 131
Protocols
class, 158
finger, 349
FTP, 349
Internet, 351
NNTP, 349
Request for Comments, 351
SMTP, 348
TCP/IP, 348
WhoIs, 349
Public
classes, 33, 120
constructors, 143
keyword, 162
method, 131
PushbackInputStream class, 342
R
Request for Comments. See Request for
Comments
Resizing, 239
Resource allocation, 37
Resume( ) method, 220
Return type, 133
Returns, 356
S
Savings files, 173
Scripting language, 7
Scrollbar class, 258
hierarchy, 260
methods, 260
Security, 12, 15, 292
Seprators, 75
SequenceInputStream class, 342
Servers, 350
sample, 361
setting up, 360
ServerSocket class, 360
Shadowing, 129
Short type, 76
Simple Mail Transfer Protocol.
See SMTP
Simple statements, 105
Single inheritance, 121
Sleep( ) method, 50, 219
Socket class, 360
Sockets, 355
Sounds, 297
Source code
saving, 173
Statements, 105
catch, 187
compound, 106
control flow, 106
finally, 189
simple, 105
switch, 109
using semi-colons, 106
writing, 104
Static methods, 132
Status bar, 296
Stop( ) method, 221
Index
Streams, 321
inputStream, 324
outputStream, 324
String arrays, 16
String type, 79
StringBufferInputStream class, 343
Subclasses, 44
Subtraction, 98
Super classes, 16
Super keyword, 135
Super( ), 142
Suspend( ) method
suspending execution, 220
Switch, 109
Synchronized methods, 132
System class, 321
system.in, 322
System events, 315
action( ), 317
handleEvent( ), 317
T
Tags, 67
TCP/IP, 348
Ternary operators, 102
TextArea class, 253
declaration, 254
hierarchy, 254
methods, 255
TextField class, 253
declaration, 254
hierarchy, 254
methods, 255
This keyword, 50, 135
ThreadGroup, 226
Threads, 29, 49, 182, 207, 212
blocking, 217
creating, 211
destroy( ) method, 222
first in first out, 217
grouping, 226
initializing, 215
413
U
Unary, 97
Unicode, 73
Uniform Resource Locator. See URLs
URLs, 364
User input, 52
User interface
component class, 231
layout manager, 271
menus, 229
V
Variable declarations, 35
Variables
constructors, 37
declarations, 79
modifiers, 149
naming, 36
414 Index
static, 149
variables, 148
vs. types, 76
Virtual machine, 6, 210
Volatile modifiers, 150
W
Web sites
Coriolis, 25
Javasoft, 54
While, 108
Y
Yield( ) method, 221