APPLYING JAVA
Chapter 32: Scrabblet: A Multiplayer Word Game 1097
mult *= 2;
else if (t == l3)
lscore *= 3;
else if (t == l2)
lscore *= 2;
if (i == -1) {
letters_seen++;
}
}
word_score += lscore;
n++;
x += xinc;
y += yinc;
}
word_score *= mult;
One last error check is done on the main word only. Since the loop ends whenever
it hits a blank square or the edge of the board, it should cover all of the freshly played
tiles, as well as some previously played ones. If it sees fewer tiles, then there must have
been a gap in them, which is an illegal position, so it returns null. If that test is passed,
it checks to see if all seven tiles were played, awarding a 50-point bonus if they were.
After inspecting the main word, findwords( ) inverts the sense of horizontal and looks
for orthogonal words on the subsequent passes.
if (i == -1) {
// first pass...
}
// if we didn't see all the letters, then there was a gap,
// which is an illegal tile position.
if (letters_seen != ntiles) {
return null;
}
if (ntiles == 7) {
turn_score += 50;
}
// after the first pass, switch to looking the other way.
horizontal = !horizontal;
260 Java™ 2: The Complete Reference
throw
So far, you have only been catching exceptions that are thrown by the Java run-time
system. However, it is possible for your program to throw an exception explicitly,
using the throw statement. The general form of throw is shown here:
throw ThrowableInstance;
Here, ThrowableInstance must be an object of type Throwable or a subclass of
Throwable. Simple types, such as int or char, as well as non-Throwable classes, such
as String and Object, cannot be used as exceptions. There are two ways you can obtain
a Throwable object: using a parameter into a catch clause, or creating one with the new
operator.
The flow of execution stops immediately after the throw statement; any subsequent
statements are not executed. The nearest enclosing try block is inspected to see if it has
a catch statement that matches the type of the exception. If it does find a match, control
is transferred to that statement. If not, then the next enclosing try statement is
inspected, and so on. If no matching catch is found, then the default exception handler
halts the program and prints the stack trace.
Here is a sample program that creates and throws an exception. The handler that
catches the exception rethrows it to the outer handler.
// Demonstrate throw.
class ThrowDemo {
static void demoproc() {
try {
throw new NullPointerException("demo");
} catch(NullPointerException e) {
System.out.println("Caught inside demoproc.");
throw e; // rethrow the exception
}
}
}
public static void main(String args[]) {
try {
demoproc();
} catch(NullPointerException e) {
System.out.println("Recaught: " + e);
}
}
1110 Java™ 2: The Complete Reference
represent the blank tile in slot 0, and A through Z in 1 through 26. The letter_counts
array says how many of each letter are in a full bag. For example, letter_counts[1] is 9,
which says there are nine A tiles in the bag. Similarly, the letter_points array maps
each letter to its point value. The A tiles are worth only 1 point, and the lone Z is worth
10. There are 100 letters stored in the array called letters. The number of letters actually
left in the bag during game play is stored in n.
import java.util.Random;
class Bag {
private Random rand;
private int letter_counts[] = {
2, 9, 2, 2, 4, 12, 2, 3, 2, 9, 1, 1, 4, 2,
6, 8, 2, 1, 6, 4, 6, 4, 2, 2, 1, 2, 1
};
private int letter_points[] = {
0, 1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3,
1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10
};
private Letter letters[] = new Letter[100];
private int n = 0;
Bag( )
The Bag constructor takes the seed and makes a Random object out of it. It then scans
through the letter_counts array, making the right number of new Letter objects, being
careful to replace the blank tile with an asterisk. It then calls putBack( ) for each letter,
to put them in the bag.
Bag(int seed) {
rand = new Random(seed);
for (int i = 0; i < letter_counts.length; i++) {
for (int j = 0; j < letter_counts[i]; j++) {
Letter l = new Letter(i == 0 ? '*' : (char)('A' + i - 1),
letter_points[i]);
putBack(l);
}
}
}
890 Java™ 2: The Complete Reference
Second, the OurButton Bean provides a push-button functionality. We will have one
button labeled “Rotate X” to rotate the molecule along its X axis and another button
labeled “Rotate Y” to rotate the molecule along its Y axis.
Figure 25-2 shows how this application appears.
Create and Configure an Instance of the Molecule Bean
Follow these steps to create and configure an instance of the Molecule Bean:
1. Position the cursor on the ToolBox entry labeled Molecule and click the left
mouse button. You should see the cursor change to a cross.
2. Move the cursor to the BeanBox display area and click the left mouse button in
approximately the area where you wish the Bean to be displayed. You should
see a rectangular region appear that contains a 3-D display of a molecule. This
area is surrounded by a hatched border, indicating that it is currently selected.
3. You can reposition the Molecule Bean by positioning the cursor over one of the
hatched borders and dragging the Bean.
4. You can change the molecule that is displayed by changing the selection in the
Properties window. Notice that the Bean display changes immediately when
you change the selected molecule.
Figure 25-2.
The Molecule and OurButton Beans
666 Java™ 2: The Complete Reference
If a mouse has a wheel, it is located between the left and right buttons. Mouse wheels
are used for scrolling. MouseWheelEvent defines these two integer constants.
WHEEL_BLOCK_SCROLL
WHEEL_UNIT_SCROLL
A page-up or page-down scroll event occurred.
A line-up or line-down scroll event occurred.
MouseWheelEvent defines the following constructor.
MouseWheelEvent(Component src, int type, long when, int modifiers,
int x, int y, int clicks, boolean triggersPopup,
int scrollHow, int amount, int count)
Here, src is a reference to the object that generated the event. The type of the event
is specified by type. The system time at which the mouse event occurred is passed in
when. The modifiers argument indicates which modifiers were pressed when the event
occurred. The coordinates of the mouse are passed in x and y. The number of clicks
the wheel has rotated is passed in clicks. The triggersPopup flag indicates if this event
causes a pop-up menu to appear on this platform. The scrollHow value must be either
WHEEL_UNIT_SCROLL or WHEEL_BLOCK_SCROLL. The number of units to scroll
is passed in amount. The count parameter indicates the number of rotational units that
the wheel moved.
MouseWheelEvent defines methods that give you access to the wheel event.
To obtain the number of rotational units, call getWheelRotation( ), shown here.
int getWheelRotation( )
It returns the number of rotational units. If the value is positive, the wheel moved
counterclockwise. If the value is negative, the wheel moved clockwise.
To obtain the type of scroll, call getScrollType( ), shown next.
int getScrollType( )
It returns either WHEEL_UNIT_SCROLL or WHEEL_BLOCK_SCROLL.
If the scroll type is WHEEL_UNIT_SCROLL, you can obtain the number of units
to scroll by calling getScrollAmount( ). It is shown here.
int getScrollAmount( )
The TextEvent Class
Instances of this class describe text events. These are generated by text fields and text
areas when characters are entered by a user or program. TextEvent defines the integer
constant TEXT_VALUE_CHANGED.
The one constructor for this class is shown here:
TextEvent(Object src, int type)
394 Java™ 2: The Complete Reference
Method
static Long decode(String str)
throws NumberFormatException
double doubleValue( )
boolean equals(Object LongObj)
float floatValue( )
static Long getLong(String propertyName)
static Long getLong(String propertyName,
long default)
static Long getLong(String propertyName,
Long default)
int hashCode( )
int intValue( )
long longValue( )
Description
Returns a Long object that
contains the value specified by
the string in str.
Returns the value of the invoking
object as a double.
Returns true if the invoking long
object is equivalent to LongObj.
Otherwise, it returns false.
Returns the value of the invoking
object as a float.
Returns the value associated
with the environmental property
specified by propertyName. A
null is returned on failure.
Returns the value associated
with the environmental property
specified by propertyName.
The value of default is returned
on failure.
Returns the value associated
with the environmental property
specified by propertyName.
The value of default is returned
on failure.
Returns the hash code for the
invoking object.
Returns the value of the invoking
object as an int.
Returns the value of the invoking
object as a long.
Table 14-6.
The Methods Defined by Long (continued)
THE JAVA LIBRARY
Chapter 18: Networking 595
Applets may only establish socket connections back to the host from which the applet was
downloaded. This restriction exists because it would be dangerous for applets loaded
through a firewall to have access to any arbitrary machine.
There are two kinds of TCP sockets in Java. One is for servers, and the other is for
clients. The ServerSocket class is designed to be a “listener,” which waits for clients to
connect before doing anything. The Socket class is designed to connect to server
sockets and initiate protocol exchanges.
The creation of a Socket object implicitly establishes a connection between the client
and server. There are no methods or constructors that explicitly expose the details of
establishing that connection. Here are two constructors used to create client sockets:
Socket(String hostName, int port)
Socket(InetAddress ipAddress, int port)
Creates a socket connecting the local
host to the named host and port; can
throw an UnknownHostException or
an IOException.
Creates a socket using a preexisting
InetAddress object and a port; can throw
an IOException.
A socket can be examined at any time for the address and port information
associated with it, by use of the following methods:
InetAddress getInetAddress( )
int getPort( )
int getLocalPort( )
Returns the InetAddress associated with
the Socket object.
Returns the remote port to which this
Socket object is connected.
Returns the local port to which this
Socket object is connected.
Once the Socket object has been created, it can also be examined to gain access to
the input and output streams associated with it. Each of these methods can throw an
IOException if the sockets have been invalidated by a loss of connection on the Net.
These streams are used exactly like the I/O streams described in Chapter 17 to send
and receive data.
InputStream getInputStream( )
OutputStream getOutputStream( )
Returns the InputStream associated
with the invoking socket.
Returns the OutputStream associated
with the invoking socket.
1138 Java™ 2: The Complete Reference
Here, release is a string that designates the release or version in which this feature
became available. The @since tag can be used in documentation for variables, methods,
and classes.
@throws
The @throws tag has the same meaning as the @exception tag.
{@value}
Displays the value of a constant, which must be a static field.
@version
The @version tag specifies the version of a class. It has the following syntax:
@version info
Here, info is a string that contains version information, typically a version number,
such as 2.2. The @version tag can be used only in documentation for a class. You may
need to specify the -version option when executing javadoc in order for the @version
field to be included in the HTML documentation.
The General Form of a Documentation
Comment
After the beginning /**, the first line or lines become the main description of your class,
variable, or method. After that, you can include one or more of the various @ tags. Each
@ tag must start at the beginning of a new line or follow an asterisk (*) that is at the
start of a line. Multiple tags of the same type should be grouped together. For example,
if you have three @see tags, put them one after the other.
Here is an example of a documentation comment for a class:
/**
* This class draws a bar chart.
* @author Herbert Schildt
* @version 3.2
*/
What javadoc Outputs
The javadoc program takes as input your Java program’s source file and outputs
several HTML files that contain the program’s documentation. Information about each
THE JAVA LIBRARY
Chapter 17: Input/Output: Exploring java.io 539
The ObjectInputStream.GetField and ObjectOutputStream.PutField inner classes
were added by Java 2. The java.io package also contains two classes that were deprecated
by Java 2 and are not shown in the preceding table: LineNumberInputStream and
StringBufferInputStream. These classes should not be used for new code.
The following interfaces are defined by java.io:
DataInput FilenameFilter ObjectOutput
DataOutput ObjectInput ObjectStreamConstants
Externalizable ObjectInputValidation Serializable
FileFilter
The FileFilter interface was added by Java 2.
As you can see, there are many classes and interfaces in the java.io package. These
include byte and character streams, and object serialization (the storage and retrieval of
objects). This chapter examines several of the most commonly used I/O components,
beginning with one of the most unique: File.
File
Although most of the classes defined by java.io operate on streams, the File class does
not. It deals directly with files and the file system. That is, the File class does not
specify how information is retrieved from or stored in files; it describes the properties
of a file itself. A File object is used to obtain or manipulate the information associated
with a disk file, such as the permissions, time, date, and directory path, and to navigate
subdirectory hierarchies.
Files are a primary source and destination for data within many programs.
Although there are severe restrictions on their use within applets for security reasons,
files are still a central resource for storing persistent and shared information. A
directory in Java is treated simply as a File with one additional property—a list of
filenames that can be examined by the list( ) method.
The following constructors can be used to create File objects:
File(String directoryPath)
File(String directoryPath, String filename)
File(File dirObj, String filename)
File(URI uriObj)
Here, directoryPath is the path name of the file, filename is the name of the file, dirObj is a
File object that specifies a directory, and uriObj is a URI object that describes a file. The
fourth constructor was added by Java 2, version 1.4.
The following example creates three files: f1, f2, and f3. The first File object is
constructed with a directory path as the only argument. The second includes two
arguments—the path and the filename. The third includes the file path assigned to f1
and a filename; f3 refers to the same file as f2.
594 Java™ 2: The Complete Reference
Here is the output produced by this program. (Of course, the output you see will be
slightly different.)
default/206.148.209.138
osborne.com/198.45.24.162
www.nba.com/64.241.238.153
www.nba.com/64.241.238.142
Instance Methods
The InetAddress class also has several other methods, which can be used on the objects
returned by the methods just discussed. Here are some of the most commonly used.
boolean equals(Object other)
byte[ ] getAddress( )
String getHostAddress( )
String getHostName( )
boolean isMulticastAddress( )
String toString( )
Returns true if this object has the same Internet
address as other.
Returns a byte array that represents the object’s
Internet address in network byte order.
Returns a string that represents the host address
associated with the InetAddress object.
Returns a string that represents the host name
associated with the InetAddress object.
Returns true if this Internet address is a multicast
address. Otherwise, it returns false.
Returns a string that lists the host name and the
IP address for convenience.
Internet addresses are looked up in a series of hierarchically cached servers. That
means that your local computer might know a particular name-to-IP-address mapping
automatically, such as for itself and nearby servers. For other names, it may ask a local
DNS server for IP address information. If that server doesn’t have a particular address,
it can go to a remote site and ask for it. This can continue all the way up to the root
server, called InterNIC (internic.net). This process might take a long time, so it is wise
to structure your code so that you cache IP address information locally rather than look
it up repeatedly.
TCP/IP Client Sockets
TCP/IP sockets are used to implement reliable, bidirectional, persistent, point-to- point,
stream-based connections between hosts on the Internet. A socket can be used to connect
Java’s I/O system to other programs that may reside either on the local machine or on
any other machine on the Internet.
THE JAVA LANGUAGE
Chapter 12: I/O, Applets, and Other Topics 329
import java.awt.*;
import java.applet.*;
public class SimpleApplet extends Applet {
public void paint(Graphics g) {
g.drawString("A Simple Applet", 20, 20);
}
}
This applet begins with two import statements. The first imports the Abstract Window
Toolkit (AWT) classes. Applets interact with the user through the AWT, not through the
console-based I/O classes. The AWT contains support for a window-based, graphical
interface. As you might expect, the AWT is quite large and sophisticated, and a complete
discussion of it consumes several chapters in Part II of this book. Fortunately, this simple
applet makes very limited use of the AWT. The second import statement imports the
applet package, which contains the class Applet. Every applet that you create must be a
subclass of Applet.
The next line in the program declares the class SimpleApplet. This class must be
declared as public, because it will be accessed by code that is outside the program.
Inside SimpleApplet, paint( ) is declared. This method is defined by the AWT
and must be overridden by the applet. paint( ) is called each time that the applet
must redisplay its output. This situation can occur for several reasons. For example,
the window in which the applet is running can be overwritten by another window and
then uncovered. Or, the applet window can be minimized and then restored. paint( ) is
also called when the applet begins execution. Whatever the cause, whenever the applet
must redraw its output, paint( ) is called. The paint( ) method has one parameter of
type Graphics. This parameter contains the graphics context, which describes the
graphics environment in which the applet is running. This context is used whenever
output to the applet is required.
Inside paint( ) is a call to drawString( ), which is a member of the Graphics class.
This method outputs a string beginning at the specified X,Y location. It has the
following general form:
void drawString(String message, int x, int y)
Here, message is the string to be output beginning at x,y. In a Java window, the upper-left
corner is location 0,0. The call to drawString( ) in the applet causes the message “A Simple
Applet” to be displayed beginning at location 20,20.
Notice that the applet does not have a main( ) method. Unlike Java programs, applets
do not begin execution at main( ).Infact, most applets don’t even have a main( ) method.
Instead, an applet begins execution when the name of its class is passed to an applet viewer
or to a network browser.
THE JAVA LIBRARY
Chapter 16: java.util Part 2: More Utility Classes 509
Method
void flip(int index)
void flip(int startIndex,
int endIndex)
boolean get(int index)
BitSet get(int startIndex,
int endIndex)
int hashCode( )
boolean intersects(BitSet bitSet)
boolean isEmpty( )
int length( )
int nextClearBit(int startIndex)
int nextSetBit(int startIndex)
void or(BitSet bitSet)
void set(int index)
Description
Reverses the bit specified by index. (Added by
Java 2, version 1.4)
Reverses the bits from startIndex to endIndex–1.
(Added by Java 2, version 1.4)
Returns the current state of the bit at the
specified index.
Returns a BitSet that consists of the bits from
startIndex to endIndex–1. The invoking object is
not changed. (Added by Java 2, version 1.4)
Returns the hash code for the invoking object.
Returns true if at least one pair of corresponding
bits within the invoking object and bitSet are 1.
(Added by Java 2, version 1.4)
Returns true if all bits in the invoking object
are zero. (Added by Java 2, version 1.4)
Returns the number of bits required to hold
the contents of the invoking BitSet. This value
is determined by the location of the last 1 bit.
(Added by Java 2)
Returns the index of the next cleared bit, (that
is, the next zero bit), starting from the index
specified by startIndex. (Added by Java 2,
version 1.4)
Returns the index of the next set bit (that is, the
next 1 bit), starting from the index specified by
startIndex.Ifnobit is set, –1 is returned. (Added
by Java 2, version 1.4)
ORs the contents of the invoking BitSet object
with that specified by bitSet. The result is
placed into the invoking object.
Sets the bit specified by index.
Table 16-2.
The Methods Defined by BitSet (continued)
Index 1153
concatenating, 185–186,
352–353. 364, 372–373
creating, 348–351
extracting characters from,
355–356
length, obtaining,
186–187, 351
literals, 52, 351
modifying, 363–366
as objects, 52, 70–71,
181–182, 348
parsing formatted input, 506
reading, 320–322
representations of numbers,
converting, 392–393, 396
searching, 361–363
String class, 28, 185, 348
constructors, 348–350
StringBuffer class, 185, 348, 361,
369–377
StringBufferInputStream class, 539
StringIndexOutOfBounds
exception, 266
StringTokenizer class, 506–508
methods, table of, 507
stringWidth( ), 725, 726
Stroustrup, Bjarne, 7
Stubs (RMI), 876–877
Subclass, 190, 192
subList( ), 446, 447
subMap( ), 465
subSequence( ), 368, 376
subSet( ), 447, 448
substring( ), 363–364, 375
Sun Microsystems, 7, 588
super, 176, 197–203
and superclass constructors,
197–202, 206
and instance variables,
202–203
Superclass, 190, 192
suspend( ), 15, 305–307, 308,
424, 426
Swing, 922–948
and Bean Builder, 891
component classes, list of
some, 922
switch statement, 104–108
Synchronization, 276, 292–297
and collections, 475
and deadlock, 302–304
race condition and, 294
via synchronized block,
295–297
via synchronized method,
292–295
synchronized modifier, 292
used with method, 292,
295
used with object, 295–297
synchronizedList( ), 475, 478
synchronizedSet( ), 475, 478
System class, 29, 318, 407
methods, table of, 408–410
System.err standard error
stream, 318
System.in standard input stream,
318, 319
System.in.read( ), 114
System.out standard output
stream, 318, 322, 323, 324
T
Tabbed panes, 936–939
Tables, Swing, 946–948
tailMap( ), 465
tailSet( ), 447, 448
tan( ), 420
TCP/IP, 15, 588, 1070
client sockets, 594–597
disadvantages of, 623
reserved sockets, 589–590
server sockets, 601–602
See also Transmission
Control Protocol (TCP)
Temple, Robert, 1012
Ternary operator (?:), 92, 95–96
Text fields, 758–761
Swing, 925–926
Text formatting, 878–882
Text output, managing, 723–733
TextArea class, 761–763
textChanged( ), 672
TextComponent class, 758, 761
TextEvent class, 658, 666–667
TextField class, 758, 759
TextListener interface, 669, 672
this, 149–150, 176
Thompson, Ken, 5, 588
Thread(s)
creating, 280–286
daemon, 532
and deadlock, 302–304, 308
definition of, 274
group, 279, 426–432
main, 277, 282, 286
messaging, 276–277, 297–302
possible states of, 275
priorities, 275–276,
289–292, 423
resuming, 305–310, 426
stopping, 305–310
suspending, 277, 278, 279,
305–310, 426
synchronization. See
Synchronization
Thread class, 15, 277,
423–426, 531
constructors, 280, 284, 423
extending, 282–284
methods, table of, 424–426
ThreadGroup class, 426–432
methods, table of, 427–428
ThreadLocal class, 380, 432
throw, 250, 260–261
Throwable class, 251, 254, 267,
269–270, 434
methods defined by, table
of, 267
obtaining object of, 260–261
throws, 250, 261–262, 265
TickTock Bean, 902–903
Time. See Date class
Timer class, 531–534
TimerTask class, 531–534
Timestamps, 659
TimeZone class, 521–522
methods defined by, table
of, 521–522
toArray( ), 444, 445, 451–452
toBinaryString( ), 397
toCharArray( ), 356
toDegrees( ), 422
toHexString( ), 397
Tokens, 506
toLowerCase( ), 367
Tomcat, 951–952
toOctalString( ), 397
Toolkit class, 720
toRadians( ), 422
toString( ), 221, 254, 268, 323,
353–354, 366, 387, 456, 510,
511, 656
totalMemory( ), 404, 405–406
toUpperCase( ), 367
transient modifier, 331–332
translatePoint( ), 665
Transmission Control
Protocol (TCP)
definition of, 589
and stream-based I/O, 592
See also TCP/IP
TreeExpansionEvent class, 942
TreeExpansionListener
interface, 942
TreeMap class, 466, 468–470, 504
TreeNode class, 942
816 Java™ 2: The Complete Reference
Figure 23-4.
Sample output from TrackedImageLoad
0 and fully opaque is 255. The width and height of the resulting image are passed in
width and height. The starting point in the pixel array to begin reading data is passed in
offset. The width of a scan line (which is often the same as the width of the image) is
passed in scanLineWidth.
The following short example generates a MemoryImageSource object using a
variation on a simple algorithm (a bitwise-exclusive-OR of the x and y address of each
pixel) from the book Beyond Photography, The Digital Darkroom by Gerard J. Holzmann
(Prentice Hall, 1988).
50 Java™ 2: The Complete Reference
A Closer Look at Literals
Literals were mentioned briefly in Chapter 2. Now that the built-in types have been
formally described, let’s take a closer look at them.
Integer Literals
Integers are probably the most commonly used type in the typical program. Any whole
number value is an integer literal. Examples are 1, 2, 3, and 42. These are all decimal
values, meaning they are describing a base 10 number. There are two other bases which
can be used in integer literals, octal (base eight) and hexadecimal (base 16). Octal values
are denoted in Java by a leading zero. Normal decimal numbers cannot have a leading
zero. Thus, the seemingly valid value 09 will produce an error from the compiler,
since 9 is outside of octal’s 0 to 7 range. A more common base for numbers used by
programmers is hexadecimal, which matches cleanly with modulo 8 word sizes, such
as 8, 16, 32, and 64 bits. You signify a hexadecimal constant with a leading zero-x, (0x
or 0X). The range of a hexadecimal digit is 0 to 15, so A through F (or a through f ) are
substituted for 10 through 15.
Integer literals create an int value, which in Java is a 32-bit integer value. Since
Java is strongly typed, you might be wondering how it is possible to assign an integer
literal to one of Java’s other integer types, such as byte or long, without causing a type
mismatch error. Fortunately, such situations are easily handled. When a literal value is
assigned to a byte or short variable, no error is generated if the literal value is within the
range of the target type. Also, an integer literal can always be assigned to a long variable.
However, to specify a long literal, you will need to explicitly tell the compiler that the
literal value is of type long. You do this by appending an upper- or lowercase L to
the literal. For example, 0x7ffffffffffffffL or 9223372036854775807L is the largest long.
Floating-Point Literals
Floating-point numbers represent decimal values with a fractional component. They
can be expressed in either standard or scientific notation. Standard notation consists
of a whole number component followed by a decimal point followed by a fractional
component. For example, 2.0, 3.14159, and 0.6667 represent valid standard-notation
floating-point numbers. Scientific notation uses a standard-notation, floating-point number
plus a suffix that specifies a power of 10 by which the number is to be multiplied. The
exponent is indicated by an E or e followed by a decimal number, which can be positive
or negative. Examples include 6.022E23, 314159E–05, and 2e+100.
Floating-point literals in Java default to double precision. To specify a float literal,
you must append an F or f to the constant. You can also explicitly specify a double literal
by appending a D or d. Doing so is, of course, redundant. The default double type
consumes 64 bits of storage, while the less-accurate float type requires only 32 bits.
436 Java™ 2: The Complete Reference
Method
char charAt(int idx)
int length( )
CharSequence
subSequence(int startIdx, int stopIdx)
String toString( )
Description
Returns the character at the index
specified by idx.
Returns the number of characters in
the invoking sequence.
Returns a subset of the invoking
sequence beginning at startIdx and
ending at stopIdx–1.
Returns the String equivalent of the
invoking sequence.
Table 14-20.
The Methods Defined by CharSequence
The CharSequence Interface
Java 2, version 1.4 adds the CharSequence interface. CharSequence defines methods
that grant read-only access to a sequence of characters. These methods are shown
in Table 14-20. This interface is implemented by String and StringBuffer. It is also
implemented by CharBuffer, which is in the new java.nio package (described later
in this book).
The Comparable Interface
Objects of classes that implement Comparable can be ordered. In other words, classes
that implement Comparable contain objects that can be compared in some meaningful
manner. The Comparable interface declares one method that is used to determine what
Java 2 calls the natural ordering of instances of a class. The signature of the method is
shown here:
int compareTo(Object obj)
This method compares the invoking object with obj. It returns 0 if the values are equal.
A negative value is returned if the invoking object has a lower value. Otherwise, a
positive value is returned.
This interface is implemented by several of the classes already reviewed in this
book. Specifically, the Byte, Character, Double, Float, Long, Short, String, and Integer
classes define a compareTo( ) method. In addition, as the next chapter explains, objects
that implement this interface can be used in various collections. Comparable was
added by Java 2.
THE JAVA LANGUAGE
Chapter 8: Inheritance 193
}
void sum() {
total = i + j; // ERROR, j is not accessible here
}
class Access {
public static void main(String args[]) {
B subOb = new B();
subOb.setij(10, 12);
}
}
subOb.sum();
System.out.println("Total is " + subOb.total);
This program will not compile because the reference to j inside the sum( ) method
of B causes an access violation. Since j is declared as private, it is only accessible by
other members of its own class. Subclasses have no access to it.
A class member that has been declared as private will remain private to its class. It is not
accessible by any code outside its class, including subclasses.
A More Practical Example
Let’s look at a more practical example that will help illustrate the power of inheritance.
Here, the final version of the Box class developed in the preceding chapter will be
extended to include a fourth component called weight. Thus, the new class will contain
a box’s width, height, depth, and weight.
// This program uses inheritance to extend Box.
class Box {
double width;
double height;
double depth;
// construct clone of an object
Box(Box ob) { // pass object to constructor
width = ob.width;
height = ob.height;
THE JAVA LIBRARY
Chapter 14: Exploring java.lang 389
Method
static String toString(byte num)
static Byte valueOf(String str)
throws NumberFormatException
static Byte valueOf(String str, int radix)
throws NumberFormatException
Description
Returns a string that contains the
decimal equivalent of num.
Returns a Byte object that contains
the value specified by the string
in str.
Returns a Byte object that contains
the value specified by the string in
str using the specified radix.
Table 14-3.
The Methods Defined by Byte (continued)
Method
byte byteValue( )
int compareTo(Short s)
int compareTo(Object obj)
static Short decode(String str)
throws NumberFormatException
Description
Returns the value of the invoking
object as a byte.
Compares the numerical value of
the invoking object with that of s.
Returns 0 if the values are equal.
Returns a negative value if the
invoking object has a lower value.
Returns a positive value if the
invoking object has a greater value.
(Added by Java 2)
Operates identically to
compareTo(Short) if obj is of
class Short. Otherwise, throws
a ClassCastException. (Added
by Java 2)
Returns a Short object that
contains the value specified by
the string in str.
Table 14-4.
The Methods Defined by Short
146 Java™ 2: The Complete Reference
}
double depth;
// This is the constructor for Box.
Box() {
System.out.println("Constructing Box");
width = 10;
height = 10;
depth = 10;
}
// compute and return volume
double volume() {
return width * height * depth;
}
class BoxDemo6 {
public static void main(String args[]) {
// declare, allocate, and initialize Box objects
Box mybox1 = new Box();
Box mybox2 = new Box();
double vol;
// get volume of first box
vol = mybox1.volume();
System.out.println("Volume is " + vol);
}
}
// get volume of second box
vol = mybox2.volume();
System.out.println("Volume is " + vol);
When this program is run, it generates the following results:
Constructing Box
Constructing Box
Volume is 1000.0
Volume is 1000.0
326 Java™ 2: The Complete Reference
class ShowFile {
public static void main(String args[])
throws IOException
{
int i;
FileInputStream fin;
try {
fin = new FileInputStream(args[0]);
} catch(FileNotFoundException e) {
System.out.println("File Not Found");
return;
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Usage: ShowFile File");
return;
}
// read characters until EOF is encountered
do {
i = fin.read();
if(i != -1) System.out.print((char) i);
} while(i != -1);
}
}
fin.close();
To write to a file, you will use the write( ) method defined by FileOutputStream.
Its simplest form is shown here:
void write(int byteval) throws IOException
This method writes the byte specified by byteval to the file. Although byteval is declared
as an integer, only the low-order eight bits are written to the file. If an error occurs
during writing, an IOException is thrown. The next example uses write( ) to copy a
text file:
/* Copy a text file.
To use this program, specify the name
of the source file and the destination file.
1128 Java™ 2: The Complete Reference
}
out = s.getOutputStream();
host = s.getInetAddress().getHostName();
id = "" + i;
// tell the new one who it is...
write("id " + id + CRLF);
new Thread(this).start();
} catch (IOException e) {
System.out.println("failed ClientConnection " + e);
}
toString( )
We override toString( ) so that we can have a clean representation of this connection
for logging.
public String toString() {
return id + " " + host + " " + name;
}
getHost( ), getId( ), isBusy( ), and setBusy( )
We wrap host, id, and busy in public methods to allow read-only access.
public String getHost() {
return host;
}
public String getId() {
return id;
}
public boolean isBusy() {
return busy;
}
public void setBusy(boolean b) {
busy = b;
}
Chapter 16
java.util Part 2: More
Utility Classes
505
APPLYING JAVA
Chapter 29: The DynamicBillboard Applet 1035
}
}
fill_pixels = new int[width];
for(int f = 0; f < width; ++f) {
fill_pixels[f] = 0xFFFFFFFF;
}
int drop_amount;
int location;
public void init(Component owner, int[] current, int[] next) {
init(owner, current, next, CELLS, 160);
setupFillPixels(cell_w);
drop_amount = (cell_h / CELLS) * cell_w;
location = pixels_per_cell - ((cell_h / CELLS) / 2) * cell_w;
for(int c = CELLS - 1; c >= 0; --c) {
try { Thread.sleep(100); } catch (InterruptedException e) {}
Smash(c + 1);
try { Thread.sleep(150); } catch (InterruptedException e) {}
createCellFromWorkPixels(c);
location -= drop_amount;
}
work_pixels = null;
}
void Smash(int max_fold) {
System.arraycopy(next_pixels, pixels_per_cell - location,
work_pixels, 0, location);
int height = cell_h - location / cell_w;
float fold_offset_adder = (float)max_fold * FOLDS / (float)height;
float fold_offset = 0.0f;
int fold_width = cell_w - max_fold;
float src_y_adder = (float)cell_h / (float)height;
float src_y_offset = cell_h - src_y_adder / 2;
for(int p = pixels_per_cell - cell_w; p >= location; p -=
cell_w) {
System.arraycopy(fill_pixels, 0, work_pixels, p, cell_w);
System.arraycopy(current_pixels, (int)src_y_offset * cell_w,
work_pixels, p + (int)fold_offset, fold_width);
src_y_offset -= src_y_adder;
fold_offset += fold_offset_adder;
APPLYING JAVA
Chapter 31: The Lavatron Applet: A Sports Arena Display 1059
How Lavatron Works
Lavatron is able to present an interesting image onscreen because of a small trick that it
employs, and its side effect allows the applet to load very quickly. The reason it loads
so quickly is that there isn’t much data transmitted over the Net. The source image is a
JPEG image that is 64 times smaller than the displayed image. Each pixel in the source
image is scaled up to an 8×8-pixel square. Here is the trick that Lavatron uses to
produce the lightbulb effect. An 8×8-pixel image of a transparent circle surrounded by
a black bezel, with a white highlight for a dash of style, is painted over the scaled-up
color pixel. As an optimization, the bulbs are preassembled into an image that can be
painted once for each column. Figure 31-2 shows what the bulb mask looks like blown
up. The two white pixels are the highlight. The black pixels in the corner are opaque.
Finally, all of the gray pixels in the middle are transparent, to allow the lightbulb color
to show through.
Lavatron paints so fast because it doesn’t have to repaint what it has already drawn.
The technique of copying the area of the screen that’s good and painting just the portion
that’s new is used in many common operations involving scrolling. The awt.Graphics
function copyArea( ) takes a portion of an image defined by a rectangle and moves it
by an x,y offset from its starting location. As a graphics speed optimization, copyArea( )
is hard to beat. It consistently outperforms any other technique of image rendering,
such as the use of drawImage( ), or drawImage( ) through a clipRect( ). Building an
Figure 31-2.
A blown-up light bulb image
10 Java™ 2: The Complete Reference
when you read your e-mail, you are viewing passive data. Even when you download a
program, the program’s code is still only passive data until you execute it. However, a
second type of object can be transmitted to your computer: a dynamic, self-executing
program. Such a program is an active agent on the client computer, yet is initiated by
the server. For example, a program might be provided by the server to display properly
the data that the server is sending.
As desirable as dynamic, networked programs are, they also present serious
problems in the areas of security and portability. Prior to Java, cyberspace was
effectively closed to half the entities that now live there. As you will see, Java addresses
those concerns and, by doing so, has opened the door to an exciting new form of
program: the applet.
Java Applets and Applications
Java can be used to create two types of programs: applications and applets. An
application is a program that runs on your computer, under the operating system of that
computer. That is, an application created by Java is more or less like one created using C
or C++. When used to create applications, Java is not much different from any other
computer language. Rather, it is Java’s ability to create applets that makes it important.
An applet is an application designed to be transmitted over the Internet and executed by
a Java-compatible Web browser. An applet is actually a tiny Java program, dynamically
downloaded across the network, just like an image, sound file, or video clip. The
important difference is that an applet is an intelligent program, not just an animation or
media file. In other words, an applet is a program that can react to user input and
dynamically change—not just run the same animation or sound over and over.
As exciting as applets are, they would be nothing more than wishful thinking if
Java were not able to address the two fundamental problems associated with them:
security and portability. Before continuing, let’s define what these two terms mean
relative to the Internet.
Security
As you are likely aware, every time that you download a “normal” program, you
are risking a viral infection. Prior to Java, most users did not download executable
programs frequently, and those who did scanned them for viruses prior to execution.
Even so, most users still worried about the possibility of infecting their systems with
a virus. In addition to viruses, another type of malicious program exists that must be
guarded against. This type of program can gather private information, such as credit
card numbers, bank account balances, and passwords, by searching the contents of
your computer’s local file system. Java answers both of these concerns by providing
a “firewall” between a networked application and your computer.
When you use a Java-compatible Web browser, you can safely download Java
applets without fear of viral infection or malicious intent. Java achieves this protection
by confining a Java program to the Java execution environment and not allowing it
THE JAVA LANGUAGE
Chapter 8: Inheritance 199
}
// constructor used when all dimensions specified
Box(double w, double h, double d) {
width = w;
height = h;
depth = d;
}
// constructor used when no dimensions specified
Box() {
width = -1; // use -1 to indicate
height = -1; // an uninitialized
depth = -1; // box
}
// constructor used when cube is created
Box(double len) {
width = height = depth = len;
}
// compute and return volume
double volume() {
return width * height * depth;
}
// BoxWeight now fully implements all constructors.
class BoxWeight extends Box {
double weight; // weight of box
// construct clone of an object
BoxWeight(BoxWeight ob) { // pass object to constructor
super(ob);
weight = ob.weight;
}
// constructor when all parameters are specified
BoxWeight(double w, double h, double d, double m) {
super(w, h, d); // call superclass constructor
weight = m;
}
SOFTWARE DEVELOPMENT
USING JAVA
Chapter 27: Servlets 967
Method
long getLastAccessedTime( )
void invalidate( )
boolean isNew( )
void removeAttribute(String attr)
void setAttribute(String attr, Object val)
Description
Returns the time (in milliseconds since
midnight, January 1, 1970, GMT) when
the client last made a request for this
session.
Invalidates this session and removes it
from the context.
Returns true if the server created the
session and it has not yet been
accessed by the client.
Removes the attribute specified by attr
from the session.
Associates the value passed in val with
the attribute name passed in attr.
Table 27-7.
The Methods Defined by HttpSession (continued)
The HttpSessionBindingListener Interface
The HttpSessionBindingListener interface is implemented by objects that need to be
notified when they are bound to or unbound from an HTTP session. The methods that
are invoked when an object is bound or unbound are
void valueBound(HttpSessionBindingEvent e)
void valueUnbound(HttpSessionBindingEvent e)
Here, e is the event object that describes the binding.
The Cookie Class
The Cookie class encapsulates a cookie. A cookie is stored on a client and contains state
information. Cookies are valuable for tracking user activities. For example, assume that
a user visits an online store. A cookie can save the user’s name, address, and other
information. The user does not need to enter this data each time he or she visits the store.
A servlet can write a cookie to a user’s machine via the addCookie( ) method of the
HttpServletResponse interface. The data for that cookie is then included in the header
of the HTTP response that is sent to the browser.
THE JAVA LANGUAGE
Chapter 11: Multithreaded Programming 295
This prevents other threads from entering call( ) while another thread is using it.
After synchronized has been added to call( ), the output of the program is as follows:
[Hello]
[Synchronized]
[World]
Any time that you have a method, or group of methods, that manipulates the
internal state of an object in a multithreaded situation, you should use the synchronized
keyword to guard the state from race conditions. Remember, once a thread enters any
synchronized method on an instance, no other thread can enter any other synchronized
method on the same instance. However, nonsynchronized methods on that instance
will continue to be callable.
The synchronized Statement
While creating synchronized methods within classes that you create is an easy and
effective means of achieving synchronization, it will not work in all cases. To understand
why, consider the following. Imagine that you want to synchronize access to objects of
a class that was not designed for multithreaded access. That is, the class does not use
synchronized methods. Further, this class was not created by you, but by a third party,
and you do not have access to the source code. Thus, you can’t add synchronized to
the appropriate methods within the class. How can access to an object of this class be
synchronized? Fortunately, the solution to this problem is quite easy: You simply put
calls to the methods defined by this class inside a synchronized block.
This is the general form of the synchronized statement:
synchronized(object) {
// statements to be synchronized
}
Here, object is a reference to the object being synchronized. A synchronized block
ensures that a call to a method that is a member of object occurs only after the current
thread has successfully entered object’s monitor.
Here is an alternative version of the preceding example, using a synchronized block
within the run( ) method:
// This program uses a synchronized block.
class Callme {
void call(String msg) {
System.out.print("[" + msg);
try {
Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
xxv
Part I
The Java Language
1 The Genesis of Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Java’s Lineage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
The Birth of Modern Programming: C . . . . . . . . . . . . . . . . . . . . . . . 4
The Need for C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
The Stage Is Set for Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
The Creation of Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
The C# Connection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Why Java Is Important to the Internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Java Applets and Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Portability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Java’s Magic: The Bytecode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
The Java Buzzwords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Object-Oriented . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
vii
966 Java™ 2: The Complete Reference
Method
void setDateHeader(String field, long msec)
void setHeader(String field, String value)
void setIntHeader(String field, int value)
void setStatus(int code)
Description
Adds field to the header with date
value equal to msec (milliseconds
since midnight, January 1, 1970,
GMT).
Adds field to the header with value
equal to value.
Adds field to the header with value
equal to value.
Sets the status code for this
response to code.
Table 27-6.
Various Methods Defined by HttpServletResponse (continued)
The HttpSession Interface
The HttpSession interface is implemented by the server. It enables a servlet to read and
write the state information that is associated with an HTTP session. Several of its methods
are summarized in Table 27-7. All of these methods throw an IllegalStateException if the
session has already been invalidated.
Method
Object getAttribute(String attr)
Enumeration getAttributeNames( )
long getCreationTime( )
String getId( )
Description
Returns the value associated with the
name passed in attr. Returns null if
attr is not found.
Returns an enumeration of the attribute
names associated with the session.
Returns the time (in milliseconds since
midnight, January 1, 1970, GMT) when
this session was created.
Returns the session ID.
Table 27-7.
The Methods Defined by HttpSession
878 Java™ 2: The Complete Reference
In the first line, the name of the server is provided. The second line uses its IP address
(11.12.13.14).
You can try this example without actually having a remote server. To do so, simply
install all of the programs on the same machine, start rmiregistry, start AddSever, and
then execute AddClient using this command line:
java AddClient 127.0.0.1 8 9
Here, the address 127.0.0.1 is the “loop back” address for the local machine. Using this
address allows you to exercise the entire RMI mechanism without actually having to
install the server on a remote computer.
In either case, sample output from this program is shown here:
The first number is: 8
The second number is: 9
The sum is: 17.0
Text Formatting
The package java.text allows you to format, search, and manipulate text. This section
takes a brief look at its most commonly used classes: those that format date and time
information.
DateFormat Class
DateFormat is an abstract class that provides the ability to format and parse dates and
times. The getDateInstance( ) method returns an instance of DateFormat that can
format date information. It is available in these forms:
static final DateFormat getDateInstance( )
static final DateFormat getDateInstance(int style)
static final DateFormat getDateInstance(int style, Locale locale)
The argument style is one of the following values: DEFAULT, SHORT, MEDIUM,
LONG, or FULL. These are int constants defined by DateFormat. They cause different
details about the date to be presented. The argument locale is one of the static references
defined by Locale (refer to Chapter 16 for details). If the style and/or locale is not
specified, defaults are used.
One of the most commonly used methods in this class is format( ). It has several
overloaded forms, one of which is shown here:
final String format(Date d)
1048 Java™ 2: The Complete Reference
The ImageMenu applet is a simple program that presents an image-based menu
with an arbitrary number of choices in a vertical list. When the user moves the
mouse cursor over these choices, the one under the cursor changes appearance,
indicating that it can be clicked on. When the user clicks on a choice, the web browser
changes to a new document specified for that choice. ImageMenu was created by
David LaVallée, the creator of several interesting applets. Figure 30-1 shows an
instance of ImageMenu.
ImageMenu uses the showDocument( ) function in AppletContext to make the
hypertext leap to the new pages. The novelty of ImageMenu is that it uses different
portions of a single source image to draw the menu on the screen. Basing a menu on
an image rather than on text frees you to design menus that use any font or image you
desire. You can also provide various types of selection feedback. You no longer need to
rely on the AWT’s limited rendering functions.
Figure 30-1.
An example of ImageMenu
1018 Java™ 2: The Complete Reference
String link_target_frame;
boolean stopFlag;
public void init() {
String s = getParameter("bgcolor");
if(s != null) {
Color color = new Color(Integer.parseInt(s.substring(1), 16));
setBackground(color);
getParent().setBackground(color);
getParent().repaint();
}
billboards = new
BillData[Integer.parseInt(getParameter("billboards"))];
current_billboard = next_billboard
= (int)(Math.random() *billboards.length);
parseBillData();
}
void parseBillData() {
String s = getParameter("bill" + next_billboard);
int field_end = s.indexOf(",");
Image new_image = getImage(getDocumentBase(),
s.substring(0, field_end));
URL link;
try {
link = new URL(getDocumentBase(),
s.substring(field_end + 1));
}
catch (java.net.MalformedURLException e) {
e.printStackTrace();
link = getDocumentBase();
}
billboards[next_billboard] = new BillData(link, new_image);
if(image == null) {
image = new_image;
}
else {
prepareImage(new_image, this);
billboards[next_billboard].initPixels(getSize().width,
getSize().height);
}
1002 Java™ 2: The Complete Reference
Notice that House multiply inherits Foundation, Walls, and Rooms. While there is
nothing wrong with structuring a C++ hierarchy like this, it is not necessary. For
example, here is the same set of classes structured for Java:
class Foundation {
// ...
}
class Walls extends Foundation {
// ...
}
class Rooms extends Walls {
// ...
}
class House extends Rooms {
// ...
}
Here, each class extends the preceding one, with House becoming the final extension.
Sometimes a multiple inheritance hierarchy is more readily converted by including
objects of the multiply inherited classes in the final object. For example, here is another
way that House could be constructed in Java:
class Foundation {
// ...
}
class Walls{
// ...
}
class Rooms {
// ...
}
/* Now, House includes Foundation, Walls, and Rooms
as object members.
*/
612 Java™ 2: The Complete Reference
private String docRoot;
private LogMessage log;
private Hashtable cache = new Hashtable();
private boolean stopFlag;
private static String version = "1.0";
private static String mime_text_html = "text/html";
private static String CRLF = "\r\n";
private static String indexfile = "index.html";
private static int buffer_size = 8192;
static String mt[] = { // mapping from file ext to Mime-Type
"txt", "text/plain",
"html", mime_text_html,
"htm", "text/html",
"gif", "image/gif",
"jpg", "image/jpg",
"jpeg", "image/jpg",
"class", "application/octet-stream"
};
static String defaultExt = "txt";
static Hashtable types = new Hashtable();
static {
for (int i=0; i
types.put(mt[i], mt[i+1]);
}
static String fnameToMimeType(String filename) {
if (filename.endsWith("/")) // special for index files.
return mime_text_html;
int dot = filename.lastIndexOf('.');
String ext = (dot > 0) ? filename.substring(dot + 1) : defaultExt;
String ret = (String) types.get(ext);
return ret != null ? ret : (String)types.get(defaultExt);
}
int hits_served = 0;
int bytes_served = 0;
int files_in_cache = 0;
int bytes_in_cache = 0;
int hits_to_cache = 0;
332 Java™ 2: The Complete Reference
int b; // will persist
}
Here, if an object of type T is written to a persistent storage area, the contents of a
would not be saved, but the contents of b would.
The volatile modifier tells the compiler that the variable modified by volatile can
be changed unexpectedly by other parts of your program. One of these situations
involves multithreaded programs. (You saw an example of this in Chapter 11.) In a
multithreaded program, sometimes, two or more threads share the same instance
variable. For efficiency considerations, each thread can keep its own, private copy of
such a shared variable. The real (or master) copy of the variable is updated at various
times, such as when a synchronized method is entered. While this approach works
fine, it may be inefficient at times. In some cases, all that really matters is that the
master copy of a variable always reflects its current state. To ensure this, simply specify
the variable as volatile, which tells the compiler that it must always use the master
copy of a volatile variable (or, at least, always keep any private copies up to date with
the master copy, and vice versa). Also, accesses to the master variable must be executed
in the precise order in which they are executed on any private copy.
volatile in Java has, more or less, the same meaning that it has in C/C++/C#.
Using instanceof
Sometimes, knowing the type of an object during run time is useful. For example, you
might have one thread of execution that generates various types of objects, and another
thread that processes these objects. In this situation, it might be useful for the processing
thread to know the type of each object when it receives it. Another situation in which
knowledge of an object’s type at run time is important involves casting. In Java, an
invalid cast causes a run-time error. Many invalid casts can be caught at compile time.
However, casts involving class hierarchies can produce invalid casts that can be detected
only at run time. For example, a superclass called A can produce two subclasses, called B
and C. Thus, castingaBobject into type A or castingaCobject into type A is legal, but
castingaBobject into type C (or vice versa) isn’t legal. Because an object of type A can
refer to objects of either B or C, how can you know, at run time, what type of object is
actually being referred to before attempting the cast to type C? It could be an object of
type A, B, or C. If it is an object of type B, a run-time exception will be thrown. Java
provides the run-time operator instanceof to answer this question.
The instanceof operator has this general form:
object instanceof type
1074 Java™ 2: The Complete Reference
Scoring
Scores are assessed at the end of each turn. Each tile has a small number engraved on
its face next to the letter. This score may be multiplied by two or three, depending on
the value (color) of the square on which it was placed. The entire sum for a word may
also be multiplied by two or three if any letter in the word covers the appropriate
square. If a word comes in contact with any other tiles to form additional words, they
are counted separately. If a player uses all seven tiles in a single turn, an additional 50
points are awarded. At the end of the game, the player with the highest score wins.
Figure 32-5 shows an example of a board after a few turns have been taken. Patrick
started with SIRE, worth eight points. That came from the four one-point tiles and the
double-word score on the center tile. Next, Herb played HIRE, using the I from SIRE.
This was worth seven points, the sum of the four tiles involved. Notice that Herb got
credit for reusing Patrick’s I but not the double-word score underneath it. At the point
shown in Figure 32-5, Patrick has played GREAT and is about to click the Done button
to complete his turn. Notice that the tiles in play are brighter than those that have
already been played (see Figure 32-6).
At any time during play, the players may converse by typing in the text entry area
at the top of the applet (see Figure 32-7). These messages will appear one at a time in
the other player’s browser’s status line, typically at the bottom of the browser (see
Figure 32-8).
Figure 32-5.
Scrabblet early in a game
THE JAVA LIBRARY
Chapter 20: Event Handling 667
Here, src is a reference to the object that generated this event. The type of the event is
specified by type.
The TextEvent object does not include the characters currently in the text component
that generated the event. Instead, your program must use other methods associated with
the text component to retrieve that information. This operation differs from other event
objects discussed in this section. For this reason, no methods are discussed here for the
TextEvent class. Think of a text event notification as a signal to a listener that it should
retrieve information from a specific text component.
The WindowEvent Class
There are ten types of window events. The WindowEvent class defines integer
constants that can be used to identify them. The constants and their meanings are
shown here:
WINDOW_ACTIVATED
WINDOW_CLOSED
WINDOW_CLOSING
WINDOW_DEACTIVATED
WINDOW_DEICONIFIED
WINDOW_GAINED_FOCUS
WINDOW_ICONIFIED
WINDOW_LOST_FOCUS
WINDOW_OPENED
WINDOW_STATE_CHANGED
The window was activated.
The window has been closed.
The user requested that the window
be closed.
The window was deactivated.
The window was deiconified.
The window gained input focus.
The window was iconified.
The window lost input focus.
The window was opened.
The state of the window changed.
(Added by Java 2, version 1.4.)
WindowEvent is a subclass of ComponentEvent. It defines several constructors.
The first is
WindowEvent(Window src, int type)
Here, src is a reference to the object that generated this event. The type of the event is type.
Java 2, version 1.4 adds the next three constructors.
WindowEvent(Window src, int type, Window other)
WindowEvent(Window src, int type, int fromState, int toState)
WindowEvent(Window src, int type, Window other, int fromState, int toState)
THE JAVA LIBRARY
Chapter 24: New I/O, Regular Expressions, and Other Packages 865
As the output shows, the regular expression pattern “W+” matches any arbitrarily long
sequence of Ws.
The next program uses a wildcard to create a pattern that will match any sequence
that begins with e and ends with d. To do this, it uses the dot wildcard character along
with the + quantifier.
// Use wildcard and quantifier.
import java.util.regex.*;
class RegExpr5 {
public static void main(String args[]) {
Pattern pat = Pattern.compile("e.+d");
Matcher mat = pat.matcher("extend cup end table");
}
}
while(mat.find())
System.out.println("Match: " + mat.group());
You might be surprised by the the output produced by the program, which is
shown here:
Match: extend cup end
Only one match is found, and it is the longest sequence that begins with e and ends
with d. You might have expected two matches: extend and end. The reason that the
longer sequence is found is that by default, find( ) matches the longest sequence that
fits the pattern. This is called greedy behavior. You can specify reluctant behavior by adding
the ? quantifier to the pattern, as shown in this version of the program. It causes the
shortest matching pattern to be obtained.
// Use the ? quantifier.
import java.util.regex.*;
class RegExpr6 {
public static void main(String args[]) {
// Use reluctant matching behavior.
Pattern pat = Pattern.compile("e.+?d");
Matcher mat = pat.matcher("extend cup end table");
while(mat.find())
THE JAVA LIBRARY
Chapter 20: Event Handling 659
int getModifiers( )
Java 2, version 1.4 added the method getWhen( ) that returns the time at which the event
took place. This is called the event’s timestamp. The getWhen( ) method is shown here.
long getWhen( )
Timestamps were added by ActionEvent to help support the improved input focus
subsystem implemented by Java 2, version 1.4.
The AdjustmentEvent Class
An AdjustmentEvent is generated by a scroll bar. There are five types of adjustment
events. The AdjustmentEvent class defines integer constants that can be used to identify
them. The constants and their meanings are shown here:
BLOCK_DECREMENT
BLOCK_INCREMENT
TRACK
UNIT_DECREMENT
UNIT_INCREMENT
The user clicked inside the scroll bar to decrease
its value.
The user clicked inside the scroll bar to increase
its value.
The slider was dragged.
The button at the end of the scroll bar was clicked
to decrease its value.
The button at the end of the scroll bar was clicked
to increase its value.
In addition, there is an integer constant, ADJUSTMENT_VALUE_CHANGED,
that indicates that a change has occurred.
Here is one AdjustmentEvent constructor:
AdjustmentEvent(Adjustable src, int id, int type, int data)
Here, src is a reference to the object that generated this event. The id equals
ADJUSTMENT_VALUE_CHANGED. The type of the event is specified by type,
and its associated data is data.
The getAdjustable( ) method returns the object that generated the event. Its form
is shown here:
Adjustable getAdjustable( )
The type of the adjustment event may be obtained by the getAdjustmentType( ) method.
It returns one of the constants defined by AdjustmentEvent. The general form is
shown here:
int getAdjustmentType( )
THE JAVA LIBRARY
Chapter 21: Introducing the AWT: Working with Windows, Graphics, and Text 727
curX = fm.stringWidth(s); // advance to end of line
}
// Display on same line.
void sameLine(String s, Graphics g) {
FontMetrics fm = g.getFontMetrics();
}
}
g.drawString(s, curX, curY);
curX += fm.stringWidth(s); // advance to end of line
Sample output from this program is shown here:
Centering Text
Here is an example that centers text, left to right, top to bottom, in a window. It obtains
the ascent, descent, and width of the string and computes the position at which it must
be displayed to be centered.
// Center text.
import java.applet.*;
import java.awt.*;
/*
*/
public class CenterText extends Applet {
final Font f = new Font("SansSerif", Font.BOLD, 18);
public void paint(Graphics g) {
116 Java™ 2: The Complete Reference
public static void main(String args[]) {
int num;
boolean isPrime = true;
}
}
num = 14;
for(int i=2; i <= num/2; i++) {
if((num % i) == 0) {
isPrime = false;
break;
}
}
if(isPrime) System.out.println("Prime");
else System.out.println("Not Prime");
Using the Comma
There will be times when you will want to include more than one statement in the
initialization and iteration portions of the for loop. For example, consider the loop
in the following program:
class Sample {
public static void main(String args[]) {
int a, b;
}
}
b = 4;
for(a=1; a
System.out.println("a = " + a);
System.out.println("b = " + b);
b--;
}
As you can see, the loop is controlled by the interaction of two variables. Since the loop
is governed by two variables, it would be useful if both could be included in the for
statement, itself, instead of b being handled manually. Fortunately, Java provides a way
to accomplish this. To allow two or more variables to control a for loop, Java permits
you to include multiple statements in both the initialization and iteration portions of
the for. Each statement is separated from the next by a comma.
74 Java™ 2: The Complete Reference
Java provides a rich operator environment. Most of its operators can be divided
into the following four groups: arithmetic, bitwise, relational, and logical. Java also
defines some additional operators that handle certain special situations. This chapter
describes all of Java’s operators except for the type comparison operator instanceof,
which is examined in Chapter 12.
If you are familiar with C/C++/C#, then you will be pleased to know that most operators
in Java work just like they do in those languages. However, there are some subtle differences,
so a careful reading is advised.
Arithmetic Operators
Arithmetic operators are used in mathematical expressions in the same way that they
are used in algebra. The following table lists the arithmetic operators:
Operator
Result
+ Addition
– Subtraction (also unary minus)
* Multiplication
/ Division
% Modulus
++ Increment
+= Addition assignment
–= Subtraction assignment
*= Multiplication assignment
/= Division assignment
%= Modulus assignment
– – Decrement
The operands of the arithmetic operators must be of a numeric type. You cannot
use them on boolean types, but you can use them on char types, since the char type in
Java is, essentially, a subset of int.
The Basic Arithmetic Operators
The basic arithmetic operations—addition, subtraction, multiplication, and division—
all behave as you would expect for all numeric types. The minus operator also has
a unary form which negates its single operand. Remember that when the division
THE JAVA LANGUAGE
Chapter 7: A Closer Look at Methods and Classes 171
you can watch what is going on and abort execution if you see that you have made
a mistake.
Here is one more example of recursion. The recursive method printArray( ) prints
the first i elements in the array values.
// Another example that uses recursion.
class RecTest {
int values[];
}
RecTest(int i) {
values = new int[i];
}
// display array -- recursively
void printArray(int i) {
if(i==0) return;
else printArray(i-1);
System.out.println("[" + (i-1) + "] " + values[i-1]);
}
class Recursion2 {
public static void main(String args[]) {
RecTest ob = new RecTest(10);
int i;
for(i=0; i<10; i++) ob.values[i] = i;
}
}
ob.printArray(10);
This program generates the following output:
[0] 0
[1] 1
[2] 2
[3] 3
[4] 4
[5] 5
[6] 6
THE JAVA LIBRARY
Chapter 21: Introducing the AWT: Working with Windows, Graphics, and Text 715
g.drawLine(0, 100, 100, 0);
g.setColor(c2);
g.drawLine(40, 25, 250, 180);
g.drawLine(75, 90, 400, 400);
g.setColor(c3);
g.drawLine(20, 150, 400, 40);
g.drawLine(5, 290, 80, 19);
g.setColor(Color.red);
g.drawOval(10, 10, 50, 50);
g.fillOval(70, 90, 140, 100);
g.setColor(Color.blue);
g.drawOval(190, 10, 90, 30);
g.drawRect(10, 10, 60, 50);
}
}
g.setColor(Color.cyan);
g.fillRect(100, 10, 60, 50);
g.drawRoundRect(190, 10, 60, 50, 15, 15);
Setting the Paint Mode
The paint mode determines how objects are drawn in a window. By default, new output
to a window overwrites any preexisting contents. However, it is possible to have new
objects XORed onto the window by using setXORMode( ), as follows:
void setXORMode(Color xorColor)
Here, xorColor specifies the color that will be XORed to the window when an object is
drawn. The advantage of XOR mode is that the new object is always guaranteed to be
visible no matter what color the object is drawn over.
To return to overwrite mode, call setPaintMode( ), shown here:
void setPaintMode( )
In general, you will want to use overwrite mode for normal output, and XOR mode for
special purposes. For example, the following program displays cross hairs that track
the mouse pointer. The cross hairs are XORed onto the window and are always visible,
no matter what the underlying color is.
714 Java™ 2: The Complete Reference
Each of these methods returns the RGB color component found in the invoking Color
object in the lower 8 bits of an integer.
getRGB( )
To obtain a packed, RGB representation of a color, use getRGB( ), shown here:
int getRGB( )
The return value is organized as described earlier.
Setting the Current Graphics Color
By default, graphics objects are drawn in the current foreground color. You can change
this color by calling the Graphics method setColor( ):
void setColor(Color newColor)
Here, newColor specifies the new drawing color.
You can obtain the current color by calling getColor( ), shown here:
Color getColor( )
A Color Demonstration Applet
The following applet constructs several colors and draws various objects using
these colors:
// Demonstrate color.
import java.awt.*;
import java.applet.*;
/*
*/
public class ColorDemo extends Applet {
// draw lines
public void paint(Graphics g) {
Color c1 = new Color(255, 100, 100);
Color c2 = new Color(100, 255, 100);
Color c3 = new Color(100, 100, 255);
g.setColor(c1);
g.drawLine(0, 0, 100, 100);
650 Java™ 2: The Complete Reference
AppletContext is an interface that lets you get information from the applet’s execution
environment. The methods defined by AppletContext are shown in Table 19-2. The
context of the currently executing applet is obtained by a call to the getAppletContext( )
method defined by Applet.
Within an applet, once you have obtained the applet’s context, you can bring
another document into view by calling showDocument( ). This method has no
return value and throws no exception if it fails, so use it carefully. There are two
showDocument( ) methods. The method showDocument(URL) displays the document
Method
Applet getApplet(String appletName)
Enumeration getApplets( )
AudioClip getAudioClip(URL url)
Image getImage(URL url)
InputStream getStream(String key)
Iterator getStreamKeys( )
void setStream(String key,
InputStream strm)
void showDocument(URL url)
void showDocument(URL url,
String where)
void showStatus(String str)
Description
Returns the applet specified by appletName if it is
within the current applet context. Otherwise, null
is returned.
Returns an enumeration that contains all of the
applets within the current applet context.
Returns an AudioClip object that encapsulates the
audio clip found at the location specified by url.
Returns an Image object that encapsulates the image
found at the location specified by url.
Returns the stream linked to key. Keys are linked to
streams by using the setStream( ) method. A null
reference is returned if no stream is linked to key.
(Added by Java 2, version 1.4)
Returns an iterator for the keys associated with the
invoking object. The keys are linked to streams. See
getStream( ) and setStream( ). (Added by Java 2,
version 1.4)
Links the stream specified by strm to the key passed
in key. The key is deleted from the invoking object if
strm is null. (Added by Java 2, version 1.4)
Brings the document at the URL specified by url
into view. This method may not be supported by
applet viewers.
Brings the document at the URL specified by url
into view. This method may not be supported by
applet viewers. The placement of the document
is specified by where as described in the text.
Displays str in the status window.
Table 19-2.
The Abstract Methods Defined by the AppletContext Interface
442 Java™ 2: The Complete Reference
In addition to collections, the framework defines several map interfaces and classes.
Maps store key/value pairs. Although maps are not “collections” in the proper use of
the term, they are fully integrated with collections. In the language of the collections
framework, you can obtain a collection-view of a map. Such a view contains the elements
from the map stored in a collection. Thus, you can process the contents of a map as a
collection, if you choose.
The collection mechanism was retrofitted to some of the original classes defined by
java.util so that they too could be integrated into the new system. It is important to
understand that although the addition of collections altered the architecture of many
of the original utility classes, it did not cause the deprecation of any. Collections simply
provide a better way of doing several things.
One last thing: If you are familiar with C++, then you will find it helpful to know
that the Java collections technology is similar in spirit to the Standard Template Library
(STL) defined by C++. What C++ calls a container, Java calls a collection.
The Collection Interfaces
The collections framework defines several interfaces. This section provides an overview of
each interface. Beginning with the collection interfaces is necessary because they determine
the fundamental nature of the collection classes. Put differently, the concrete classes simply
provide different implementations of the standard interfaces. The interfaces that underpin
collections are summarized in the following table:
Interface
Collection
List
Set
SortedSet
Description
Enables you to work with groups of objects; it is at the top of the
collections hierarchy
Extends Collection to handle sequences (lists of objects)
Extends Collection to handle sets, which must contain unique elements
Extends Set to handle sorted sets
In addition to the collection interfaces, collections also use the Comparator, Iterator,
ListIterator and RandomAccess interfaces, which are described in depth later in this
chapter. Briefly, Comparator defines how two objects are compared; Iterator and
ListIterator enumerate the objects within a collection. By implementing RandomAccess,
a list indicates that it supports efficient, random access to its elements.
To provide the greatest flexibility in their use, the collection interfaces allow some
methods to be optional. The optional methods enable you to modify the contents of a
collection. Collections that support these methods are called modifiable. Collections that
do not allow their contents to be changed are called unmodifiable. If an attempt is made
968 Java™ 2: The Complete Reference
The names and values of cookies are stored on the user’s machine. Some of the
information that is saved for each cookie includes the following:
■ The name of the cookie
■ The value of the cookie
■ The expiration date of the cookie
■ The domain and path of the cookie
The expiration date determines when this cookie is deleted from the user’s machine.
If an expiration date is not explicitly assigned to a cookie, it is deleted when the current
browser session ends. Otherwise, the cookie is saved in a file on the user’s machine.
The domain and path of the cookie determine when it is included in the header of
an HTTP request. If the user enters a URL whose domain and path match these values,
the cookie is then supplied to the Web server. Otherwise, it is not.
There is one constructor for Cookie. It has the signature shown here:
Cookie(String name, String value)
Here, the name and value of the cookie are supplied as arguments to the constructor.
The methods of the Cookie class are summarized in Table 27-8.
Method
Object clone( )
String getComment( )
String getDomain( )
int getMaxAge( )
String getName( )
String getPath( )
boolean getSecure( )
String getValue( )
int getVersion( )
Description
Returns a copy of this object.
Returns the comment.
Returns the domain.
Returns the age (in seconds).
Returns the name.
Returns the path.
Returns true if the cookie must be sent using
only a secure protocol. Otherwise, returns false.
Returns the value.
Returns the cookie protocol version. (Will be
0 or 1.)
Table 27-8.
The Methods Defined by Cookie
THE JAVA LANGUAGE
Chapter 11: Multithreaded Programming 291
class HiLoPri {
public static void main(String args[]) {
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
clicker hi = new clicker(Thread.NORM_PRIORITY + 2);
clicker lo = new clicker(Thread.NORM_PRIORITY - 2);
lo.start();
hi.start();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
lo.stop();
hi.stop();
// Wait for child threads to terminate.
try {
hi.t.join();
lo.t.join();
} catch (InterruptedException e) {
System.out.println("InterruptedException caught");
}
}
}
System.out.println("Low-priority thread: " + lo.click);
System.out.println("High-priority thread: " + hi.click);
The output of this program, shown as follows when run under Windows 98,
indicates that the threads did context switch, even though neither voluntarily yielded
the CPU nor blocked for I/O. The higher-priority thread got approximately 90 percent
of the CPU time.
Low-priority thread: 4408112
High-priority thread: 589626904
Of course, the exact output produced by this program depends on the speed of your
CPU and the number of other tasks running in the system. When this same program
is run under a nonpreemptive system, different results will be obtained.
One other note about the preceding program. Notice that running is preceded
by the keyword volatile. Although volatile is examined more carefully in the next
786 Java™ 2: The Complete Reference
}
g.drawString("Testing is off.", 10, 240);
}
class MyWindowAdapter extends WindowAdapter {
MenuFrame menuFrame;
public MyWindowAdapter(MenuFrame menuFrame) {
this.menuFrame = menuFrame;
}
public void windowClosing(WindowEvent we) {
menuFrame.dispose();
}
}
class MyMenuHandler implements ActionListener, ItemListener {
MenuFrame menuFrame;
public MyMenuHandler(MenuFrame menuFrame) {
this.menuFrame = menuFrame;
}
// Handle action events
public void actionPerformed(ActionEvent ae) {
String msg = "You selected ";
String arg = (String)ae.getActionCommand();
// Activate a dialog box when New is selected.
if(arg.equals("New...")) {
msg += "New.";
SampleDialog d = new
SampleDialog(menuFrame, "New Dialog Box");
d.setVisible(true);
}
// Try defining other dialog boxes for these options.
else if(arg.equals("Open..."))
msg += "Open.";
else if(arg.equals("Close"))
msg += "Close.";
else if(arg.equals("Quit..."))
msg += "Quit.";
else if(arg.equals("Edit"))
msg += "Edit.";
else if(arg.equals("Cut"))
msg += "Cut.";
THE JAVA LIBRARY
Chapter 22: Using AWT Controls, Layout Managers, and Menus 761
Figure 22-7.
Sample output from the TextFieldDemo applet
Using a TextArea
Sometimes a single line of text input is not enough for a given task. To handle these
situations, the AWT includes a simple multiline editor called TextArea. Following are
the constructors for TextArea:
TextArea( )
TextArea(int numLines, int numChars)
TextArea(String str)
TextArea(String str, int numLines, int numChars)
TextArea(String str, int numLines, int numChars, int sBars)
Here, numLines specifies the height, in lines, of the text area, and numChars specifies its
width, in characters. Initial text can be specified by str. In the fifth form you can specify
the scroll bars that you want the control to have. sBars must be one of these values:
SCROLLBARS_BOTH
SCROLLBARS_HORIZONTAL_ONLY
SCROLLBARS_NONE
SCROLLBARS_VERTICAL_ONLY
TextArea is a subclass of TextComponent. Therefore, it supports the getText( ), setText( ),
getSelectedText( ), select( ), isEditable( ), and setEditable( ) methods described in the
preceding section.
This page intentionally left blank.
520 Java™ 2: The Complete Reference
class GregorianCalendarDemo {
public static void main(String args[]) {
String months[] = {
"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"};
int year;
// Create a Gregorian calendar initialized
// with the current date and time in the
// default locale and timezone.
GregorianCalendar gcalendar = new GregorianCalendar();
// Display current time and date information.
System.out.print("Date: ");
System.out.print(months[gcalendar.get(Calendar.MONTH)]);
System.out.print(" " + gcalendar.get(Calendar.DATE) + " ");
System.out.println(year = gcalendar.get(Calendar.YEAR));
System.out.print("Time: ");
System.out.print(gcalendar.get(Calendar.HOUR) + ":");
System.out.print(gcalendar.get(Calendar.MINUTE) + ":");
System.out.println(gcalendar.get(Calendar.SECOND));
}
}
// Test if the current year is a leap year
if(gcalendar.isLeapYear(year)) {
System.out.println("The current year is a leap year");
}
else {
System.out.println("The current year is not a leap year");
}
Sample output is shown here:
Date: Apr 22 2002
Time: 11:25:27
The current year is not a leap year
518 Java™ 2: The Complete Reference
class CalendarDemo {
public static void main(String args[]) {
String months[] = {
"Jan", "Feb", "Mar", "Apr",
"May", "Jun", "Jul", "Aug",
"Sep", "Oct", "Nov", "Dec"};
// Create a calendar initialized with the
// current date and time in the default
// locale and timezone.
Calendar calendar = Calendar.getInstance();
// Display current time and date information.
System.out.print("Date: ");
System.out.print(months[calendar.get(Calendar.MONTH)]);
System.out.print(" " + calendar.get(Calendar.DATE) + " ");
System.out.println(calendar.get(Calendar.YEAR));
System.out.print("Time: ");
System.out.print(calendar.get(Calendar.HOUR) + ":");
System.out.print(calendar.get(Calendar.MINUTE) + ":");
System.out.println(calendar.get(Calendar.SECOND));
// Set the time and date information and display it.
calendar.set(Calendar.HOUR, 10);
calendar.set(Calendar.MINUTE, 29);
calendar.set(Calendar.SECOND, 22);
}
}
System.out.print("Updated time: ");
System.out.print(calendar.get(Calendar.HOUR) + ":");
System.out.print(calendar.get(Calendar.MINUTE) + ":");
System.out.println(calendar.get(Calendar.SECOND));
Sample output is shown here:
Date: Apr 22 2002
Time: 11:24:25
Updated time: 10:29:22
1038 Java™ 2: The Complete Reference
source index counter each time, and there will be a speed benefit from using the array
copy method for a particular line.
The Code
Here is the source code for the TearTransition class:
import java.awt.*;
import java.awt.image.*;
public class TearTransition extends BillTransition {
static final int CELLS = 7;
static final float INITIAL_X_CROSS = 1.6f;
static final float X_CROSS_DIVISOR = 3.5f;
float x_cross;
public void init(Component owner, int[] current, int[] next) {
init(owner, current, next, CELLS);
System.arraycopy(next_pixels, 0, work_pixels, 0,
pixels_per_cell);
System.arraycopy(current_pixels, 0, work_pixels, 0, cell_w);
}
x_cross = INITIAL_X_CROSS;
for(int c = CELLS - 1; c >= 0; --c) {
try { Thread.sleep(100); } catch (InterruptedException e) {}
Tear();
try { Thread.sleep(150); } catch (InterruptedException e) {}
createCellFromWorkPixels(c);
x_cross /= X_CROSS_DIVISOR;
}
work_pixels = null;
final void Tear() {
float x_increment;
int p, height_adder;
p = height_adder = cell_w;
for (int y = 1; y < cell_h; ++y) {
x_increment = x_cross * y;
if(x_increment >= 0.50f) {
float fx = 0.0f;
THE JAVA LIBRARY
Chapter 24: New I/O, Regular Expressions, and Other Packages 859
}
}
System.exit(1);
}
Because the input file is mapped to mBuf, it contains the entire source file. Thus, the
call to write( ) copies all of mBuf to the target file. This, of course, means that the target
file is an identical copy of the source file.
Is NIO the Future of I/O Handling?
The new I/O APIs offer an exciting new way to think about and handle some types
of file operations. Because of this it is natural to ask the question, “Is NIO the future
of I/O handling?” Unfortunately, at the time of this writing, this question cannot be
answered. Certainly, channels and buffers offer a clean way of thinking about I/O.
However, they also add another layer of abstraction. Furthermore, the traditional
stream-based approach is both well-understood, and widely used. As explained at
the outset, channel-based I/O is currently designed to supplement, not replace the
standard I/O mechanisms defined in java.io.Inthis role, the channel/buffer approach
used by the NIO APIs succeeds admirably. Whether the new approach will someday
supplant the traditional approach, only time and usage patterns will tell.
Regular Expression Processing
Another exciting package added by Java 2, version 1.4 is java.util.regex, which
supports regular expression processing. As the term is used here, a regular expression is
a string of characters that describes a character sequence. This general description,
called a pattern, can then be used to find matches in other character sequences. Regular
expressions can specify wildcard characters, sets of characters, and various quantifiers.
Thus, you can specify a regular expression that represents a general form that can
match several different specific character sequences.
There are two classes that support regular expression processing: Pattern and
Matcher. These classes work together. Use Pattern to define a regular expression.
Match the pattern against another sequence using Matcher.
Pattern
The Pattern class defines no constructors. Instead, a pattern is created by calling the
compile( ) factory method. One of its forms is shown here:
static Pattern compile(String pattern)
424 Java™ 2: The Complete Reference
As expected, these constants specify the maximum, minimum, and default
thread priorities.
The methods defined by Thread are shown in Table 14-16. In versions of Java
prior to 2, Thread also included the methods stop( ), suspend( ), and resume( ).
However, as explained in Chapter 11, these have been deprecated by Java 2 because
they were inherently unstable. Also deprecated by Java 2 is countStackFrames( ),
because it calls suspend( ).
Method
static int activeCount( )
void checkAccess( )
static Thread currentThread( )
void destroy( )
static void dumpStack( )
static int enumerate(Thread threads[ ])
ClassLoader getContextClassLoader( )
final String getName( )
final int getPriority( )
final ThreadGroup getThreadGroup( )
static boolean holdsLock(Object ob)
Description
Returns the number of threads in the
group to which the thread belongs.
Causes the security manager to verify
that the current thread can access
and/or change the thread on which
checkAccess( ) is called.
Returns a Thread object that
encapsulates the thread that calls
this method.
Terminates the thread.
Displays the call stack for the thread.
Puts copies of all Thread objects in the
current thread’s group into threads. The
number of threads is returned.
Returns the class loader that is used to
load classes and resources for this
thread. (Added by Java 2)
Returns the thread’s name.
Returns the thread’s priority setting.
Returns the ThreadGroup object of
which the invoking thread is a member.
Returns true if the invoking thread
owns the lock on ob. Returns false
otherwise. (Added by Java 2, version 1.4)
Table 14-16.
The Methods Defined by Thread
840 Java™ 2: The Complete Reference
}
}
public void run() {
idx = 0;
while (true) {
paint(getGraphics());
idx = (idx + 1) % nseq;
try { Thread.sleep(1000/framerate); } catch (Exception e) { };
if(stopFlag)
return;
}
}
The following applet tag shows the famous locomotion study by Eadweard
Muybridge, which proved that horses do, indeed, get all four hooves off the ground at
once. (Of course, you can substitute another image file in your own applet.)
Figure 23-13 shows the applet running. Notice the source image that has been loaded
below the applet using a normal
![]()
tag.
Additional Imaging Classes
In addition to the imaging classes described in this chapter, java.awt.image supplies several
others that offer enhanced control over the imaging process and that support advanced
This page intentionally left blank.
938 Java™ 2: The Complete Reference
}
}
JCheckBox cb1 = new JCheckBox("Red");
add(cb1);
JCheckBox cb2 = new JCheckBox("Green");
add(cb2);
JCheckBox cb3 = new JCheckBox("Blue");
add(cb3);
class FlavorsPanel extends JPanel {
public FlavorsPanel() {
}
}
JComboBox jcb = new JComboBox();
jcb.addItem("Vanilla");
jcb.addItem("Chocolate");
jcb.addItem("Strawberry");
add(jcb);
Output from this applet is shown in the following three illustrations:
18 Java™ 2: The Complete Reference
Like all other computer languages, the elements of Java do not exist in isolation.
Rather, they work together to form the language as a whole. However, this
interrelatedness can make it difficult to describe one aspect of Java without
involving several others. Often a discussion of one feature implies prior knowledge
of another. For this reason, this chapter presents a quick overview of several key
features of Java. The material described here will give you a foothold that will allow
you to write and understand simple programs. Most of the topics discussed will be
examined in greater detail in the remaining chapters of Part 1.
Object-Oriented Programming
Object-oriented programming is at the core of Java. In fact, all Java programs are objectoriented—this
isn’t an option the way that it is in C++, for example. OOP is so integral
to Java that you must understand its basic principles before you can write even simple
Java programs. Therefore, this chapter begins with a discussion of the theoretical aspects
of OOP.
Two Paradigms
As you know, all computer programs consist of two elements: code and data. Furthermore,
a program can be conceptually organized around its code or around its data. That is,
some programs are written around “what is happening” and others are written around
“who is being affected.” These are the two paradigms that govern how a program is
constructed. The first way is called the process-oriented model. This approach characterizes
a program as a series of linear steps (that is, code). The process-oriented model can be
thought of as code acting on data. Procedural languages such as C employ this model to
considerable success. However, as mentioned in Chapter 1, problems with this approach
appear as programs grow larger and more complex.
To manage increasing complexity, the second approach, called object-oriented
programming, was conceived. Object-oriented programming organizes a program around
its data (that is, objects) and a set of well-defined interfaces to that data. An object-oriented
program can be characterized as data controlling access to code. As you will see, by switching
the controlling entity to data, you can achieve several organizational benefits.
Abstraction
An essential element of object-oriented programming is abstraction. Humans manage
complexity through abstraction. For example, people do not think of a car as a set of
tens of thousands of individual parts. They think of it as a well-defined object with its
own unique behavior. This abstraction allows people to use a car to drive to the grocery
store without being overwhelmed by the complexity of the parts that form the car. They
can ignore the details of how the engine, transmission, and braking systems work. Instead
they are free to utilize the object as a whole.
THE JAVA LIBRARY
Chapter 14: Exploring java.lang 383
Method
static int floatToIntBits(float num)
float floatValue( )
int hashCode( )
static float intBitsToFloat(int num)
int intValue( )
boolean isInfinite( )
static boolean isInfinite(float num)
boolean isNaN( )
static boolean isNaN(float num)
long longValue( )
static float parseFloat(String str)
throws NumberFormatException
short shortValue( )
String toString( )
static String toString(float num)
static Float valueOf(String str)
throws NumberFormatException
Description
Returns the IEEE-compatible,
single-precision bit pattern that
corresponds to the num.
Returns the value of the invoking object as
a float.
Returns the hash code for the invoking object.
Returns float equivalent of the
IEEE-compatible, single-precision bit
pattern specified by num.
Returns the value of the invoking object as
an int.
Returns true if the invoking object contains
an infinite value. Otherwise, it returns false.
Returns true if num specifies an infinite
value. Otherwise, it returns false.
Returns true if the invoking object
contains a value that is not a number.
Otherwise, it returns false.
Returns true if num specifies a value that is
not a number. Otherwise, it returns false.
Returns the value of the invoking object as
a long.
Returns the float equivalent of the number
contained in the string specified by str
using radix 10. (Added by Java 2)
Returns the value of the invoking object as
a short.
Returns the string equivalent of the
invoking object.
Returns the string equivalent of the value
specified by num.
Returns the Float object that contains the
value specified by the string in str.
Table 14-1.
The Methods Defined by Float (continued)
THE JAVA LIBRARY
Chapter 16: java.util Part 2: More Utility Classes 521
TimeZone
Another time-related class is TimeZone. The TimeZone class allows you to work with
time zone offsets from Greenwich mean time (GMT), also referred to as Coordinated
Universal Time (UTC). It also computes daylight saving time. TimeZone only supplies
the default constructor.
Some methods defined by TimeZone are summarized in Table 16-5.
Method
Object clone( )
static String[ ] getAvailableIDs( )
static String[ ] getAvailableIDs(int timeDelta)
static TimeZone getDefault( )
String getID( )
abstract int getOffset(int era, int year,
int month,
int dayOfMonth,
int dayOfWeek,
int millisec)
abstract int getRawOffset( )
Description
Returns a TimeZone-specific
version of clone( ).
Returns an array of String
objects representing the names
of all time zones.
Returns an array of String objects
representing the names of all time
zones that are timeDelta offset
from GMT.
Returns a TimeZone object that
represents the default time zone
used on the host computer.
Returns the name of the invoking
TimeZone object.
Returns the offset that should be
added to GMT to compute local
time. This value is adjusted for
daylight saving time. The
parameters to the method
represent date and time
components.
Returns the raw offset that should
be added to GMT to compute local
time. This value is not adjusted for
daylight saving time.
Table 16-5.
Some of the Methods Defined by TimeZone
204 Java™ 2: The Complete Reference
}
depth = d;
}
// constructor used when no dimensions specified
Box() {
width = -1; // use -1 to indicate
height = -1; // an uninitialized
depth = -1; // box
}
// constructor used when cube is created
Box(double len) {
width = height = depth = len;
}
// compute and return volume
double volume() {
return width * height * depth;
}
// Add weight.
class BoxWeight extends Box {
double weight; // weight of box
// construct clone of an object
BoxWeight(BoxWeight ob) { // pass object to constructor
super(ob);
weight = ob.weight;
}
// constructor when all parameters are specified
BoxWeight(double w, double h, double d, double m) {
super(w, h, d); // call superclass constructor
weight = m;
}
// default constructor
BoxWeight() {
super();
weight = -1;
}
THE JAVA LANGUAGE
Chapter 11: Multithreaded Programming 303
To understand deadlock fully, it is useful to see it in action. The next example creates
two classes, A and B, with methods foo( ) and bar( ), respectively, which pause briefly
before trying to call a method in the other class. The main class, named Deadlock, creates
an A and a B instance, and then starts a second thread to set up the deadlock condition.
The foo( ) and bar( ) methods use sleep( ) as a way to force the deadlock condition
to occur.
// An example of deadlock.
class A {
synchronized void foo(B b) {
String name = Thread.currentThread().getName();
}
}
System.out.println(name + " entered A.foo");
try {
Thread.sleep(1000);
} catch(Exception e) {
System.out.println("A Interrupted");
}
System.out.println(name + " trying to call B.last()");
b.last();
synchronized void last() {
System.out.println("Inside A.last");
}
class B {
synchronized void bar(A a) {
String name = Thread.currentThread().getName();
System.out.println(name + " entered B.bar");
try {
Thread.sleep(1000);
} catch(Exception e) {
System.out.println("B Interrupted");
}
System.out.println(name + " trying to call A.last()");
a.last();
584 Java™ 2: The Complete Reference
MyClass object1 = new MyClass("Hello", -7, 2.7e10);
System.out.println("object1: " + object1);
FileOutputStream fos = new FileOutputStream("serial");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object1);
oos.flush();
oos.close();
}
catch(Exception e) {
System.out.println("Exception during serialization: " + e);
System.exit(0);
}
}
}
// Object deserialization
try {
MyClass object2;
FileInputStream fis = new FileInputStream("serial");
ObjectInputStream ois = new ObjectInputStream(fis);
object2 = (MyClass)ois.readObject();
ois.close();
System.out.println("object2: " + object2);
}
catch(Exception e) {
System.out.println("Exception during deserialization: " + e);
System.exit(0);
}
class MyClass implements Serializable {
String s;
int i;
double d;
public MyClass(String s, int i, double d) {
this.s = s;
this.i = i;
this.d = d;
}
public String toString() {
return "s=" + s + "; i=" + i + "; d=" + d;
}
}
788 Java™ 2: The Complete Reference
}
f.setVisible(false);
}
Here is sample output from the DialogDemo applet:
On your own, try defining dialog boxes for the other options presented by the menus.
FileDialog
Java provides a built-in dialog box that lets the user specify a file. To create a file dialog
box, instantiate an object of type FileDialog. This causes a file dialog box to be displayed.
Usually, this is the standard file dialog box provided by the operating system. FileDialog
provides these constructors:
FileDialog(Frame parent, String boxName)
FileDialog(Frame parent, String boxName, int how)
FileDialog(Frame parent)
Here, parent is the owner of the dialog box, and boxName is the name displayed in
the box’s title bar. If boxName is omitted, the title of the dialog box is empty. If how is
FileDialog.LOAD, then the box is selecting a file for reading. If how is FileDialog.SAVE,
the box is selecting a file for writing. The third constructor creates a dialog box for selecting
a file for reading.
THE JAVA LANGUAGE
Chapter 10: Exception Handling 261
This program gets two chances to deal with the same error. First, main( ) sets up an
exception context and then calls demoproc( ). The demoproc( ) method then sets up
another exception-handling context and immediately throws a new instance of
NullPointerException, which is caught on the next line. The exception is then
rethrown. Here is the resulting output:
Caught inside demoproc.
Recaught: java.lang.NullPointerException: demo
The program also illustrates how to create one of Java’s standard exception objects.
Pay close attention to this line:
throw new NullPointerException("demo");
Here, new is used to construct an instance of NullPointerException. All of Java’s
built-in run-time exceptions have at least two constructors: one with no parameter
and one that takes a string parameter. When the second form is used, the argument
specifies a string that describes the exception. This string is displayed when the object
is used as an argument to print( ) or println( ). It can also be obtained by a call to
getMessage( ), which is defined by Throwable.
throws
If a method is capable of causing an exception that it does not handle, it must specify
this behavior so that callers of the method can guard themselves against that exception.
You do this by including a throws clause in the method’s declaration. A throws clause
lists the types of exceptions that a method might throw. This is necessary for all
exceptions, except those of type Error or RuntimeException, or any of their subclasses.
All other exceptions that a method can throw must be declared in the throws clause. If
they are not, a compile-time error will result.
This is the general form of a method declaration that includes a throws clause:
type method-name(parameter-list) throws exception-list
{
// body of method
}
Here, exception-list is a comma-separated list of the exceptions that a method can throw.
978 Java™ 2: The Complete Reference
A session can be created via the getSession( ) method of HttpServletRequest. An
HttpSession object is returned. This object can store a set of bindings that associate
names with objects. The setAttribute( ), getAttribute( ), getAttributeNames( ), and
removeAttribute( ) methods of HttpSession manage these bindings. It is important
to note that session state is shared among all the servlets that are associated with a
particular client.
The following servlet illustrates how to use session state. The getSession( ) method
gets the current session. A new session is created if one does not already exist. The
getAttribute( ) method is called to obtain the object that is bound to the name “date”.
That object is a Date object that encapsulates the date and time when this page was last
accessed. (Of course, there is no such binding when the page is first accessed.) A Date
object encapsulating the current date and time is then created. The setAttribute( )
method is called to bind the name “date” to this object.
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DateServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Get the HttpSession object.
HttpSession hs = request.getSession(true);
// Get writer.
response.setContentType("text/html");
PrintWriter pw = response.getWriter();
pw.print("");
// Display date/time of last access.
Date date = (Date)hs.getAttribute("date");
if(date != null) {
pw.print("Last access: " + date + "
");
}
// Display current date/time.
date = new Date();
hs.setAttribute("date", date);
APPLYING JAVA
Chapter 32: Scrabblet: A Multiplayer Word Game 1105
offGraphics.setColor(Color.black);
offGraphics.fillRect(lm,tm,aw-2*lt,ah-2*lt);
lm += lt;
tm += lt;
offGraphics.setColor(Color.white);
offGraphics.fillRect(lm,tm,aw-4*lt,ah-4*lt);
lm += lt;
tm += lt;
int sfh = (lh > 30) ? lh / 4 : lh / 2;
Font font = new Font("SansSerif", Font.PLAIN, sfh);
offGraphics.setFont(font);
for (int j = 0, y = tm; j < 15; j++, y += lh + lt) {
for (int i = 0, x = lm; i < 15; i++, x += lw + lt) {
Color c = tiles[j < 8 ? j : 14 - j][i < 8 ? i : 14 - i];
offGraphics.setColor(c);
offGraphics.fillRect(x, y, lw, lh);
offGraphics.setColor(Color.black);
if (lh > 30) {
String td = (c == w2 || c == l2) ? "DOUBLE" :
(c == w3 || c == l3) ? "TRIPLE" : null;
String wl = (c == l2 || c == l3) ? "LETTER" :
(c == w2 || c == w3) ? "WORD" : null;
if (td != null) {
center(offGraphics, td, x, y + 2 + sfh, lw);
center(offGraphics, wl, x, y + 2 * (2 + sfh), lw);
center(offGraphics, "SCORE", x, y + 3 * (2 + sfh), lw);
}
} else {
String td = (c == w2 || c == l2) ? "2" :
(c == w3 || c == l3) ? "3" : null;
String wl = (c == l2 || c == l3) ? "L" :
(c == w2 || c == w3) ? "W" : null;
if (td != null) {
center(offGraphics, td + wl, x,
y + (lh - sfh) * 4 / 10 + sfh, lw);
}
}
}
}
Color c = new Color(255, 255, 200);
offGraphics.setColor(c);
THE JAVA LANGUAGE
Chapter 2: An Overview of Java 31
assigns to num the value 100. In Java, the assignment operator is a single equal sign.
The next line of code outputs the value of num preceded by the string “This is num:”.
System.out.println("This is num: " + num);
In this statement, the plus sign causes the value of num to be appended to the string
that precedes it, and then the resulting string is output. (Actually, num is first converted
from an integer into its string equivalent and then concatenated with the string that
precedes it. This process is described in detail later in this book.) This approach can be
generalized. Using the + operator, you can string together as many items as you want
within a single println( ) statement.
The next line of code assigns num the value of num times 2. Like most other
languages, Java uses the * operator to indicate multiplication. After this line executes,
num will contain the value 200.
Here are the next two lines in the program:
System.out.print("The value of num * 2 is ");
System.out.println(num);
Several new things are occurring here. First, the built-in method print( ) is used to
display the string “The value of num * 2 is ”. This string is not followed by a newline.
This means that when the next output is generated, it will start on the same line. The
print( ) method is just like println( ), except that it does not output a newline character
after each call. Now look at the call to println( ). Notice that num is used by itself. Both
print( ) and println( ) can be used to output values of any of Java’s built-in types.
Two Control Statements
Although Chapter 5 will look closely at control statements, two are briefly introduced
here so that they can be used in example programs in Chapters 3 and 4. They will also
help illustrate an important aspect of Java: blocks of code.
The if Statement
The Java if statement works much like the IF statement in any other language. Further,
it is syntactically identical to the if statements in C, C++, and C#. Its simplest form is
shown here:
if(condition) statement;
782 Java™ 2: The Complete Reference
}
f.setVisible(true);
}
public void stop() {
f.setVisible(false);
}
Sample output from the MenuDemo applet is shown in Figure 22-8.
There is one other menu-related class that you might find interesting: PopupMenu.
It works just like Menu but produces a menu that can be displayed at a specific location.
PopupMenu provides a flexible, useful alternative for some types of menuing situations.
Dialog Boxes
Often, you will want to use a dialog box to hold a set of related controls. Dialog boxes
are primarily used to obtain user input. They are similar to frame windows, except that
dialog boxes are always child windows of a top-level window. Also, dialog boxes don’t
have menu bars. In other respects, dialog boxes function like frame windows. (You can
add controls to them, for example, in the same way that you add controls to a frame
window.) Dialog boxes may be modal or modeless. When a modal dialog box is active,
Figure 22-8.
Sample output from the MenuDemo applet
THE JAVA LIBRARY
Chapter 23: Images 801
Image Fundamentals: Creating, Loading,
and Displaying
There are three common operations that occur when you work with images: creating
an image, loading an image, and displaying an image. In Java, the Image class is used
to refer to images in memory and to images that must be loaded from external sources.
Thus, Java provides ways for you to create a new image object and ways to load one. It
also provides a means by which an image can be displayed. Let’s look at each.
Creating an Image Object
You might expect that you create a memory image using something like the following:
Image test = new Image(200, 100); // Error -- won't work
Not so. Because images must eventually be painted on a window to be seen, the Image
class doesn’t have enough information about its environment to create the proper data
format for the screen. Therefore, the Component class in java.awt has a factory method
called createImage( ) that is used to create Image objects. (Remember that all of the
AWT components are subclasses of Component, so all support this method.)
The createImage( ) method has the following two forms:
Image createImage(ImageProducer imgProd)
Image createImage(int width, int height)
The first form returns an image produced by imgProd, which is an object of a class that
implements the ImageProducer interface. (We will look at image producers later.)
The second form returns a blank (that is, empty) image that has the specified width
and height. Here is an example:
Canvas c = new Canvas();
Image test = c.createImage(200, 100);
This creates an instance of Canvas and then calls the createImage( ) method to actually
make an Image object. At this point, the image is blank. Later you will see how to write
data to it.
Loading an Image
The other way to obtain an image is to load one. To do this, use the getImage( ) method
defined by the Applet class. It has the following forms:
Image getImage(URL url)
Image getImage(URL url, String imageName)
SOFTWARE DEVELOPMENT
USING JAVA
Chapter 27: Servlets 979
}
pw.println("Current date: " + date);
}
When you first request this servlet, the browser displays one line with the current
date and time information. On subsequent invocations, two lines are displayed. The
first line shows the date and time when the servlet was last accessed. The second line
shows the current date and time.
Security Issues
In earlier chapters of this book, you learned that untrusted applets are constrained
to operate in a “sandbox”. They cannot perform operations that are potentially
dangerous to a user’s machine. This includes reading and writing files, opening
sockets to arbitrary machines, calling native methods, and creating new processes.
Other restrictions also apply.
Similar constraints also exist for untrusted servlets. Code that is loaded from a
remote machine is untrusted. However, trusted servlets are not limited in this manner.
Trusted servlets are those which are loaded from the local machine.
368 Java™ 2: The Complete Reference
String Methods Added by Java 2, Version 1.4
Java 2, version 1.4 adds several methods to the String class. These are summarized in
the following table.
Method
boolean contentEquals(StringBuffer str)
CharSequence
subSequence(int startIndex,
int stopIndex)
boolean matches(string regExp)
String
replaceFirst(String regExp,
String newStr)
String
replaceAll(String regExp,
String newStr)
String[ ] split(String regExp)
String[ ] split(String regExp, int max)
Description
Returns true if the invoking string contains
the same string as str. Otherwise, returns
false.
Returns a substring of the invoking string,
beginning at startIndex and stopping at
stopIndex. This method is required by the
CharSequence interface, which is now
implemented by String.
Returns true if the invoking string matches
the regular expression passed in regExp.
Otherwise, returns false.
Returns a string in which the first substring
that matches the regular expression
specified by regExp is replaced by newStr.
Returns a string in which all substrings that
match the regular expression specified by
regExp are replaced by newStr.
Decomposes the invoking string into parts
and returns an array that contains the
result. Each part is delimited by the regular
expression passed in regExp.
Decomposes the invoking string into parts
and returns an array that contains the
result. Each part is delimited by the regular
expression passed in regExp. The number
of pieces is specified by max. If max is
negative, then the invoking string is fully
decomposed. Otherwise, if max contains
a non-zero value, the last entry in the
returned array contains the remainder
of the invoking string. If max is zero, the
invoking string is fully decomposed.
THE JAVA LANGUAGE
Chapter 12: I/O, Applets, and Other Topics 321
public static void main(String args[])
throws IOException
{
// create a BufferedReader using System.in
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String str;
}
}
System.out.println("Enter lines of text.");
System.out.println("Enter 'stop' to quit.");
do {
str = br.readLine();
System.out.println(str);
} while(!str.equals("stop"));
The next example creates a tiny text editor. It creates an array of String objects and
then reads in lines of text, storing each line in the array. It will read up to 100 lines or
until you enter “stop”. It uses a BufferedReader to read from the console.
// A tiny editor.
import java.io.*;
class TinyEdit {
public static void main(String args[])
throws IOException
{
// create a BufferedReader using System.in
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String str[] = new String[100];
System.out.println("Enter lines of text.");
System.out.println("Enter 'stop' to quit.");
for(int i=0; i<100; i++) {
str[i] = br.readLine();
if(str[i].equals("stop")) break;
}
System.out.println("\nHere is your file:");
446 Java™ 2: The Complete Reference
Method
void add(int index, Object obj)
boolean addAll(int index, Collection c)
Object get(int index)
int indexOf(Object obj)
int lastIndexOf(Object obj)
ListIterator listIterator( )
ListIterator listIterator(int index)
Object remove(int index)
Object set(int index, Object obj)
List subList(int start, int end)
Description
Inserts obj into the invoking list at the
index passed in index. Any preexisting
elements at or beyond the point of
insertion are shifted up. Thus, no
elements are overwritten.
Inserts all elements of c into the invoking
list at the index passed in index. Any
preexisting elements at or beyond the
point of insertion are shifted up. Thus,
no elements are overwritten. Returns
true if the invoking list changes and
returns false otherwise.
Returns the object stored at the specified
index within the invoking collection.
Returns the index of the first instance of
obj in the invoking list. If obj is not an
element of the list, –1 is returned.
Returns the index of the last instance of
obj in the invoking list. If obj is not an
element of the list, –1 is returned.
Returns an iterator to the start of the
invoking list.
Returns an iterator to the invoking list
that begins at the specified index.
Removes the element at position index from
the invoking list and returns the deleted
element. The resulting list is compacted.
That is, the indexes of subsequent elements
are decremented by one.
Assigns obj to the location specified by
index within the invoking list.
Returns a list that includes elements
from start to end–1 in the invoking list.
Elements in the returned list are also
referenced by the invoking object.
Table 15-2.
The Methods Defined by List
THE JAVA LIBRARY
Chapter 21: Introducing the AWT: Working with Windows, Graphics, and Text 721
// Show fonts.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
/*
*/
public class SampleFonts extends Applet {
int next = 0;
Font f;
String msg;
public void init() {
f = new Font("Dialog", Font.PLAIN, 12);
msg = "Dialog";
setFont(f);
addMouseListener(new MyMouseAdapter(this));
}
}
public void paint(Graphics g) {
g.drawString(msg, 4, 20);
}
class MyMouseAdapter extends MouseAdapter {
SampleFonts sampleFonts;
public MyMouseAdapter(SampleFonts sampleFonts) {
this.sampleFonts = sampleFonts;
}
public void mousePressed(MouseEvent me) {
// Switch fonts with each mouse click.
sampleFonts.next++;
switch(sampleFonts.next) {
case 0:
sampleFonts.f = new Font("Dialog", Font.PLAIN, 12);
sampleFonts.msg = "Dialog";
break;
case 1:
sampleFonts.f = new Font("DialogInput", Font.PLAIN, 12);
sampleFonts.msg = "DialogInput";
break;
case 2:
98 Java™ 2: The Complete Reference
In addition to altering the normal precedence of an operator, parentheses can
sometimes be used to help clarify the meaning of an expression. For anyone reading
your code, a complicated expression can be difficult to understand. Adding redundant
but clarifying parentheses to complex expressions can help prevent confusion later. For
example, which of the following expressions is easier to read?
a | 4 + c >> b & 7
(a | (((4 + c) >> b) & 7))
One other point: parentheses (redundant or not) do not degrade the performance of
your program. Therefore, adding parentheses to reduce ambiguity does not negatively
affect your program.
670 Java™ 2: The Complete Reference
The ActionListener Interface
This interface defines the actionPerformed( ) method that is invoked when an action
event occurs. Its general form is shown here:
void actionPerformed(ActionEvent ae)
The AdjustmentListener Interface
This interface defines the adjustmentValueChanged( ) method that is invoked when
an adjustment event occurs. Its general form is shown here:
void adjustmentValueChanged(AdjustmentEvent ae)
The ComponentListener Interface
This interface defines four methods that are invoked when a component is resized,
moved, shown, or hidden. Their general forms are shown here:
void componentResized(ComponentEvent ce)
void componentMoved(ComponentEvent ce)
void componentShown(ComponentEvent ce)
void componentHidden(ComponentEvent ce)
The AWT processes the resize and move events. The componentResized( ) and
componentMoved( ) methods are provided for notification purposes only.
The ContainerListener Interface
This interface contains two methods. When a component is added to a container,
componentAdded( ) is invoked. When a component is removed from a container,
componentRemoved( ) is invoked. Their general forms are shown here:
void componentAdded(ContainerEvent ce)
void componentRemoved(ContainerEvent ce)
The FocusListener Interface
This interface defines two methods. When a component obtains keyboard focus,
focusGained( ) is invoked. When a component loses keyboard focus, focusLost( )
is called. Their general forms are shown here:
void focusGained(FocusEvent fe)
void focusLost(FocusEvent fe)
THE JAVA LIBRARY
Chapter 13: String Handling 353
Be careful when you mix other types of operations with string concatenation
expressions, however. You might get surprising results. Consider the following:
String s = "four: " + 2 + 2;
System.out.println(s);
This fragment displays
four: 22
rather than the
four: 4
that you probably expected. Here’s why. Operator precedence causes the concatenation of
“four” with the string equivalent of 2 to take place first. This result is then concatenated
with the string equivalent of 2 a second time. To complete the integer addition first, you
must use parentheses, like this:
String s = "four: " + (2 + 2);
Now s contains the string “four: 4”.
String Conversion and toString( )
When Java converts data into its string representation during concatenation, it does so
by calling one of the overloaded versions of the string conversion method valueOf( )
defined by String. valueOf( ) is overloaded for all the simple types and for type Object.
For the simple types, valueOf( ) returns a string that contains the human-readable
equivalent of the value with which it is called. For objects, valueOf( ) calls the
toString( ) method on the object. We will look more closely at valueOf( ) later in this
chapter. Here, let’s examine the toString( ) method, because it is the means by which
you can determine the string representation for objects of classes that you create.
Every class implements toString( ) because it is defined by Object. However, the
default implementation of toString( ) is seldom sufficient. For most important classes
that you create, you will want to override toString( ) and provide your own string
representations. Fortunately, this is easy to do. The toString( ) method has this
general form:
String toString( )
To implement toString( ), simply return a String object that contains the humanreadable
string that appropriately describes an object of your class.
SOFTWARE DEVELOPMENT
USING JAVA
Chapter 25: Java Beans 891
Create and Configure an Instance of the OurButton Bean
Follow these steps to create and configure an instance of the OurButton Bean and
connect it to the Molecule Bean:
1. Position the cursor on the ToolBox entry labeled OurButton and click the left
mouse button. You should see the cursor change to a cross.
2. Move the cursor to the BeanBox display area and click the left mouse button in
approximately the area where you wish the Bean to be displayed. You should
see a rectangular region appear that contains a button. This area is surrounded
by a hatched border indicating that it is currently selected.
3. You may reposition the OurButton Bean by positioning the cursor over one of
the hatched borders and dragging the Bean.
4. Go to the Properties window and change the label of the Bean to “Rotate X”.
The button appearance changes immediately when this property is changed.
5. Go to the menu bar of the BeanBox and select Edit | Events | action |
actionPerformed. You should now see a line extending from the button to the
cursor. Notice that one end of the line moves as the cursor moves. However, the
other end of the line remains fixed at the button.
6. Move the cursor so that it is inside the Molecule Bean display area, and click
the left mouse button. You should see the Event Target Dialog dialog box.
7. The dialog box allows you to choose a method that should be invoked when
this button is clicked. Select the entry labeled “rotateOnX” and click the OK
button. You should see a message box appear very briefly, stating that the tool
is “Generating and compiling adaptor class.”
Test the application. Each time you press the button, the molecule should move a
few degrees around one of its axes.
Now create another instance of the OurButton Bean. Label it “Rotate Y” and map
its action event to the “rotateY” method of the Molecule Bean. The steps to do this are
very similar to those just described for the button labeled “Rotate X”.
Test the application by clicking these buttons and observing how the molecule moves.
JAR Files
Before developing your own Bean, it is necessary for you to understand JAR (Java
Archive) files, because tools such as the BDK expect Beans to be packaged within JAR
files. A JAR file allows you to efficiently deploy a set of classes and their associated
resources. For example, a developer may build a multimedia application that uses
various sound and image files. A set of Beans can control how and when this
information is presented. All of these pieces can be placed into one JAR file.
THE JAVA LANGUAGE
Chapter 4: Operators 79
These operators are unique in that they can appear both in postfix form, where
they follow the operand as just shown, and prefix form, where they precede the
operand. In the foregoing examples, there is no difference between the prefix and
postfix forms. However, when the increment and/or decrement operators are part
of a larger expression, then a subtle, yet powerful, difference between these two forms
appears. In the prefix form, the operand is incremented or decremented before the value
is obtained for use in the expression. In postfix form, the previous value is obtained for
use in the expression, and then the operand is modified. For example:
x = 42;
y = ++x;
In this case, y is set to 43 as you would expect, because the increment occurs before x is
assigned to y. Thus, the line y = ++x; is the equivalent of these two statements:
x = x + 1;
y = x;
However, when written like this,
x = 42;
y = x++;
the value of x is obtained before the increment operator is executed, so the value of
y is 42. Of course, in both cases x is set to 43. Here, the line y = x++; is the equivalent
of these two statements:
y = x;
x = x + 1;
The following program demonstrates the increment operator.
// Demonstrate ++.
class IncDec {
public static void main(String args[]) {
int a = 1;
int b = 2;
int c;
THE JAVA LANGUAGE
Chapter 7: A Closer Look at Methods and Classes 183
// This program will not compile.
class Outer {
int outer_x = 100;
}
void test() {
Inner inner = new Inner();
inner.display();
}
// this is an inner class
class Inner {
int y = 10; // y is local to Inner
void display() {
System.out.println("display: outer_x = " + outer_x);
}
}
void showy() {
System.out.println(y); // error, y not known here!
}
class InnerClassDemo {
public static void main(String args[]) {
Outer outer = new Outer();
outer.test();
}
}
Here, y is declared as an instance variable of Inner. Thus it is not known outside of
that class and it cannot be used by showy( ).
Although we have been focusing on nested classes declared within an outer class
scope, it is possible to define inner classes within any block scope. For example, you
can define a nested class within the block defined by a method or even within the body
of a for loop, as this next program shows.
// Define an inner class within a for loop.
class Outer {
int outer_x = 100;
THE JAVA LIBRARY
Chapter 23: Images 841
Figure 23-13.
Sample output of Animation
imaging techniques. Java 2, version 1.4 also adds a new imaging package called
javax.imageio. This package supports plug-ins that handle various image formats.
If sophisticated graphical output is of special interest to you, then you will want to
explore the additional classes found in java.awt.image and javax.imageio.
600 Java™ 2: The Complete Reference
System.out.println("No expiration information.");
else
System.out.println("Expires: " + new Date(d));
// get last-modified date
d = hpCon.getLastModified();
if(d==0)
System.out.println("No last-modified information.");
else
System.out.println("Last-Modified: " + new Date(d));
// get content length
int len = hpCon.getContentLength();
if(len == -1)
System.out.println("Content length unavailable.");
else
System.out.println("Content-Length: " + len);
if(len != 0) {
System.out.println("=== Content ===");
InputStream input = hpCon.getInputStream();
int i = len;
while (((c = input.read()) != -1)) { // && (--i > 0)) {
System.out.print((char) c);
}
input.close();
} else {
System.out.println("No content available.");
}
}
}
The program establishes an HTTP connection to www.internic.net over port 80. We
then list out the header values and retrieve the content. Here are the first lines of the
output (the precise output will vary over time).
Date: Sat Apr 27 12:17:32 CDT 2002
Content-Type: text/html
No expiration information.
Last-Modified: Tue Mar 19 17:52:42 CST 2002
Content-Length: 5299
=== Content ===
Chapter 23
Images
799
790 Java™ 2: The Complete Reference
}
}
FileDialog fd = new FileDialog(f, "File Dialog");
fd.setVisible(true);
The output generated by this program is shown here. (The precise configuration of the
dialog box may vary.)
Handling Events by Extending AWT
Components
Before concluding our look at the AWT, one more topic needs to be discussed: handling
events by extending AWT components. The delegation event model was introduced in
Chapter 20, and all of the programs in this book so far have used that design. But Java also
allows you to handle events by subclassing AWT components. Doing so allows you to
handle events in much the same way as they were handled under the original 1.0 version
of Java. Of course, this technique is discouraged, because it has the same disadvantages of
the Java 1.0 event model, the main one being inefficiency. Handling events by extending
AWT components is described in this section for completeness. However, this technique
is not used in any other sections of this book.
To extend an AWT component, you must call the enableEvents( ) method of
Component. Its general form is shown here:
protected final void enableEvents(long eventMask)
214 Java™ 2: The Complete Reference
Dynamic, run-time polymorphism is one of the most powerful mechanisms that
object-oriented design brings to bear on code reuse and robustness. The ability of
existing code libraries to call methods on instances of new classes without recompiling
while maintaining a clean abstract interface is a profoundly powerful tool.
Applying Method Overriding
Let’s look at a more practical example that uses method overriding. The following
program creates a superclass called Figure that stores the dimensions of various
two-dimensional objects. It also defines a method called area( ) that computes the area
of an object. The program derives two subclasses from Figure. The first is Rectangle
and the second is Triangle. Each of these subclasses overrides area( ) so that it returns
the area of a rectangle and a triangle, respectively.
// Using run-time polymorphism.
class Figure {
double dim1;
double dim2;
}
Figure(double a, double b) {
dim1 = a;
dim2 = b;
}
double area() {
System.out.println("Area for Figure is undefined.");
return 0;
}
class Rectangle extends Figure {
Rectangle(double a, double b) {
super(a, b);
}
}
// override area for rectangle
double area() {
System.out.println("Inside Area for Rectangle.");
return dim1 * dim2;
}
class Triangle extends Figure {
562 Java™ 2: The Complete Reference
RandomAccessFile implements the standard input and output methods, which
you can use to read and write to random access files. It also includes some additional
methods. One is setLength( ). It has this signature:
void setLength(long len) throws IOException
This method sets the length of the invoking file to that specified by len. This method can be
used to lengthen or shorten a file. If the file is lengthened, the added portion is undefined.
Java 2, version 1.4 added the getChannel( ) method to RandomAccessFile. This
method returns a channel connected to the RandomAccessFile object. Channels are
used by the new I/O classes contained in java.nio. (See Chapter 24.)
The Character Streams
While the byte stream classes provide sufficient functionality to handle any type of I/O
operation, they cannot work directly with Unicode characters. Since one of the main
purposes of Java is to support the “write once, run anywhere” philosophy, it was
necessary to include direct I/O support for characters. In this section, several of the
character I/O classes are discussed. As explained earlier, at the top of the character
stream hierarchies are the Reader and Writer abstract classes. We will begin with them.
As discussed in Chapter 12, the character I/O classes were added by the 1.1 release of
Java. Because of this, you may still find legacy code that uses byte streams where
character streams should be. When working on such code, it is a good idea to update it.
Reader
Reader is an abstract class that defines Java’s model of streaming character input. All of
the methods in this class will throw an IOException on error conditions. Table 17-3
provides a synopsis of the methods in Reader.
Writer
Writer is an abstract class that defines streaming character output. All of the methods
in this class return a void value and throw an IOException in the case of errors.
Table 17-4 shows a synopsis of the methods in Writer.
FileReader
The FileReader class creates a Reader that you can use to read the contents of a file. Its
two most commonly used constructors are shown here:
FileReader(String filePath)
FileReader(File fileObj)
THE JAVA LANGUAGE
Chapter 4: Operators 77
a += 4;
This version uses the += assignment operator. Both statements perform the same
action: they increase the value of a by 4.
Here is another example,
a = a % 2;
which can be expressed as
a %= 2;
In this case, the %= obtains the remainder of a/2 and puts that result back into a.
There are assignment operators for all of the arithmetic, binary operators. Thus,
any statement of the form
var = var op expression;
can be rewritten as
var op= expression;
The assignment operators provide two benefits. First, they save you a bit of typing,
because they are “shorthand” for their equivalent long forms. Second, they are
implemented more efficiently by the Java run-time system than are their equivalent
long forms. For these reasons, you will often see the assignment operators used in
professionally written Java programs.
Here is a sample program that shows several op= operator assignments in action:
// Demonstrate several assignment operators.
class OpEquals {
public static void main(String args[]) {
int a = 1;
int b = 2;
int c = 3;
a += 5;
b *= 4;
Part I
The Java Language
1000 Java™ 2: The Complete Reference
}
cout << "Area of 3.0 by 3.0 square: ";
cout << area(3.0) << endl;
return 0;
As you can see, when area( ) is called with only one argument, the second defaults to
zero. When this happens, the function simply uses the first argument for both the
length and the width of the rectangle.
While convenient, default arguments are not, of course, necessary. In essence,
default arguments are actually a shorthand form of function overloading in which one
form of the function has a different number of parameters than the other. Thus, to
convert a C++ function that contains one or more default arguments into Java, simply
create overloaded methods that handle each case. In this example, you need a version
of area( ) that takes two arguments and another that takes only one argument. Using
this approach, here is the preceding program rewritten for Java:
// Java version of area program.
class Area {
// Compute area of a rectangle.
static double area(double l, double w) {
if(w==0) return l * l;
else return l * w;
}
// Overload area( ) for a square.
static double area(double l) {
return l * l;
}
public static void main(String args[]) {
System.out.println("Area of 2.2 by 3.4 rectangle: " +
area(2.2, 3.4));
}
}
System.out.println("Area of 3.0 by 3.0 square: " +
area(3.0));
712 Java™ 2: The Complete Reference
public class ResizeMe extends Applet {
final int inc = 25;
int max = 500;
int min = 200;
Dimension d;
public ResizeMe() {
addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent me) {
int w = (d.width + inc) > max?min :(d.width + inc);
int h = (d.height + inc) > max?min :(d.height + inc);
setSize(new Dimension(w, h));
}
});
}
public void paint(Graphics g) {
d = getSize();
}
}
g.drawLine(0, 0, d.width-1, d.height-1);
g.drawLine(0, d.height-1, d.width-1, 0);
g.drawRect(0, 0, d.width-1, d.height-1);
Working with Color
Java supports color in a portable, device-independent fashion. The AWT color system
allows you to specify any color you want. It then finds the best match for that color,
given the limits of the display hardware currently executing your program or applet.
Thus, your code does not need to be concerned with the differences in the way color is
supported by various hardware devices. Color is encapsulated by the Color class.
As you saw in Chapter 19, Color defines several constants (for example, Color.black)
to specify a number of common colors. You can also create your own colors, using one of
the color constructors. The most commonly used forms are shown here:
Color(int red, int green, int blue)
Color(int rgbValue)
Color(float red, float green, float blue)
The first constructor takes three integers that specify the color as a mix of red, green,
and blue. These values must be between 0 and 255, as in this example:
new Color(255, 100, 100); // light red.
942 Java™ 2: The Complete Reference
Here, tel is the listener object.
The getPathForLocation( ) method is used to translate a mouse click on a specific
point of the tree to a tree path. Its signature is shown here:
TreePath getPathForLocation(int x, int y)
Here, x and y are the coordinates at which the mouse is clicked. The return value is a
TreePath object that encapsulates information about the tree node that was selected by
the user.
The TreePath class encapsulates information about a path to a particular node in a
tree. It provides several constructors and methods. In this book, only the toString( )
method is used. It returns a string equivalent of the tree path.
The TreeNode interface declares methods that obtain information about a tree
node. For example, it is possible to obtain a reference to the parent node or an
enumeration of the child nodes. The MutableTreeNode interface extends TreeNode. It
declares methods that can insert and remove child nodes or change the parent node.
The DefaultMutableTreeNode class implements the MutableTreeNode interface.
It represents a node in a tree. One of its constructors is shown here:
DefaultMutableTreeNode(Object obj)
Here, obj is the object to be enclosed in this tree node. The new tree node doesn’t have a
parent or children.
To create a hierarchy of tree nodes, the add( ) method of DefaultMutableTreeNode
can be used. Its signature is shown here:
void add(MutableTreeNode child)
Here, child is a mutable tree node that is to be added as a child to the current node.
Tree expansion events are described by the class TreeExpansionEvent in the
javax.swing.event package. The getPath( ) method of this class returns a TreePath
object that describes the path to the changed node. Its signature is shown here:
TreePath getPath( )
The TreeExpansionListener interface provides the following two methods:
void treeCollapsed(TreeExpansionEvent tee)
void treeExpanded(TreeExpansionEvent tee)
Here, tee is the tree expansion event. The first method is called when a subtree is
hidden, and the second method is called when a subtree becomes visible.
Here are the steps that you should follow to use a tree in an applet:
SOFTWARE DEVELOPMENT
USING JAVA
Chapter 28: Migrating from C++ to Java 993
// Swap program incorrectly converted to Java.
class Coord {
int x;
int y;
};
class SwapDemo {
static void swap(Coord a, Coord b) {
Coord temp = new Coord();
}
// this won't swap contents of a and b!
temp = a;
a = b;
b = temp;
public static void main(String args[]) {
Coord ob1 = new Coord();
Coord ob2 = new Coord();
}
}
ob1.x = 10;
ob1.y = 20;
ob2.x = 88;
ob2.y = 99;
System.out.println("Original values:");
System.out.println("ob1: " +
ob1.x + ", " + ob1.y);
System.out.println("ob2: " +
ob2.x + ", " + ob2.y + "\n");
swap(ob1, ob2);
System.out.println("Swapped values:");
System.out.println("ob1: " +
ob1.x + ", " + ob1.y);
System.out.println("ob2: " +
ob2.x + ", " + ob2.y + "\n");
THE JAVA LIBRARY
Chapter 15: java.util Part 1: The Collections Framework 441
The ResourceBundle, ListResourceBundle, and PropertyResourceBundle classes
aid in the internationalization of large programs with many locale-specific resources.
These classes are not examined here. PropertyPermission, which allows you to grant
a read/write permission to a system property, is also beyond the scope of this book.
EventObject, EventListener, and EventListenerProxy are described in Chapter 20. The
remaining classes and interfaces are examined in detail.
Because java.util is quite large, its description is broken into two chapters. This
chapter examines those members of java.util that relate to collections of objects.
Chapter 16 discusses the other classes and interfaces.
Collections Overview
The Java collections framework standardizes the way in which groups of objects are
handled by your programs. Prior to Java 2, Java provided ad hoc classes such as
Dictionary, Vector, Stack, and Properties to store and manipulate groups of objects.
Although these classes were quite useful, they lacked a central, unifying theme. Thus,
the way that you used Vector was different from the way that you used Properties, for
example. Also, the previous, ad hoc approach was not designed to be easily extensible
or adaptable. Collections are an answer to these (and other) problems.
The collections framework was designed to meet several goals. First, the framework
had to be high-performance. The implementations for the fundamental collections
(dynamic arrays, linked lists, trees, and hash tables) are highly efficient. You seldom, if
ever, need to code one of these “data engines” manually. Second, the framework had to
allow different types of collections to work in a similar manner and with a high degree of
interoperability. Third, extending and/or adapting a collection had to be easy. Toward this
end, the entire collections framework is designed around a set of standard interfaces.
Several standard implementations (such as LinkedList, HashSet, and TreeSet)ofthese
interfaces are provided that you may use as-is. You may also implement your own
collection, if you choose. Various special-purpose implementations are created for your
convenience, and some partial implementations are provided that make creating your own
collection class easier. Finally, mechanisms were added that allow the integration of
standard arrays into the collections framework.
Algorithms are another important part of the collection mechanism. Algorithms
operate on collections and are defined as static methods within the Collections class.
Thus, they are available for all collections. Each collection class need not implement its
own versions. The algorithms provide a standard means of manipulating collections.
Another item created by the collections framework is the Iterator interface. An
iterator gives you a general-purpose, standardized way of accessing the elements
within a collection, one at a time. Thus, an iterator provides a means of enumerating the
contents of a collection. Because each collection implements Iterator, the elements of any
collection class can be accessed through the methods defined by Iterator. Thus, with
only small changes, the code that cycles through a set can also be used to cycle through
a list, for example.
THE JAVA LIBRARY
Chapter 17: Input/Output: Exploring java.io 565
while((s = br.readLine()) != null) {
System.out.println(s);
}
}
}
fr.close();
FileWriter
FileWriter creates a Writer that you can use to write to a file. Its most commonly used
constructors are shown here:
FileWriter(String filePath)
FileWriter(String filePath, boolean append)
FileWriter(File fileObj)
FileWriter(File fileObj, boolean append)
They can throw an IOException. Here, filePath is the full path name of a file, and fileObj
is a File object that describes the file. If append is true, then output is appended to the
end of the file. The fourth constructor was added by Java 2, version 1.4.
Creation of a FileWriter is not dependent on the file already existing. FileWriter
will create the file before opening it for output when you create the object. In the case
where you attempt to open a read-only file, an IOException will be thrown.
The following example is a character stream version of an example shown earlier
when FileOutputStream was discussed. This version creates a sample buffer of
characters by first making a String and then using the getChars( ) method to extract
the character array equivalent. It then creates three files. The first, file1.txt, will contain
every other character from the sample. The second, file2.txt, will contain the entire set
of characters. Finally, the third, file3.txt, will contain only the last quarter.
// Demonstrate FileWriter.
import java.io.*;
class FileWriterDemo {
public static void main(String args[]) throws Exception {
String source = "Now is the time for all good men\n"
+ " to come to the aid of their country\n"
+ " and pay their due taxes.";
char buffer[] = new char[source.length()];
source.getChars(0, source.length(), buffer, 0);
THE JAVA LIBRARY
Chapter 20: Event Handling 675
public void mousePressed(MouseEvent me) {
// save coordinates
mouseX = me.getX();
mouseY = me.getY();
msg = "Down";
repaint();
}
// Handle button released.
public void mouseReleased(MouseEvent me) {
// save coordinates
mouseX = me.getX();
mouseY = me.getY();
msg = "Up";
repaint();
}
}
// Handle mouse dragged.
public void mouseDragged(MouseEvent me) {
// save coordinates
mouseX = me.getX();
mouseY = me.getY();
msg = "*";
showStatus("Dragging mouse at " + mouseX + ", " + mouseY);
repaint();
}
// Handle mouse moved.
public void mouseMoved(MouseEvent me) {
// show status
showStatus("Moving mouse at " + me.getX() + ", " + me.getY());
}
// Display msg in applet window at current X,Y location.
public void paint(Graphics g) {
g.drawString(msg, mouseX, mouseY);
}
THE JAVA LIBRARY
Chapter 15: java.util Part 1: The Collections Framework 453
The first constructor builds an empty linked list. The second constructor builds a linked
list that is initialized with the elements of the collection c.
In addition to the methods that it inherits, the LinkedList class defines some useful
methods of its own for manipulating and accessing lists. To add elements to the start of
the list, use addFirst( ); to add elements to the end, use addLast( ). Their signatures are
shown here:
void addFirst(Object obj)
void addLast(Object obj)
Here, obj is the item being added.
To obtain the first element, call getFirst( ). To retrieve the last element, call
getLast( ). Their signatures are shown here:
Object getFirst( )
Object getLast( )
To remove the first element, use removeFirst( ); to remove the last element, call
removeLast( ). They are shown here:
Object removeFirst( )
Object removeLast( )
The following program illustrates several of the methods supported by LinkedList:
// Demonstrate LinkedList.
import java.util.*;
class LinkedListDemo {
public static void main(String args[]) {
// create a linked list
LinkedList ll = new LinkedList();
// add elements to the linked list
ll.add("F");
ll.add("B");
ll.add("D");
ll.add("E");
ll.add("C");
ll.addLast("Z");
ll.addFirst("A");
ll.add(1, "A2");
26 Java™ 2: The Complete Reference
guess, your operating system must be capable of supporting long filenames. This means
that DOS and Windows 3.1 are not capable of supporting Java. However, Windows
95/98 and Windows NT/2000/XP work just fine.
As you can see by looking at the program, the name of the class defined by the
program is also Example. This is not a coincidence. In Java, all code must reside inside
a class. By convention, the name of that class should match the name of the file that
holds the program. You should also make sure that the capitalization of the filename
matches the class name. The reason for this is that Java is case-sensitive. At this point,
the convention that filenames correspond to class names may seem arbitrary. However,
this convention makes it easier to maintain and organize your programs.
Compiling the Program
To compile the Example program, execute the compiler, javac, specifying the name of
the source file on the command line, as shown here:
C:\>javac Example.java
The javac compiler creates a file called Example.class that contains the bytecode version
of the program. As discussed earlier, the Java bytecode is the intermediate representation
of your program that contains instructions the Java interpreter will execute. Thus, the
output of javac is not code that can be directly executed.
To actually run the program, you must use the Java interpreter, called java. To do
so, pass the class name Example as a command-line argument, as shown here:
C:\>java Example
When the program is run, the following output is displayed:
This is a simple Java program.
When Java source code is compiled, each individual class is put into its own output
file named after the class and using the .class extension. This is why it is a good idea to
give your Java source files the same name as the class they contain—the name of the
source file will match the name of the .class file. When you execute the Java interpreter
as just shown, you are actually specifying the name of the class that you want the
interpreter to execute. It will automatically search for a file by that name that has
the .class extension. If it finds the file, it will execute the code contained in the
specified class.
344 Java™ 2: The Complete Reference
To enable or disable all subpackages of a package, follow the package name with three
dots. For example,
-ea:MyPack...
You can also specify a class with the -ea or -da option. For example, this enables
AssertDemo individually.
-ea:AssertDemo
492 Java™ 2: The Complete Reference
Stack st = new Stack();
}
}
System.out.println("stack: " + st);
showpush(st, 42);
showpush(st, 66);
showpush(st, 99);
showpop(st);
showpop(st);
showpop(st);
try {
showpop(st);
} catch (EmptyStackException e) {
System.out.println("empty stack");
}
The following is the output produced by the program; notice how the exception
handler for EmptyStackException is caught so that you can gracefully handle a
stack underflow:
stack: [ ]
push(42)
stack: [42]
push(66)
stack: [42, 66]
push(99)
stack: [42, 66, 99]
pop -> 99
stack: [42, 66]
pop -> 66
stack: [42]
pop -> 42
stack: [ ]
pop -> empty stack
Dictionary
Dictionary is an abstract class that represents a key/value storage repository and
operates much like Map. Given a key and value, you can store the value in a Dictionary
1106 Java™ 2: The Complete Reference
}
offGraphics.fillRect(lm, tm + ah - 3 * lt, 7 * (lw + lt), lh +
2 * lt);
Letter.resize(lw, lh);
// if we already have some letters, place them.
for (int i = 0; i < 7; i++) {
if (tray[i] != null) {
moveToTray(tray[i], i);
}
}
paintScore();
}
return d;
center( )
center( ) is a convenience routine that checksize( ) uses to center the “Double Letter
Score” text.
private void center(Graphics g, String s, int x, int y, int w) {
x += (w - g.getFontMetrics().stringWidth(s)) / 2;
g.drawString(s, x, y);
}
paintScore( )
The paintScore( ) method paints the two players’ scores or just the one score in
single-player mode.
private void paintScore() {
int x = lm + (lw + lt) * 7 + lm;
int y = tm + ah - 3 * lt;
int h = lh + 2 * lt;
Font font = new Font("TimesRoman", Font.PLAIN, h/2);
offGraphics.setFont(font);
FontMetrics fm = offGraphics.getFontMetrics();
offGraphics.setColor(Color.white);
offGraphics.fillRect(x, y, aw, h);
offGraphics.setColor(Color.black);
120 Java™ 2: The Complete Reference
In addition to the jump statements discussed here, Java supports one other way that you
can change your program’s flow of execution: through exception handling. Exception
handling provides a structured method by which run-time errors can be trapped and
handled by your program. It is supported by the keywords try, catch, throw, throws,
and finally. In essence, the exception handling mechanism allows your program to
perform a nonlocal branch. Since exception handling is a large topic, it is discussed
in its own chapter, Chapter 10.
Using break
In Java, the break statement has three uses. First, as you have seen, it terminates a
statement sequence in a switch statement. Second, it can be used to exit a loop. Third,
it can be used as a “civilized” form of goto. The last two uses are explained here.
Using break to Exit a Loop
By using break, you can force immediate termination of a loop, bypassing the
conditional expression and any remaining code in the body of the loop. When a break
statement is encountered inside a loop, the loop is terminated and program control
resumes at the next statement following the loop. Here is a simple example:
// Using break to exit a loop.
class BreakLoop {
public static void main(String args[]) {
for(int i=0; i<100; i++) {
if(i == 10) break; // terminate loop if i is 10
System.out.println("i: " + i);
}
System.out.println("Loop complete.");
}
}
This program generates the following output:
i: 0
i: 1
i: 2
i: 3
i: 4
i: 5
i: 6
i: 7
i: 8
THE JAVA LANGUAGE
Chapter 9: Packages and Interfaces 225
Defining a Package
To create a package is quite easy: simply include a package command as the first
statement in a Java source file. Any classes declared within that file will belong to the
specified package. The package statement defines a name space in which classes are
stored. If you omit the package statement, the class names are put into the default
package, which has no name. (This is why you haven’t had to worry about packages
before now.) While the default package is fine for short, sample programs, it is
inadequate for real applications. Most of the time, you will define a package for
your code.
This is the general form of the package statement:
package pkg;
Here, pkg is the name of the package. For example, the following statement creates a
package called MyPackage.
package MyPackage;
Java uses file system directories to store packages. For example, the .class files for
any classes you declare to be part of MyPackage must be stored in a directory called
MyPackage. Remember that case is significant, and the directory name must match the
package name exactly.
More than one file can include the same package statement. The package statement
simply specifies to which package the classes defined in a file belong. It does not exclude
other classes in other files from being part of that same package. Most real-world packages
are spread across many files.
You can create a hierarchy of packages. To do so, simply separate each package
name from the one above it by use of a period. The general form of a multileveled
package statement is shown here:
package pkg1[.pkg2[.pkg3]];
A package hierarchy must be reflected in the file system of your Java development
system. For example, a package declared as
package java.awt.image;
needs to be stored in java/awt/image, java\awt\image, or java:awt:image on your
UNIX, Windows, or Macintosh file system, respectively. Be sure to choose your
package names carefully. You cannot rename a package without renaming the
directory in which the classes are stored.
This page intentionally left blank.
THE JAVA LANGUAGE
Chapter 10: Exception Handling 271
} catch(NullPointerException e) {
// display top level exception
System.out.println("Caught: " + e);
}
}
}
// display cause exception
System.out.println("Original cause: " +
e.getCause());
The output from the program is shown here.
Caught: java.lang.NullPointerException: top layer
Original cause: java.lang.ArithmeticException: cause
In this example, the top-level exception is NullPointerException. To it is added
a cause exception, ArithmeticException. When the exception is thrown out of
demoproc( ), itiscaught by main( ). There, the top-level exception is displayed,
followed by the underlying exception, which is obtained by calling getCause( ).
Chained exceptions can be carried on to whatever depth is necessary. Thus, the
cause exception can, itself, have a cause. Be aware that overly long chains of exceptions
may indicate poor design.
Chained exceptions are not something that every program will need. However, in
cases in which knowledge of an underlying cause is useful, they offer an elegant solution.
Using Exceptions
Exception handling provides a powerful mechanism for controlling complex programs
that have many dynamic run-time characteristics. It is important to think of try, throw,
and catch as clean ways to handle errors and unusual boundary conditions in your
program’s logic. If you are like most programmers, then you probably are used to
returning an error code when a method fails. When you are programming in Java, you
should break this habit. When a method can fail, have it throw an exception. This is a
cleaner way to handle failure modes.
One last point: Java’s exception-handling statements should not be considered a
general mechanism for nonlocal branching. If you do so, it will only confuse your code
and make it hard to maintain.
Chapter 17
Input/Output:
Exploring java.io
537
THE JAVA LIBRARY
Chapter 17: Input/Output: Exploring java.io 547
Method
void reset( )
long skip(long numBytes)
Description
Resets the input pointer to the previously
set mark.
Ignores (that is, skips) numBytes bytes of input,
returning the number of bytes actually ignored.
Table 17-1.
The Methods Defined by InputStream (continued)
OutputStream
OutputStream is an abstract class that defines streaming byte output. All of the
methods in this class return a void value and throw an IOException in the case of
errors. Table 17-2 shows the methods in OutputStream.
Method
void close( )
void flush( )
void write(int b)
void write(byte buffer[ ])
void write(byte buffer[ ], int offset,
int numBytes)
Description
Closes the output stream. Further write
attempts will generate an IOException.
Finalizes the output state so that any
buffers are cleared. That is, it flushes the
output buffers.
Writes a single byte to an output stream.
Note that the parameter is an int, which
allows you to call write( ) with expressions
without having to cast them back to byte.
Writes a complete array of bytes to an
output stream.
Writes a subrange of numBytes bytes from
the array buffer, beginning at buffer[offset].
Table 17-2.
The Methods Defined by OutputStream
28 Java™ 2: The Complete Reference
comments for longer remarks and single-line comments for brief, line-by-line
descriptions.
The next line of code is shown here:
public static void main(String args[]) {
This line begins the main( ) method. As the comment preceding it suggests, this is the
line at which the program will begin executing. All Java applications begin execution
by calling main( ). (This is just like C/C++.) The exact meaning of each part of this line
cannot be given now, since it involves a detailed understanding of Java’s approach to
encapsulation. However, since most of the examples in the first part of this book will
use this line of code, let’s take a brief look at each part now.
The public keyword is an access specifier, which allows the programmer to control
the visibility of class members. When a class member is preceded by public, then that
member may be accessed by code outside the class in which it is declared. (The opposite
of public is private, which prevents a member from being used by code defined outside
of its class.) In this case, main( ) must be declared as public, since it must be called
by code outside of its class when the program is started. The keyword static allows
main( ) to be called without having to instantiate a particular instance of the class. This
is necessary since main( ) is called by the Java interpreter before any objects are made.
The keyword void simply tells the compiler that main( ) does not return a value. As
you will see, methods may also return values. If all this seems a bit confusing, don’t
worry. All of these concepts will be discussed in detail in subsequent chapters.
As stated, main( ) is the method called when a Java application begins. Keep in
mind that Java is case-sensitive. Thus, Main is different from main. It is important
to understand that the Java compiler will compile classes that do not contain a main( )
method. But the Java interpreter has no way to run these classes. So, if you had typed
Main instead of main, the compiler would still compile your program. However,
the Java interpreter would report an error because it would be unable to find the
main( ) method.
Any information that you need to pass to a method is received by variables specified
within the set of parentheses that follow the name of the method. These variables are
called parameters. If there are no parameters required for a given method, you still need
to include the empty parentheses. In main( ), there is only one parameter, albeit a
complicated one. String args[ ] declares a parameter named args, which is an array of
instances of the class String. (Arrays are collections of similar objects.) Objects of type
String store character strings. In this case, args receives any command-line arguments
present when the program is executed. This program does not make use of this
information, but other programs shown later in this book will.
The last character on the line is the {. This signals the start of main( )’s body. All of
the code that comprises a method will occur between the method’s opening curly brace
and its closing curly brace.
62 Java™ 2: The Complete Reference
you must allocate one using new and assign it to month_days. new is a special operator
that allocates memory.
You will look more closely at new in a later chapter, but you need to use it now to
allocate memory for arrays. The general form of new as it applies to one-dimensional
arrays appears as follows:
array-var = new type[size];
Here, type specifies the type of data being allocated, size specifies the number of elements
in the array, and array-var is the array variable that is linked to the array. That is, to use
new to allocate an array, you must specify the type and number of elements to allocate.
The elements in the array allocated by new will automatically be initialized to zero.
This example allocates a 12-element array of integers and links them to month_days.
month_days = new int[12];
After this statement executes, month_days will refer to an array of 12 integers. Further,
all elements in the array will be initialized to zero.
Let’s review: Obtaining an array is a two-step process. First, you must declare a
variable of the desired array type. Second, you must allocate the memory that will hold
the array, using new, and assign it to the array variable. Thus, in Java all arrays are
dynamically allocated. If the concept of dynamic allocation is unfamiliar to you, don’t
worry. It will be described at length later in this book.
Once you have allocated an array, you can access a specific element in the array by
specifying its index within square brackets. All array indexes start at zero. For example,
this statement assigns the value 28 to the second element of month_days.
month_days[1] = 28;
The next line displays the value stored at index 3.
System.out.println(month_days[3]);
Putting together all the pieces, here is a program that creates an array of the
number of days in each month.
// Demonstrate a one-dimensional array.
class Array {
THE JAVA LANGUAGE
Chapter 11: Multithreaded Programming 305
Suspending, Resuming, and Stopping Threads
Sometimes, suspending execution of a thread is useful. For example, a separate thread
can be used to display the time of day. If the user doesn’t want a clock, then its thread
can be suspended. Whatever the case, suspending a thread is a simple matter. Once
suspended, restarting the thread is also a simple matter.
The mechanisms to suspend, stop, and resume threads differ between Java 2 and
earlier versions. Although you should use the Java 2 approach for all new code, you
still need to understand how these operations were accomplished for earlier Java
environments. For example, you may need to update or maintain older, legacy code.
You also need to understand why a change was made for Java 2. For these reasons, the
next section describes the original way that the execution of a thread was controlled,
followed by a section that describes the approach required for Java 2.
Suspending, Resuming, and Stopping Threads Using
Java 1.1 and Earlier
Prior to Java 2, a program used suspend( ) and resume( ), which are methods defined by
Thread,topause and restart the execution of a thread. They have the form shown below:
final void suspend( )
final void resume( )
The following program demonstrates these methods:
// Using suspend() and resume().
class NewThread implements Runnable {
String name; // name of thread
Thread t;
NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
t.start(); // Start the thread
}
// This is the entry point for thread.
public void run() {
try {
for(int i = 15; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(200);
564 Java™ 2: The Complete Reference
Method
abstract void close( )
abstract void flush( )
void write(int ch)
void write(char buffer[ ])
abstract void write(char buffer[ ],
int offset,
int numChars)
void write(String str)
void write(String str, int offset,
int numChars)
Description
Closes the output stream. Further write
attempts will generate an IOException.
Finalizes the output state so that any
buffers are cleared. That is, it flushes the
output buffers.
Writes a single character to the invoking
output stream. Note that the parameter is
an int, which allows you to call write with
expressions without having to cast them
back to char.
Writes a complete array of characters to
the invoking output stream.
Writes a subrange of numChars characters
from the array buffer, beginning at
buffer[offset] to the invoking output stream.
Writes str to the invoking output stream.
Writes a subrange of numChars characters
from the array str, beginning at the
specified offset.
Table 17-4.
The Methods Defined by Writer
The following example shows how to read lines from a file and print these
to the standard output stream. It reads its own source file, which must be in the
current directory.
// Demonstrate FileReader.
import java.io.*;
class FileReaderDemo {
public static void main(String args[]) throws Exception {
FileReader fr = new FileReader("FileReaderDemo.java");
BufferedReader br = new BufferedReader(fr);
String s;
THE JAVA LANGUAGE
Chapter 3: Data Types, Variables, and Arrays 59
Conversion of int to byte.
i and b 257 1
Conversion of double to int.
d and i 323.142 323
Conversion of double to byte.
d and b 323.142 67
Let’s look at each conversion. When the value 257 is cast into a byte variable, the
result is the remainder of the division of 257 by 256 (the range of a byte), which is 1 in
this case. When the d is converted to an int, its fractional component is lost. When d is
converted to a byte, its fractional component is lost, and the value is reduced modulo
256, which in this case is 67.
Automatic Type Promotion in Expressions
In addition to assignments, there is another place where certain type conversions
may occur: in expressions. To see why, consider the following. In an expression, the
precision required of an intermediate value will sometimes exceed the range of either
operand. For example, examine the following expression:
byte a = 40;
byte b = 50;
byte c = 100;
int d = a * b / c;
The result of the intermediate term a * b easily exceeds the range of either of
its byte operands. To handle this kind of problem, Java automatically promotes each
byte or short operand to int when evaluating an expression. This means that the
subexpression a * b is performed using integers—not bytes. Thus, 2,000, the result of
the intermediate expression, 50 * 40, is legal even though a and b are both specified as
type byte.
As useful as the automatic promotions are, they can cause confusing compile-time
errors. For example, this seemingly correct code causes a problem:
byte b = 50;
b = b * 2; // Error! Cannot assign an int to a byte!
SOFTWARE DEVELOPMENT
USING JAVA
Chapter 27: Servlets 971
HttpSessionEvent defines one method, getSession( ), which is shown here:
HttpSession getSession( )
It returns the session in which the event occurred.
The HttpSessionBindingEvent Class
The HttpSessionBindingEvent class extends HttpSessionEvent. It is generated
when a listener is bound to or unbound from a value in an HttpSession object. It is
also generated when an attribute is bound or unbound. Here are its constructors:
HttpSessionBindingEvent(HttpSession session, String name)
HttpSessionBindingEvent(HttpSession session, String name, Object val)
Here, session is the source of the event and name is the name associated with the object
that is being bound or unbound. If an attribute is being bound or unbound, its value is
passed in val.
The getName( ) method obtains the name that is being bound or unbound. Its is
shown here:
String getName( )
The getSession( ) method, shown next, obtains the session to which the listener is
being bound or unbound:
HttpSession getSession( )
The getValue( ) method obtains the value of the attribute that is being bound or
unbound. It is shown here:
Object getValue( )
Handling HTTP Requests and Responses
The HttpServlet class provides specialized methods that handle the various types of
HTTP requests. A servlet developer typically overrides one of these methods. These
methods are doDelete( ), doGet( ), doHead( ), doOptions( ), doPost( ), doPut( ), and
doTrace( ). A complete description of the different types of HTTP requests is beyond
the scope of this book. However, the GET and POST requests are commonly used
when handling form input. Therefore, this section presents examples of these cases.
Handling HTTP GET Requests
Here we will develop a servlet that handles an HTTP GET request. The servlet is invoked
when a form on a Web page is submitted. The example contains two files. A Web page
THE JAVA LIBRARY
Chapter 24: New I/O, Regular Expressions, and Other Packages 857
public static void main(String args[]) {
RandomAccessFile fOut;
FileChannel fChan;
ByteBuffer mBuf;
try {
fOut = new RandomAccessFile("test.txt", "rw");
// Next, obtain a channel to that file.
fChan = fOut.getChannel();
// Then, map the file into a buffer.
mBuf = fChan.map(FileChannel.MapMode.READ_WRITE,
0, 26);
// Write some bytes to the buffer.
for(int i=0; i<26; i++)
mBuf.put((byte)('A' + i));
}
}
// close channel and file.
fChan.close();
fOut.close();
} catch (IOException exc) {
System.out.println(exc);
System.exit(1);
}
As you can see, there are no explicit write operations to the channel, itself. Because mBuf
is mapped to the file, changes to mBuf are automatically reflected in the underlying file.
Copying a File Using the New I/O
The new I/O system simplifies some types of file operations. For example, the
following program copies a file. It does so by opening an input channel to the source
file and an output channel to the target file. It then writes the mapped input buffer
to the output file in a single operation. You might want to compare this version of the
file copy program to the one found in Chapter 12. As you will find, the part of the
program that actually copies the file is substantially shorter.
// Copy a file using NIO.
THE JAVA LIBRARY
Chapter 14: Exploring java.lang 421
Method
static double pow(double y, double x)
static double sqrt(double arg)
Description
Returns y raised to the x; for example,
pow(2.0, 3.0) returns 8.0.
Returns the square root of arg.
Rounding Functions
The Math class defines several methods that provide various types of rounding
operations. They are shown in Table 14-15.
Method
static int abs(int arg)
static long abs(long arg)
static float abs(float arg)
static double abs(double arg)
Description
Returns the absolute value of arg.
Returns the absolute value of arg.
Returns the absolute value of arg.
Returns the absolute value of arg.
static double ceil(double arg)
Returns the smallest whole number greater
than or equal to arg.
static double floor(double arg) Returns the largest whole number less than
or equal to arg.
static int max(int x, int y) Returns the maximum of x and y.
static long max(long x, long y) Returns the maximum of x and y.
static float max(float x, float y) Returns the maximum of x and y.
static double max(double x, double y) Returns the maximum of x and y.
static int min(int x, int y)
Returns the minimum of x and y
static long min(long x, long y) Returns the minimum of x and y.
static float min(float x, float y) Returns the minimum of x and y.
static double min(double x, double y) Returns the minimum of x and y.
static double rint(double arg)
Returns the integer nearest in value to arg.
static int round(float arg)
Returns arg rounded up to the nearest int.
static long round(double arg) Returns arg rounded up to the nearest long.
Table 14-15.
The Rounding Methods Defined by Math
736 Java™ 2: The Complete Reference
This chapter continues our exploration of the Abstract Window Toolkit (AWT).
It examines the standard controls and layout managers defined by Java. It also
discusses menus and the menu bar. The chapter includes a discussion of two
high-level components: the dialog box and the file dialog box. It concludes with
another look at event handling.
Controls are components that allow a user to interact with your application in
various ways—for example, a commonly used control is the push button. A layout
manager automatically positions components within a container. Thus, the appearance
of a window is determined by a combination of the controls that it contains and the
layout manager used to position them.
In addition to the controls, a frame window can also include a standard-style menu bar.
Each entry in a menu bar activates a drop-down menu of options from which the user can
choose. A menu bar is always positioned at the top of a window. Although different in
appearance, menu bars are handled in much the same way as are the other controls.
While it is possible to manually position components within a window, doing so is
quite tedious. The layout manager automates this task. For the first part of this chapter,
which introduces the various controls, the default layout manager will be used. This
displays components in a container using left-to-right, top-to-bottom organization.
Once the controls have been covered, the layout managers will be examined. There
you will see how to better manage the positioning of your controls.
Control Fundamentals
The AWT supports the following types of controls:
■ Labels
■ Push buttons
■ Check boxes
■ Choice lists
■ Lists
■ Scroll bars
■ Text editing
These controls are subclasses of Component.
Adding and Removing Controls
To include a control in a window, you must add it to the window. To do this, you must
first create an instance of the desired control and then add it to a window by calling add( ),
768 Java™ 2: The Complete Reference
"Therefore all progress depends " +
"on the unreasonable man.\n\n" +
" - George Bernard Shaw\n\n";
}
}
add(new TextArea(msg), BorderLayout.CENTER);
Sample output from the BorderLayoutDemo applet is shown here:
Using Insets
Sometimes you will want to leave a small amount of space between the container
that holds your components and the window that contains it. To do this, override
the getInsets( ) method that is defined by Container. This function returns an Insets
object that contains the top, bottom, left, and right inset to be used when the container
is displayed. These values are used by the layout manager to inset the components
when it lays out the window. The constructor for Insets is shown here:
Insets(int top, int left, int bottom, int right)
The values passed in top, left, bottom, and right specify the amount of space between the
container and its enclosing window.
644 Java™ 2: The Complete Reference
NAME NAME is an optional attribute used to specify a name for the applet instance.
Applets must be named in order for other applets on the same page to find them by
name and communicate with them. To obtain an applet by name, use getApplet( ),
which is defined by the AppletContext interface.
WIDTH AND HEIGHT WIDTH and HEIGHT are required attributes that give the
size (in pixels) of the applet display area.
ALIGN ALIGN is an optional attribute that specifies the alignment of the applet.
This attribute is treated the same as the HTML IMG tag with these possible values:
LEFT, RIGHT, TOP, BOTTOM, MIDDLE, BASELINE, TEXTTOP, ABSMIDDLE,
and ABSBOTTOM.
VSPACE AND HSPACE These attributes are optional. VSPACE specifies the space,
in pixels, above and below the applet. HSPACE specifies the space, in pixels, on each
side of the applet. They’re treated the same as the IMG tag’s VSPACE and HSPACE
attributes.
PARAM NAME AND VALUE The PARAM tag allows you to specify appletspecific
arguments in an HTML page. Applets access their attributes with the
getParameter( ) method.
HANDLING OLDER BROWSERS Some very old web browsers can’t execute applets
and don’t recognize the APPLET tag. Although these browsers are now nearly extinct
(having been replaced by Java-compatible ones), you may need to deal with them
occasionally. The best way to design your HTML page to deal with such browsers is to
include HTML text and markup within your
tags. If the applet tags
are not recognized by your browser, you will see the alternate markup. If Java is
available, it will consume all of the markup between the
tags and
disregard the alternate markup.
Here’s the HTML to start an applet called SampleApplet in Java and to display a
message in older browsers:
Passing Parameters to Applets
As just discussed, the APPLET tag in HTML allows you to pass parameters to your
applet. To retrieve a parameter, use the getParameter( ) method. It returns the value of
THE JAVA LIBRARY
Chapter 16: java.util Part 2: More Utility Classes 515
Calendar defines the following int constants, which are used when you get or set
components of the calendar:
AM FRIDAY PM
AM_PM HOUR SATURDAY
APRIL HOUR_OF_DAY SECOND
AUGUST JANUARY SEPTEMBER
DATE JULY SUNDAY
DAY_OF_MONTH JUNE THURSDAY
DAY_OF_WEEK MARCH TUESDAY
DAY_OF_WEEK_IN_MONTH MAY UNDECIMBER
DAY_OF_YEAR MILLISECOND WEDNESDAY
DECEMBER MINUTE WEEK_OF_MONTH
DST_OFFSET MONDAY WEEK_OF_YEAR
ERA MONTH YEAR
FEBRUARY NOVEMBER ZONE_OFFSET
FIELD_COUNT
OCTOBER
Method
abstract void add(int which, int val)
boolean after(Object calendarObj)
boolean before(Object calendarObj)
Description
Adds val to the time or date
component specified by which. To
subtract, add a negative value. which
must be one of the fields defined by
Calendar, such as Calendar.HOUR.
Returns true if the invoking Calendar
object contains a date that is later
than the one specified by calendarObj.
Otherwise, it returns false.
Returns true if the invoking Calendar
object contains a date that is earlier
than the one specified by calendarObj.
Otherwise, it returns false.
Table 16-4.
Commonly Used Methods Defined by Calendar
80 Java™ 2: The Complete Reference
}
}
int d;
c = ++b;
d = a++;
c++;
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("c = " + c);
System.out.println("d = " + d);
The output of this program follows:
a = 2
b = 3
c = 4
d = 1
The Bitwise Operators
Java defines several bitwise operators which can be applied to the integer types, long,
int, short, char, and byte. These operators act upon the individual bits of their operands.
They are summarized in the following table:
Operator
Result
~ Bitwise unary NOT
&
Bitwise AND
| Bitwise OR
^
Bitwise exclusive OR
>> Shift right
>>> Shift right zero fill
<< Shift left
&=
Bitwise AND assignment
|= Bitwise OR assignment
THE JAVA LIBRARY
Chapter 23: Images 831
}
private int cont(int in) {
return (in < 128) ? (int)(in/gain) : multclamp(in, gain);
}
public int filterRGB(int x, int y, int rgb) {
int r = cont((rgb >> 16) & 0xff);
int g = cont((rgb >> 8) & 0xff);
int b = cont(rgb & 0xff);
return (0xff000000 | r << 16 | g << 8 | b);
}
Figure 23-10 shows the image after Contrast is pressed.
Convolver.java
The abstract class Convolver handles the basics of a convolution filter by implementing
the ImageConsumer interface to move the source pixels into an array called imgpixels.
It also creates a second array called newimgpixels for the filtered data. Convolution
filters sample a small rectangle of pixels around each pixel in an image, called the
Figure 23-10.
Using the Contrast filter with ImageFilterDemo
THE JAVA LIBRARY
Chapter 18: Networking 619
int fsp = request.indexOf(' ');
int nsp = request.indexOf(' ', fsp+1);
int eol = request.indexOf('\n');
String method = request.substring(0, fsp);
String url = request.substring(fsp+1, nsp);
String raw_mime_header = request.substring(eol + 1);
MimeHeader inmh = new MimeHeader(raw_mime_header);
request = request.substring(0, eol);
}
if (method.equalsIgnoreCase("get")) {
if (url.indexOf("://") >= 0) {
handleProxy(out, url, inmh);
} else {
handleGet(out, url, inmh);
}
} else {
writeString(out, error(405, "Method Not Allowed", method));
}
in.close();
out.close();
public void run() {
try {
ServerSocket acceptSocket;
acceptSocket = new ServerSocket(port);
while (true) {
Socket s = acceptSocket.accept();
host = s.getInetAddress().getHostName();
doRequest(s);
s.close();
}
} catch (IOException e) {
log.log("accept loop IOException: " + e + "\n");
} catch (Exception e) {
log.log("Exception: " + e);
}
}
private Thread t;
public synchronized void start() {
930 Java™ 2: The Complete Reference
Check Boxes
The JCheckBox class, which provides the functionality of a check box, is a concrete
implementation of AbstractButton. Its immediate superclass is JToggleButton, which
provides support for two-state buttons. Some of its constructors are shown here:
JCheckBox(Icon i)
JCheckBox(Icon i, boolean state)
JCheckBox(String s)
JCheckBox(String s, boolean state)
JCheckBox(String s, Icon i)
JCheckBox(String s, Icon i, boolean state)
Here, i is the icon for the button. The text is specified by s. If state is true, the check box
is initially selected. Otherwise, it is not.
The state of the check box can be changed via the following method:
void setSelected(boolean state)
Here, state is true if the check box should be checked.
The following example illustrates how to create an applet that displays four check
boxes and a text field. When a check box is pressed, its text is displayed in the text field.
The content pane for the JApplet object is obtained, and a flow layout is assigned as its
layout manager. Next, four check boxes are added to the content pane, and icons are
assigned for the normal, rollover, and selected states. The applet is then registered to
receive item events. Finally, a text field is added to the content pane.
When a check box is selected or deselected, an item event is generated. This is
handled by itemStateChanged( ). Inside itemStateChanged( ), the getItem( ) method
gets the JCheckBox object that generated the event. The getText( ) method gets the text
for that check box and uses it to set the text inside the text field.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/*
*/
public class JCheckBoxDemo extends JApplet
implements ItemListener {
JTextField jtf;
public void init() {
THE JAVA LIBRARY
Chapter 21: Introducing the AWT: Working with Windows, Graphics, and Text 697
Handling Events in a Frame Window
Since Frame is a subclass of Component, it inherits all the capabilities defined by
Component. This means that you can use and manage a frame window that you create
just like you manage your applet’s main window. For example, you can override
paint( ) to display output, call repaint( ) when you need to restore the window, and
override all event handlers. Whenever an event occurs in a window, the event handlers
defined by that window will be called. Each window handles its own events. For
example, the following program creates a window that responds to mouse events.
The main applet window also responds to mouse events. When you experiment
with this program, you will see that mouse events are sent to the window in which
the event occurs.
// Handle mouse events in both child and applet windows.
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
/*
*/
// Create a subclass of Frame.
class SampleFrame extends Frame
implements MouseListener, MouseMotionListener {
String msg = "";
int mouseX=10, mouseY=40;
int movX=0, movY=0;
894 Java™ 2: The Complete Reference
Updating an Existing JAR File
The following command adds the file file1.class to Xyz.jar:
jar -uf Xyz.jar file1.class
Recursing Directories
The following command adds all files below directoryX to Xyz.jar:
jar -uf Xyz.jar -C directoryX *
Introspection
Introspection is the process of analyzing a Bean to determine its capabilities. This is an
essential feature of the Java Beans API, because it allows an application builder tool to
present information about a component to a software designer. Without introspection,
the Java Beans technology could not operate.
There are two ways in which the developer of a Bean can indicate which of its
properties, events, and methods should be exposed by an application builder tool. With
the first method, simple naming conventions are used. These allow the introspection
mechanisms to infer information about a Bean. In the second way, an additional class is
provided that explicitly supplies this information. The first approach is examined here.
The second method is described later.
The following sections indicate the design patterns for properties and events that
enable the functionality of a Bean to be determined.
Design Patterns for Properties
A property is a subset of a Bean’s state. The values assigned to the properties determine
the behavior and appearance of that component. This section discusses three types of
properties: simple, Boolean, and indexed.
Simple Properties
A simple property has a single value. It can be identified by the following design
patterns, where N is the name of the property and T is its type.
public T getN( );
public void setN(T arg);
A read/write property has both of these methods to access its values. A read-only
property has only a get method. A write-only property has only a set method.
996 Java™ 2: The Complete Reference
}
// Return next integer in list.
int getNext() {
if(getIndex >= 100) {
cout << "List Underflow";
exit(1);
}
getIndex++;
return storage[getIndex-1];
}
// Put an integer on the list.
void putOnList(int i) {
if(putIndex < 100) {
storage[putIndex] = i;
putIndex++;
}
else {
cout << "List Overflow";
exit(1);
}
}
};
int main()
{
IntArray nums;
int i;
for(i=0; i<10; i++) nums.putOnList(i);
for(i=0; i<10; i++)
cout << nums.getNext() << endl;
return 0;
}
1154 Java™ 2: The Complete Reference
Trees, Swing, 941–946
TreeSet class, 449, 455, 456–457, 504
TreePath class, 942
trim( ), 365–366
trimToSize( ), 451
true, 39, 48, 51, 91
TRUE, 401
True and false in Java, 51, 91
try block(s), 250, 253–254
nested, 257–259
Two's complement, 81
TYPE, 382, 387, 398, 401, 402
Type
casting, 57–59, 60
checking, 42
conversion, automatic, 42,
57, 157–159
promotion, 44, 59–61
Types, data. See Data types
U
UDP protocol, 589, 591–592, 624
UnavailableException class, 955,
960
unhand( ) macro, 342
UnicastRemoteObject, 874
Unicode, 47, 48, 51, 315, 350, 356,
401, 562
Uniform Resource Identifier
(URI), 626
UNIX, 5, 588
UnknownHostException,
593, 595
unmodifiable, 475
unread( ), 558, 571
UnsupportedOperationException,
266, 442–443, 445, 463, 475
update( ), 527, 528, 638, 639, 705
overriding, 635
URI class, 592, 626
URL (Uniform Resource
Locator), 597
specification format, 597
URL class, 597–599, 601
URLConnection class, 599–601
User Datagram Protocol (UDP),
589, 591–592, 624
V
valueBound( ), 967
valueOf( ), 353, 366–367
values( ), 464
valueUnbound( ), 967
van Hoff, Arthur, 7
Variable(s), 52–56
declaration, 30–31, 52–53
definition of, 29, 52
dynamic initialization of, 53
final, 178–179
instance. See Instance
variables
interface, 236
object reference. See Object
reference variables
scope and lifetime of, 54–56
Vector class, 462, 485–490
methods, table of, 486–488
Virtual functions (C++), 213
Virtual machine, Java, 400
void, 28, 138
Void class, 401
volatile modifier, 291–292, 331, 332
VSPACE 644
W
wait( ), 221, 297–298, 300–302
waitFor( ), 407
Warth, Chris, 7
wc( ), 572–577
WeakHashMap class, 466, 467
Web browser
executing applet in, 330,
331, 628
handling older, 644
using status window of, 642
Web server and servlets, 950, 951
while loop, 109–111
Whitespace, 37
from string, removing, 365
whitespaceChars( ), 575
Whois, 596–597
WIDTH, 644
Window
displaying information in,
704–705
frame. See Frame window
fundamentals, 691–693
status, using, 642
Window class, 693, 783
windowActivated( ), 672
windowClosed( ), 672
windowClosing( ), 672, 694, 695
windowDeactivated( ), 672
windowDeiconified( ), 672
WindowEvent class, 658, 667–668
WindowFocusListener interface,
669, 672
windowGainedFocus( ), 672
windowIconified( ), 672
WindowListener interface, 669,
672, 694
windowLostFocus( ), 672
windowOpened( ), 672
Windows 3.1 and Java, 26
Windows 95/98 and Windows NT
and Java, 26
wordChars( ), 575
World Wide Web, 7, 8, 597
wrap( ), 850
Wrappers, simple type, 380–401
write( ), 315, 322–323, 326–328, 850,
855–856
Writer class, 315, 545, 562
methods defined by, table
of, 564
writeObject( ), 578
writeTo( ), 554
X
XOR (exclusive OR) operator (^)
bitwise, 80, 82, 83
Boolean, 92
Y
Yellin, Frank, 7
Z
Zero crossing, 81
ZIP file format, 536
ZLIB file format, 536
THE JAVA LIBRARY
Chapter 23: Images 837
Figure 23-12.
Using the Sharpen filter with ImageFilterDemo
Cell Animation
Now that we have presented an overview of the image APIs, we can put together
an interesting applet that will display a sequence of animation cells. The animation
cells are taken from a single image that can arrange the cells in a grid specified via
the rows and cols
tags. Each cell in the image is snipped out in a way similar
to that used in the TileImage example earlier. We obtain the sequence in which to
display the cells from the sequence
tag. This is a comma-separated list of
cell numbers that is zero-based and proceeds across the grid from left to right, top
to bottom.
Once the applet has parsed the
tags and loaded the source image, it cuts
the image into a number of small subimages. Then, a thread is started that causes the
images to be displayed according to the order described in sequence. The thread sleeps
for enough time to maintain the framerate. Here is the source code:
// Animation example.
import java.applet.*;
import java.awt.*;
THE JAVA LIBRARY
Chapter 14: Exploring java.lang 427
Method
int activeCount( )
int activeGroupCount( )
final void checkAccess( )
final void destroy( )
int enumerate(Thread group[ ])
int enumerate(Thread group[ ], boolean all)
int enumerate(ThreadGroup group[ ])
int enumerate(ThreadGroup group[ ],
boolean all)
final int getMaxPriority( )
Description
Returns the number of threads in
the group plus any groups for
which this thread is a parent.
Returns the number of groups
for which the invoking thread
is a parent.
Causes the security manager to
verify that the invoking thread
may access and/or change the
group on which checkAccess( )
is called.
Destroys the thread group
(and any child groups) on which
it is called.
The threads that comprise the
invoking thread group are put into
the group array.
The threads that comprise the
invoking thread group are put into
the group array. If all is true, then
threads in all subgroups of the
thread are also put into group.
The subgroups of the invoking
thread group are put into the
group array.
The subgroups of the invoking
thread group are put into the group
array. If all is true, then all
subgroups of the subgroups (and
so on) are also put into group.
Returns the maximum priority
setting for the group.
Table 14-17.
The Methods Defined by ThreadGroup
This page intentionally left blank.
THE JAVA LANGUAGE
Chapter 5: Control Statements 101
Here, if a is less than b, then a is set to zero. Otherwise, b is set to zero. In no case are
they both set to zero.
Most often, the expression used to control the if will involve the relational operators.
However, this is not technically necessary. It is possible to control the if using a single
boolean variable, as shown in this code fragment:
boolean dataAvailable;
// ...
if (dataAvailable)
ProcessData();
else
waitForMoreData();
Remember, only one statement can appear directly after the if or the else. If you
want to include more statements, you’ll need to create a block, as in this fragment:
int bytesAvailable;
// ...
if (bytesAvailable > 0) {
ProcessData();
bytesAvailable -= n;
} else
waitForMoreData();
Here, both statements within the if block will execute if bytesAvailable is greater
than zero.
Some programmers find it convenient to include the curly braces when using the if,
even when there is only one statement in each clause. This makes it easy to add another
statement at a later date, and you don’t have to worry about forgetting the braces. In
fact, forgetting to define a block when one is needed is a common cause of errors. For
example, consider the following code fragment:
int bytesAvailable;
// ...
if (bytesAvailable > 0) {
ProcessData();
bytesAvailable -= n;
} else
waitForMoreData();
bytesAvailable = n;
THE JAVA LANGUAGE
Chapter 12: I/O, Applets, and Other Topics 333
Here, object is an instance of a class, and type is a class type. If object is of the specified
type or can be cast into the specified type, then the instanceof operator evaluates to
true. Otherwise, its result is false. Thus, instanceof is the means by which your
program can obtain run-time type information about an object.
The following program demonstrates instanceof:
// Demonstrate instanceof operator.
class A {
int i, j;
}
class B {
int i, j;
}
class C extends A {
int k;
}
class D extends A {
int k;
}
class InstanceOf {
public static void main(String args[]) {
A a = new A();
B b = new B();
C c = new C();
D d = new D();
if(a instanceof A)
System.out.println("a is instance of A");
if(b instanceof B)
System.out.println("b is instance of B");
if(c instanceof C)
System.out.println("c is instance of C");
if(c instanceof A)
System.out.println("c can be cast to A");
if(a instanceof C)
System.out.println("a can be cast to C");
818 Java™ 2: The Complete Reference
Figure 23-5.
Sample output from MemoryImageGenerator
ImageProducer, described earlier. An object that implements the ImageConsumer
interface is going to create int or byte arrays that represent pixels from an Image
object. We will examine the PixelGrabber class, which is a simple implementation of
the ImageConsumer interface.
PixelGrabber
The PixelGrabber class is defined within java.lang.image. It is the inverse of the
MemoryImageSource class. Rather than constructing an image from an array of
pixel values, it takes an existing image and grabs the pixel array from it. To use
PixelGrabber, you first create an array of ints big enough to hold the pixel data, and
then you create a PixelGrabber instance passing in the rectangle that you want to grab.
Finally, you call grabPixels( ) on that instance.
The PixelGrabber constructor that is used in this chapter is shown here:
PixelGrabber(Image imgObj, int left, int top, int width, int height, int pixel[ ],
int offset, int scanLineWidth)
Here, imgObj is the object whose pixels are being grabbed. The values of left and top
specify the upper-left corner of the rectangle, and width and height specify the
404 Java™ 2: The Complete Reference
Method
void exit(int exitCode)
long freeMemory( )
void gc( )
static Runtime getRuntime( )
void halt(int code)
void load(String libraryFileName)
void loadLibrary(String libraryName)
boolean removeShutdownHook(Thread thrd)
void runFinalization( )
long totalMemory( )
void traceInstructions(boolean traceOn)
void traceMethodCalls(boolean traceOn)
Description
Halts execution and returns the value of
exitCode to the parent process. By
convention, 0 indicates normal
termination. All other values indicate
some form of error.
Returns the approximate number of bytes
of free memory available to the Java
run-time system.
Initiates garbage collection.
Returns the current Runtime object.
Immediately terminates the Java virtual
machine. No termination threads or
finalizers are run. The value of code is
returned to the invoking process.
(Added by Java 2, version 1.3)
Loads the dynamic library whose file is
specified by libraryFileName, which must
specify its complete path.
Loads the dynamic library whose name is
associated with libraryName.
Removes thrd from the list of threads
to run when the Java virtual machine
terminates. It returns true if
successful⎯that is, if the thread was
removed. (Added by Java 2, verison 1.3)
Initiates calls to the finalize( ) methods of
unused but not yet recycled objects.
Returns the total number of bytes of
memory available to the program.
Turns on or off instruction tracing,
depending upon the value of traceOn. If
traceOn is true, the trace is displayed. If it
is false, tracing is turned off.
Turns on or off method call tracing,
depending upon the value of traceOn. If
traceOn is true, the trace is displayed. If it
is false, tracing is turned off.
Table 14-10.
The Commonly Used Methods Defined by Runtime (continued)
920 Java™ 2: The Complete Reference
Figure 25-14.
The Bean Builder application executing
You can save your application by selecting Save in the file menu.
The Bean Builder is a powerful, yet easy to use development tool. If Bean
development is in your future, you will want to master its features. The best way
to do this is to create a number of sample Bean applications. Also, try creating your
own Beans and loading them into the palette. (To do so, create a JAR file containing
your Beans, as described earlier.)
THE JAVA LIBRARY
Chapter 16: java.util Part 2: More Utility Classes 533
void schedule(TimerTask TTask,
Date targetTime)
void schedule(TimerTask TTask,
Date targetTime,
long repeat)
void scheduleAtFixedRate(
TimerTask TTask,
long wait, long repeat)
void scheduleAtFixedRate(
TimerTask TTask,
Date targetTime,
long repeat)
TTask is scheduled for execution at the
time specified by targetTime.
TTask is scheduled for execution at the
time specified by targetTime. The task is
then executed repeatedly at the interval
passed in repeat. The repeat parameter is
specified in milliseconds.
TTask is scheduled for execution after
the period passed in wait has elapsed.
The task is then executed repeatedly at
the interval specified by repeat. Both wait
and repeat are specified in milliseconds.
The time of each repetition is relative to
the first execution, not the preceding
execution. Thus, the overall rate of
execution is fixed.
TTask is scheduled for execution at the
time specified by targetTime. The task is
then executed repeatedly at the interval
passed in repeat. The repeat parameter is
specified in milliseconds. The time of
each repetition is relative to the first
execution, not the preceding execution.
Thus, the overall rate of execution
is fixed.
Table 16-9.
The Methods Defined by Timer (continued)
Once a Timer has been created, you will schedule a task by calling schedule( )
on the Timer that you created. As Table 16-9 shows, there are several forms of
schedule( ) which allow you to schedule tasks in a variety of ways.
If you create a non-daemon task, then you will want to call cancel( ) to end the task
when your program ends. If you don’t do this, then your program may “hang” for a
period of time.
The following program demonstrates Timer and TimerTask. It defines a timer
task whose run( ) method displays the message “Timer task executed.” This task is
scheduled to run once very half second after an intial delay of one second.
602 Java™ 2: The Complete Reference
ServerSocket has a method called accept( ), which is a blocking call that will wait
for a client to initiate communications, and then return with a normal Socket that is
then used for communication with the client.
Java 2, version 1.4 added the getChannel( ) method to ServerSocket. This method
returns a channel connected to the ServerSocket object. Channels are used by the new
I/O classes contained in java.nio. (See Chapter 24.)
A Caching Proxy HTTP Server
In the remainder of this section, we will develop a simple caching proxy HTTP server,
called http, to demonstrate client and server sockets. http supports only GET
operations and a very limited range of hard-coded MIME types. (MIME types are the
type descriptors for multimedia content.) The proxy HTTP server is single threaded, in
that each request is handled in turn while all others wait. It has fairly naive strategies
for caching—it keeps everything in RAM forever. When it is acting as a proxy server,
http also copies every file it gets to a local cache for which it has no strategy for
refreshing or garbage collecting. All of these caveats aside, http represents a productive
example of client and server sockets, and it is fun to explore and easy to extend.
Source Code
The implementation of this HTTP server is presented here in five classes and one
interface. A more complete implementation would likely split many of the methods
out of the main class, httpd, in order to abstract more of the components. For space
considerations in this book, most of the functionality is in the single class, and the small
support classes are only acting as data structures. We will take a close look at each class
and method to examine how this server works, starting with the support classes and
ending with the main program.
MimeHeader.java
MIME is an Internet standard for communicating multimedia content over e-mail
systems. This standard was created by Nat Borenstein in 1992. The HTTP protocol uses
and extends the notion of MIME headers to pass general attribute/value pairs between
the HTTP client and server.
CONSTRUCTORS This class is a subclass of Hashtable so that it can conveniently
store and retrieve the key/value pairs associated with a MIME header. It has two
constructors. One creates a blank MimeHeader with no keys. The other takes a string
formatted as a MIME header and parses it for the initial contents of the object. See
parse( ) next.
parse( ) The parse( ) method is used to take a raw MIME-formatted string and enter
its key/value pairs into a given instance of MimeHeader. It uses a StringTokenizer to
split the input data into individual lines, marked by the CRLF (\r\n) sequence. It then
THE JAVA LIBRARY
Chapter 14: Exploring java.lang 395
Method
static long parseLong(String str)
throws NumberFormatException
static long parseLong(String str, int radix)
throws NumberFormatException
short shortValue( )
static String toBinaryString(long num)
static String toHexString(long num)
static String toOctalString(long num)
String toString( )
static String toString(long num)
static String toString(long num, int radix)
static Long valueOf(String str)
throws NumberFormatException
static Long valueOf(String str, int radix)
throws NumberFormatException
Description
Returns the long equivalent of
the number contained in the
string specified by str in radix 10.
Returns the long equivalent of
the number contained in the
string specified by str using the
specified radix.
Returns the value of the invoking
object as a short.
Returns a string that contains the
binary equivalent of num.
Returns a string that contains the
hexadecimal equivalent of num.
Returns a string that contains the
octal equivalent of num.
Returns a string that contains the
decimal equivalent of the
invoking object.
Returns a string that contains the
decimal equivalent of num.
Returns a string that contains the
decimal equivalent of num using
the specified radix.
Returns a Long object that
contains the value specified by
the string in str.
Returns a Long object that
contains the value specified by
the string in str using the
specified radix.
Table 14-6.
The Methods Defined by Long (continued)
Complete References
Herbert Schildt
0-07-213485-2
Jeffery R. Shapiro
0-07-213381-3
Chris H. Pappas & William
H. Murray, III
0-07-212958-1
Herbert Schildt
0-07-213084-9
Ron Ben-Natan & Ori Sasson
0-07-222394-4
Arthur Griffith
0-07-222405-3
For the answers to everything related to your technology, drill as deeply as you
please into our Complete Reference series. Written by topical authorities, these
comprehensive resources offer a full range of knowledge, including extensive product
information, theory, step-by-step tutorials, sample projects, and helpful appendixes.
For more information on these and other Osborne books, visit our Web site at www.osborne.com
904 Java™ 2: The Complete Reference
Here, the first argument is the name of the property, and the second argument is the
class of the Bean.
// A Bean information class.
package sunw.demo.colors;
import java.beans.*;
public class ColorsBeanInfo extends SimpleBeanInfo {
public PropertyDescriptor[] getPropertyDescriptors() {
try {
PropertyDescriptor rectangular = new
PropertyDescriptor("rectangular", Colors.class);
PropertyDescriptor pd[] = {rectangular};
return pd;
}
catch(Exception e) {
}
return null;
}
}
You must compile this file from the BDK\demo directory or set CLASSPATH so
that it includes c:\bdk\demo. If you don’t, the compiler won’t find the Colors.class
file properly. After this file is successfully compiled, the colors.mft file can be updated,
as shown here:
Name: sunw/demo/colors/ColorsBeanInfo.class
Name: sunw/demo/colors/Colors.class
Java-Bean: True
Use the JAR tool to create a new colors.jar file. Restart the BDK and create an
instance of the Colors Bean in the BeanBox.
The introspection facilities are designed to look for a BeanInfo class. If it exists,
its behavior explicitly determines the information that is presented to a Bean user.
Otherwise, design patterns are used to infer this information.
Figure 25-5 shows how the Properties window now appears. Compare it with
Figure 24-3. You can see that the properties inherited from Component are no longer
presented for the Colors Bean. Only the rectangular property appears.
Part IV
Applying Java
THE JAVA LIBRARY
Chapter 13: String Handling 363
lastIndexOf(t) = 65
indexOf(the) = 7
lastIndexOf(the) = 55
indexOf(t, 10) = 11
lastIndexOf(t, 60) = 55
indexOf(the, 10) = 44
lastIndexOf(the, 60) = 55
Modifying a String
Because String objects are immutable, whenever you want to modify a String, you
must either copy it into a StringBuffer or use one of the following String methods,
which will construct a new copy of the string with your modifications complete.
substring( )
You can extract a substring using substring( ). It has two forms. The first is
String substring(int startIndex)
Here, startIndex specifies the index at which the substring will begin. This form returns a
copy of the substring that begins at startIndex and runs to the end of the invoking string.
The second form of substring( ) allows you to specify both the beginning and
ending index of the substring:
String substring(int startIndex, int endIndex)
Here, startIndex specifies the beginning index, and endIndex specifies the stopping
point. The string returned contains all the characters from the beginning index, up to,
but not including, the ending index.
The following program uses substring( ) to replace all instances of one substring
with another within a string:
// Substring replacement.
class StringReplace {
public static void main(String args[]) {
String org = "This is a test. This is, too.";
String search = "is";
String sub = "was";
String result = "";
int i;
do { // replace all matching substrings
System.out.println(org);
976 Java™ 2: The Complete Reference
public class AddCookieServlet extends HttpServlet {
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Get parameter from HTTP request.
String data = request.getParameter("data");
// Create cookie.
Cookie cookie = new Cookie("MyCookie", data);
// Add cookie to HTTP response.
response.addCookie(cookie);
}
}
// Write output to browser.
response.setContentType("text/html");
PrintWriter pw = response.getWriter();
pw.println("MyCookie has been set to");
pw.println(data);
pw.close();
The source code for GetCookiesServlet.java is shown in the following listing. It
invokes the getCookies( ) method to read any cookies that are included in the HTTP
GET request. The names and values of these cookies are then written to the HTTP
response. Observe that the getName( ) and getValue( ) methods are called to obtain
this information.
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class GetCookiesServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Get cookies from header of HTTP request.
690 Java™ 2: The Complete Reference
Class
GraphicsEnvironment
GridBagConstraints
GridBagLayout
GridLayout
Image
Insets
Label
List
MediaTracker
Menu
MenuBar
MenuComponent
MenuItem
MenuShortcut
Panel
Point
Polygon
PopupMenu
PrintJob
Rectangle
Robot
Scrollbar
Description
Describes the collection of available Font and
GraphicsDevice objects.
Defines various constraints relating to the
GridBagLayout class.
The grid bag layout manager. Grid bag layout
displays components subject to the constraints
specified by GridBagConstraints.
The grid layout manager. Grid layout displays
components in a two-dimensional grid.
Encapsulates graphical images.
Encapsulates the borders of a container.
Creates a label that displays a string.
Creates a list from which the user can choose. Similar
to the standard Windows list box.
Manages media objects.
Creates a pull-down menu.
Creates a menu bar.
An abstract class implemented by various menu
classes.
Creates a menu item.
Encapsulates a keyboard shortcut for a menu item.
The simplest concrete subclass of Container.
Encapsulates a Cartesian coordinate pair, stored in x
and y.
Encapsulates a polygon.
Encapsulates a pop-up menu.
An abstract class that represents a print job.
Encapsulates a rectangle.
Supports automated testing of AWT- based applications.
(Added by Java 2, vl.3)
Creates a scroll bar control.
Table 21-1.
Some AWT Classes (continued)
1062 Java™ 2: The Complete Reference
column with rectangles in the Color of the appropriate pixel, using color( ). The bulb
image strip is then painted over the new column. Then the current scrolled position,
scrollX, is updated to be one more to the right, modulo the width, pixscan.
start( ), stop( ), and run( )
When the applet starts, it creates and starts a new Thread called t. This thread will call
run( ), which will keep calling paint( ) as fast as possible, while maintaining the courtesy
of calling yield( ) so that other threads can run. When the applet stop( ) method is
called, stopFlag is set to true. This variable is checked by the infinite loop in the run( )
method. Program control breaks from the loop when stopFlag is true.
A useful enhancement would be to introduce a threshold frame rate, say 30 fps (frames
per second), and change the call to the yield( ) into an appropriate call to sleep( ) if the
rendering is too fast.
The Code
Here is the source code for the Lavatron class:
import java.applet.*;
import java.awt.* ;
import java.awt.image.* ;
public class Lavatron extends Applet implements Runnable {
int scrollX;
int bulbsW, bulbsH;
int bulbS = 8;
Dimension d;
Image offscreen, bulb, img;
Graphics offgraphics;
int pixels[];
int pixscan;
IntHash clut = new IntHash();
boolean stopFlag;
public void init() {
d = getSize();
int offw = (int) Math.ceil(d.width/bulbS) * bulbS;
int offh = (int) Math.ceil(d.height/bulbS) * bulbS;
offscreen = createImage(offw, offh);
offgraphics = offscreen.getGraphics();
bulbsW = offw/bulbS;
bulbsH = offh/bulbS;
THE JAVA LIBRARY
Chapter 19: The Applet Class 637
A good place to set the foreground and background colors is in the init( ) method.
Of course, you can change these colors as often as necessary during the execution of
your applet. The default foreground color is black. The default background color is
light gray.
You can obtain the current settings for the background and foreground colors by
calling getBackground( ) and getForeground( ), respectively. They are also defined
by Component and are shown here:
Color getBackground( )
Color getForeground( )
Here is a very simple applet that sets the background color to cyan, the foreground
color to red, and displays a message that illustrates the order in which the init( ),
start( ), and paint( ) methods are called when an applet starts up:
/* A simple applet that sets the foreground and
background colors and outputs a string. */
import java.awt.*;
import java.applet.*;
/*
*/
public class Sample extends Applet{
String msg;
}
// set the foreground and background colors.
public void init() {
setBackground(Color.cyan);
setForeground(Color.red);
msg = "Inside init( ) --";
}
// Initialize the string to be displayed.
public void start() {
msg += " Inside start( ) --";
}
// Display msg in applet window.
public void paint(Graphics g) {
msg += " Inside paint( ).";
g.drawString(msg, 10, 30);
}
THE JAVA LIBRARY
Chapter 23: Images 835
}
}
}
}
rs << 16 | gs << 8 | bs);
Figure 23-11 shows the applet after Blur.
Sharpen.java
The Sharpen filter is also a subclass of Convolver and is (more or less) the inverse of
Blur. It runs through every pixel in the source image array, imgpixels, and computes
the average of the 3×3 box surrounding it, not counting the center. The corresponding
output pixel in newimgpixels has the difference between the center pixel and the
surrounding average added to it. This basically says that if a pixel is 30 brighter
than its surroundings, make it another 30 brighter. If, however, it is 10 darker, then
make it another 10 darker. This tends to accentuate edges while leaving smooth
areas unchanged.
Figure 23-11.
Using the Blur filter with ImageFilterDemo
THE JAVA LIBRARY
Chapter 21: Introducing the AWT: Working with Windows, Graphics, and Text 725
Method
int getDescent( )
Font getFont( )
int getHeight( )
Description
Returns the descent of the font.
Returns the font.
Returns the height of a line of text. This value
can be used to output multiple lines of text in
a window.
int getLeading( )
Returns the space between lines of text.
int getMaxAdvance( ) Returns the width of the widest character. –1
is returned if this value is not available.
int getMaxAscent( )
Returns the maximum ascent.
int getMaxDescent( )
Returns the maximum descent.
int[ ] getWidths( )
Returns the widths of the first 256 characters.
int stringWidth(String str) Returns the width of the string specified by str.
String toString( )
Returns the string equivalent of the
invoking object.
Table 21-3.
Some Methods Defined by FontMetrics (continued)
Displaying Multiple Lines of Text
Perhaps the most common use of FontMetrics is to determine the spacing between
lines of text. The second most common use is to determine the length of a string that is
being displayed. Here, you will see how to accomplish these tasks.
In general, to display multiple lines of text, your program must manually keep
track of the current output position. Each time a newline is desired, the Y coordinate
must be advanced to the beginning of the next line. Each time a string is displayed, the
X coordinate must be set to the point at which the string ends. This allows the next
string to be written so that it begins at the end of the preceding one.
To determine the spacing between lines, you can use the value returned by
getLeading( ). To determine the total height of the font, add the value returned by
getAscent( ) to the value returned by getDescent( ). You can then use these values to
position each line of text you output. However, in many cases, you will not need to use
these individual values. Often, all that you will need to know is the total height of a
line, which is the sum of the leading space and the font’s ascent and descent values.
The easiest way to obtain this value is to call getHeight( ). Simply increment the Y
662 Java™ 2: The Complete Reference
InputEvent defines several integer constants that represent any modifiers, such as
the control key being pressed, that might be associated with the event. Originally, the
InputEvent class defined the following eight values to represent the modifiers.
ALT_MASK BUTTON2_MASK META_MASK
ALT_GRAPH_MASK BUTTON3_MASK SHIFT_MASK
BUTTON1_MASK
CTRL_MASK
However, because of possible conflicts between the modifiers used by keyboard events
and mouse events, and other issues, Java 2, version 1.4 added the following extended
modifier values.
ALT_DOWN_MASK ALT_GRAPH_DOWN_MASK BUTTON1_DOWN_MASK
BUTTON2_DOWN_MASK BUTTON3_DOWN_MASK CTRL_DOWN_MASK
META_DOWN_MASK SHIFT_DOWN_MASK
When writing new code, it is recommended that you use the new, extended modifiers
rather than the original modifiers.
To test if a modifier was pressed at the time an event is generated, use the
isAltDown( ), isAltGraphDown( ), isControlDown( ), isMetaDown( ), and
isShiftDown( ) methods. The forms of these methods are shown here:
boolean isAltDown( )
boolean isAltGraphDown( )
boolean isControlDown( )
boolean isMetaDown( )
boolean isShiftDown( )
You can obtain a value that contains all of the original modifier flags by calling
the getModifiers( ) method. It is shown here:
int getModifiers( )
You can obtain the extended modifiers by called getModifiersEx( ), which is shown here.
int getModifiersEx( )
This method was also added by Java 2, version 1.4.
The ItemEvent Class
An ItemEvent is generated when a check box or a list item is clicked or when a checkable
menu item is selected or deselected. (Check boxes and list boxes are described later in this
book.) There are two types of item events, which are identified by the following integer
constants:
THE JAVA LANGUAGE
Chapter 4: Operators 91
Operator Result
< Less than
>= Greater than or equal to
<= Less than or equal to
The outcome of these operations is a boolean value. The relational operators are
most frequently used in the expressions that control the if statement and the various
loop statements.
Any type in Java, including integers, floating-point numbers, characters, and Booleans
can be compared using the equality test, ==, and the inequality test, !=. Notice that in
Java (as in C/C++/C#) equality is denoted with two equal signs, not one. (Remember:
a single equal sign is the assignment operator.) Only numeric types can be compared
using the ordering operators. That is, only integer, floating-point, and character operands
may be compared to see which is greater or less than the other.
As stated, the result produced by a relational operator is a boolean value. For
example, the following code fragment is perfectly valid:
int a = 4;
int b = 1;
boolean c = a < b;
In this case, the result of a
If you are coming from a C/C++ background, please note the following. In C/C++,
these types of statements are very common:
int done;
// ...
if(!done) ... // Valid in C/C++
if(done) ... // but not in Java.
In Java, these statements must be written like this:
if(done == 0)) ... // This is Java-style.
if(done != 0) ...
The reason is that Java does not define true and false in the same way as C/C++.
In C/C++, true is any nonzero value and false is zero. In Java, true and false are
nonnumeric values which do not relate to zero or nonzero. Therefore, to test for zero
or nonzero, you must explicitly employ one or more of the relational operators.
THE JAVA LANGUAGE
Chapter 8: Inheritance 217
// A Simple demonstration of abstract.
abstract class A {
abstract void callme();
}
// concrete methods are still allowed in abstract classes
void callmetoo() {
System.out.println("This is a concrete method.");
}
class B extends A {
void callme() {
System.out.println("B's implementation of callme.");
}
}
class AbstractDemo {
public static void main(String args[]) {
B b = new B();
}
}
b.callme();
b.callmetoo();
Notice that no objects of class A are declared in the program. As mentioned, it is
not possible to instantiate an abstract class. One other point: class A implements a
concrete method called callmetoo( ). This is perfectly acceptable. Abstract classes can
include as much implementation as they see fit.
Although abstract classes cannot be used to instantiate objects, they can be used
to create object references, because Java’s approach to run-time polymorphism is
implemented through the use of superclass references. Thus, it must be possible to
create a reference to an abstract class so that it can be used to point to a subclass object.
You will see this feature put to use in the next example.
Using an abstract class, you can improve the Figure class shown earlier. Since
there is no meaningful concept of area for an undefined two-dimensional figure, the
following version of the program declares area( ) as abstract inside Figure. This, of
course, means that all classes derived from Figure must override area( ).
// Using abstract methods and classes.
abstract class Figure {
122 Java™ 2: The Complete Reference
This program generates the following output:
Pass 0: 0 1 2 3 4 5 6 7 8 9
Pass 1: 0 1 2 3 4 5 6 7 8 9
Pass 2: 0 1 2 3 4 5 6 7 8 9
Loops complete.
As you can see, the break statement in the inner loop only causes termination of that
loop. The outer loop is unaffected.
Here are two other points to remember about break. First, more than one break
statement may appear in a loop. However, be careful. Too many break statements have
the tendency to destructure your code. Second, the break that terminates a switch
statement affects only that switch statement and not any enclosing loops.
break was not designed to provide the normal means by which a loop is terminated. The
loop’s conditional expression serves this purpose. The break statement should be used to
cancel a loop only when some sort of special situation occurs.
Using break as a Form of Goto
In addition to its uses with the switch statement and loops, the break statement can also
be employed by itself to provide a “civilized” form of the goto statement. Java does
not have a goto statement, because it provides a way to branch in an arbitrary and
unstructured manner. This usually makes goto-ridden code hard to understand and
hard to maintain. It also prohibits certain compiler optimizations. There are, however,
a few places where the goto is a valuable and legitimate construct for flow control. For
example, the goto can be useful when you are exiting from a deeply nested set of loops.
To handle such situations, Java defines an expanded form of the break statement. By
using this form of break, you can break out of one or more blocks of code. These blocks
need not be part of a loop or a switch. They can be any block. Further, you can specify
precisely where execution will resume, because this form of break works with a label.
As you will see, break gives you the benefits of a goto without its problems.
The general form of the labeled break statement is shown here:
break label;
Here, label is the name of a label that identifies a block of code. When this form of break
executes, control is transferred out of the named block of code. The labeled block of
code must enclose the break statement, but it does not need to be the immediately
enclosing block. This means that you can use a labeled break statement to exit from a
set of nested blocks. But you cannot use break to transfer control to a block of code that
does not enclose the break statement.
88 Java™ 2: The Complete Reference
sometimes this is undesirable. For example, if you are shifting something that does
not represent a numeric value, you may not want sign extension to take place. This
situation is common when you are working with pixel-based values and graphics. In
these cases you will generally want to shift a zero into the high-order bit no matter
what its initial value was. This is known as an unsigned shift. To accomplish this, you
will use Java’s unsigned, shift-right operator, >>>, which always shifts zeros into the
high-order bit.
The following code fragment demonstrates the >>>. Here, a is set to –1, which sets
all 32 bits to 1 in binary. This value is then shifted right 24 bits, filling the top 24 bits
with zeros, ignoring normal sign extension. This sets a to 255.
int a = -1;
a = a >>> 24;
Here is the same operation in binary form to further illustrate what is happening:
11111111 11111111 11111111 11111111 –1 in binary as an int
>>>24
00000000 00000000 00000000 11111111 255 in binary as an int
The >>> operator is often not as useful as you might like, since it is only meaningful
for 32- and 64-bit values. Remember, smaller values are automatically promoted to int
in expressions. This means that sign-extension occurs and that the shift will take place
on a 32-bit rather than on an 8- or 16-bit value. That is, one might expect an unsigned
right shift on a byte value to zero-fill beginning at bit 7. But this is not the case, since
it is a 32-bit value that is actually being shifted. The following program demonstrates
this effect:
// Unsigned shifting a byte value.
class ByteUShift {
static public void main(String args[]) {
char hex[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
byte b = (byte) 0xf1;
byte c = (byte) (b >> 4);
byte d = (byte) (b >>> 4);
byte e = (byte) ((b & 0xff) >> 4);
184 Java™ 2: The Complete Reference
}
void test() {
for(int i=0; i<10; i++) {
class Inner {
void display() {
System.out.println("display: outer_x = " + outer_x);
}
}
Inner inner = new Inner();
inner.display();
}
}
class InnerClassDemo {
public static void main(String args[]) {
Outer outer = new Outer();
outer.test();
}
}
The output from this version of the program is shown here.
display: outer_x = 100
display: outer_x = 100
display: outer_x = 100
display: outer_x = 100
display: outer_x = 100
display: outer_x = 100
display: outer_x = 100
display: outer_x = 100
display: outer_x = 100
display: outer_x = 100
While nested classes are not used in most day-to-day programming, they are
particularly helpful when handling events in an applet. We will return to the topic
of nested classes in Chapter 20. There you will see how inner classes can be used to
simplify the code needed to handle certain types of events. You will also learn about
anonymous inner classes, which are inner classes that don't have a name.
One final point: Nested classes were not allowed by the original 1.0 specification for
Java. They were added by Java 1.1.
70 Java™ 2: The Complete Reference
0 0 0 0 0
0 1 2 3 4
0 2 4 6 8
0 3 6 9 12
0 0 0 0 0
0 2 4 6 8
0 4 8 12 16
0 6 12 18 24
Alternative Array Declaration Syntax
There is a second form that may be used to declare an array:
type[ ] var-name;
Here, the square brackets follow the type specifier, and not the name of the array
variable. For example, the following two declarations are equivalent:
int al[] = new int[3];
int[] a2 = new int[3];
The following declarations are also equivalent:
char twod1[][] = new char[3][4];
char[][] twod2 = new char[3][4];
This alternative declaration form is included as a convenience, and is also useful when
specifying an array as a return type for a method.
A Few Words About Strings
As you may have noticed, in the preceding discussion of data types and arrays there
has been no mention of strings or a string data type. This is not because Java does not
support such a type—it does. It is just that Java’s string type, called String, isnota
simple type. Nor is it simply an array of characters (as are strings in C/C++). Rather,
String defines an object, and a full description of it requires an understanding of several
object-related features. As such, it will be covered later in this book, after objects are
described. However, so that you can use simple strings in example programs, the
following brief introduction is in order.
The String type is used to declare string variables. You can also declare arrays of
strings. A quoted string constant can be assigned to a String variable. A variable
556 Java™ 2: The Complete Reference
Buffering an input stream also provides the foundation required to support moving
backward in the stream of the available buffer. Beyond the read( ) and skip( ) methods
implemented in any InputStream, BufferedInputStream also supports the mark( ) and
reset( ) methods. This support is reflected by BufferedInputStream.markSupported( )
returning true.
The following example contrives a situation where we can use mark( ) to remember
where we are in an input stream and later use reset( ) to get back there. This example is
parsing a stream for the HTML entity reference for the copyright symbol. Such a
reference begins with an ampersand (&) and ends with a semicolon (;) without any
intervening whitespace. The sample input has two ampersands to show the case where
the reset( ) happens and where it does not.
// Use buffered input.
import java.io.*;
class BufferedInputStreamDemo {
public static void main(String args[]) throws IOException {
String s = "This is a © copyright symbol " +
"but this is © not.\n";
byte buf[] = s.getBytes();
ByteArrayInputStream in = new ByteArrayInputStream(buf);
BufferedInputStream f = new BufferedInputStream(in);
int c;
boolean marked = false;
while ((c = f.read()) != -1) {
switch(c) {
case '&':
if (!marked) {
f.mark(32);
marked = true;
} else {
marked = false;
}
break;
case ';':
if (marked) {
marked = false;
System.out.print("(c)");
} else
System.out.print((char) c);
break;
THE JAVA LANGUAGE
Chapter 5: Control Statements 103
statement;
else if(condition)
statement;
.
.
.
else
statement;
The if statements are executed from the top down. As soon as one of the conditions
controlling the if is true, the statement associated with that if is executed, and the rest
of the ladder is bypassed. If none of the conditions is true, then the final else statement
will be executed. The final else acts as a default condition; that is, if all other conditional
tests fail, then the last else statement is performed. If there is no final else and all other
conditions are false, then no action will take place.
Here is a program that uses an if-else-if ladder to determine which season a particular
month is in.
// Demonstrate if-else-if statements.
class IfElse {
public static void main(String args[]) {
int month = 4; // April
String season;
if(month == 12 || month == 1 || month == 2)
season = "Winter";
else if(month == 3 || month == 4 || month == 5)
season = "Spring";
else if(month == 6 || month == 7 || month == 8)
season = "Summer";
else if(month == 9 || month == 10 || month == 11)
season = "Autumn";
else
season = "Bogus Month";
}
}
System.out.println("April is in the " + season + ".");
Here is the output produced by the program:
April is in the Spring.
352 Java™ 2: The Complete Reference
String Concatenation
In general, Java does not allow operators to be applied to String objects. The one
exception to this rule is the + operator, which concatenates two strings, producing a
String object as the result. This allows you to chain together a series of + operations.
For example, the following fragment concatenates three strings:
String age = "9";
String s = "He is " + age + " years old.";
System.out.println(s);
This displays the string “He is 9 years old.”
One practical use of string concatenation is found when you are creating very long
strings. Instead of letting long strings wrap around within your source code, you can
break them into smaller pieces, using the + to concatenate them. Here is an example:
// Using concatenation to prevent long lines.
class ConCat {
public static void main(String args[]) {
String longStr = "This could have been " +
"a very long line that would have " +
"wrapped around. But string concatenation " +
"prevents this.";
}
}
System.out.println(longStr);
String Concatenation with Other Data Types
You can concatenate strings with other types of data. For example, consider this
slightly different version of the earlier example:
int age = 9;
String s = "He is " + age + " years old.";
System.out.println(s);
In this case, age is an int rather than another String, but the output produced is the
same as before. This is because the int value in age is automatically converted into its
string representation within a String object. This string is then concatenated as before.
The compiler will convert an operand to its string equivalent whenever the other
operand of the + is an instance of String.
960 Java™ 2: The Complete Reference
The GenericServlet Class
The GenericServlet class provides implementations of the basic life cycle methods for
a servlet and is typically subclassed by servlet developers. GenericServlet implements
the Servlet and ServletConfig interfaces. In addition, a method to append a string to
the server log file is available. The signatures of this method are shown here:
void log(String s)
void log(String s, Throwable e)
Here, s is the string to be appended to the log, and e is an exception that occurred.
The ServletInputStream Class
The ServletInputStream class extends InputStream. It is implemented by the server
and provides an input stream that a servlet developer can use to read the data from a
client request. It defines the default constructor. In addition, a method is provided to
read bytes from the stream. Its signature is shown here:
int readLine(byte[ ] buffer, int offset, int size) throws IOException
Here, buffer is the array into which size bytes are placed starting at offset. The method
returns the actual number of bytes read or –1 if an end-of-stream condition is encountered.
The ServletOutputStream Class
The ServletOutputStream class extends OutputStream. It is implemented by the
server and provides an output stream that a servlet developer can use to write data
to a client response. A default constructor is defined. It also defines the print( ) and
println( ) methods, which output data to the stream.
The Servlet Exception Classes
javax.servlet defines two exceptions. The first is ServletException, which indicates that
a servlet problem has occurred. The second is UnavailableException, which extends
ServletException. It indicates that a servlet is unavailable.
Reading Servlet Parameters
The ServletRequest class includes methods that allow you to read the names and
values of parameters that are included in a client request. We will develop a servlet
that illustrates their use. The example contains two files. A Web page is defined in
PostParameters.htm and a servlet is defined in PostParametersServlet.java.
The HTML source code for PostParameters.htm is shown in the following listing. It
defines a table that contains two labels and two text fields. One of the labels is Employee
THE JAVA LANGUAGE
Chapter 1: The Genesis of Java 5
Prior to C, programmers usually had to choose between languages that optimized
one set of traits or the other. For example, although FORTRAN could be used to write
fairly efficient programs for scientific applications, it was not very good for systems
code. And while BASIC was easy to learn, it wasn’t very powerful, and its lack of
structure made its usefulness questionable for large programs. Assembly language
can be used to produce highly efficient programs, but it is not easy to learn or use
effectively. Further, debugging assembly code can be quite difficult.
Another compounding problem was that early computer languages such as BASIC,
COBOL, and FORTRAN were not designed around structured principles. Instead, they
relied upon the GOTO as a primary means of program control. As a result, programs
written using these languages tended to produce “spaghetti code”—a mass of tangled
jumps and conditional branches that make a program virtually impossible to
understand. While languages like Pascal are structured, they were not designed for
efficiency, and failed to include certain features necessary to make them applicable to
a wide range of programs. (Specifically, given the standard dialects of Pascal available
at the time, it was not practical to consider using Pascal for systems-level code.)
So, just prior to the invention of C, no one language had reconciled the conflicting
attributes that had dogged earlier efforts. Yet the need for such a language was
pressing. By the early 1970s, the computer revolution was beginning to take hold, and
the demand for software was rapidly outpacing programmers’ ability to produce it.
A great deal of effort was being expended in academic circles in an attempt to create a
better computer language. But, and perhaps most importantly, a secondary force was
beginning to be felt. Computer hardware was finally becoming common enough that a
critical mass was being reached. No longer were computers kept behind locked doors.
For the first time, programmers were gaining virtually unlimited access to their
machines. This allowed the freedom to experiment. It also allowed programmers to
begin to create their own tools. On the eve of C’s creation, the stage was set for a
quantum leap forward in computer languages.
Invented and first implemented by Dennis Ritchie on a DEC PDP-11 running the
UNIX operating system, C was the result of a development process that started with
an older language called BCPL, developed by Martin Richards. BCPL influenced a
language called B, invented by Ken Thompson, which led to the development of C
in the 1970s. For many years, the de facto standard for C was the one supplied with
the UNIX operating system and described in The C Programming Language by Brian
Kernighan and Dennis Ritchie (Prentice-Hall, 1978). C was formally standardized in
December 1989, when the American National Standards Institute (ANSI) standard for
C was adopted.
The creation of C is considered by many to have marked the beginning of the
modern age of computer languages. It successfully synthesized the conflicting
attributes that had so troubled earlier languages. The result was a powerful, efficient,
structured language that was relatively easy to learn. It also included one other, nearly
intangible aspect: it was a programmer’s language. Prior to the invention of C, computer
languages were generally designed either as academic exercises or by bureaucratic
committees. C is different. It was designed, implemented, and developed by real,
THE JAVA LIBRARY
Chapter 14: Exploring java.lang 401
Java 2, version 1.4 adds a method called getDirectionality( ) which can be used to
determine the direction of a character. Several new constants have been added which
describe directionality. Most programs will not need to use character directionality.
Character also defines the equals( ) and hashCode( ) methods.
Two other character-related classes are Character.Subset, used to describe a subset
of Unicode, and Character.UnicodeBlock, which contains Unicode character blocks.
Boolean
Boolean is a very thin wrapper around boolean values, which is useful mostly when
you want to pass a boolean variable by reference. It contains the constants TRUE and
FALSE, which define true and false Boolean objects. Boolean also defines the TYPE
field, which is the Class object for boolean. Boolean defines these constructors:
Boolean(boolean boolValue)
Boolean(String boolString)
In the first version, boolValue must be either true or false. In the second version, if
boolString contains the string “true” (in uppercase or lowercase), then the new Boolean
object will be true. Otherwise, it will be false.
Boolean defines the methods shown in Table 14-8.
Method
boolean booleanValue( )
boolean equals(Object boolObj)
static boolean
getBoolean(String propertyName)
int hashCode( )
String toString( )
static String toString(boolean boolVal)
static Boolean valueOf(boolean boolVal)
static Boolean valueOf(String boolString)
Description
Returns boolean equivalent.
Returns true if the invoking object is equivalent
to boolObj. Otherwise, it returns false.
Returns true if the system property specified
by propertyName is true. Otherwise, it returns
false.
Returns the hash code for the invoking object.
Returns the string equivalent of the invoking
object.
Returns the string equivalent of boolVal.
(Added by Java 2, version 1.4)
Returns the Boolean equivalent of boolVal.
(Added by Java 2, version 1.4)
Returns true if boolString contains the string
“true” (in uppercase or lowercase).
Otherwise, it returns false.
Table 14-8.
The Methods Defined by Boolean
922 Java™ 2: The Complete Reference
In Part II, you saw how to build user interfaces with the AWT classes. Here, we will
take a tour of a supercharged alternative called Swing. Swing is a set of classes that
provides more powerful and flexible components than are possible with the AWT.
In addition to the familiar components, such as buttons, check boxes, and labels, Swing
supplies several exciting additions, including tabbed panes, scroll panes, trees, and
tables. Even familiar components such as buttons have more capabilities in Swing. For
example, a button may have both an image and a text string associated with it. Also,
the image can be changed as the state of the button changes.
Unlike AWT components, Swing components are not implemented by
platform-specific code. Instead, they are written entirely in Java and, therefore, are
platform-independent. The term lightweight is used to describe such elements.
The number of classes and interfaces in the Swing packages is substantial, and this
chapter provides an overview of just a few. Swing is an area that you will want to
explore further on your own.
The Swing component classes that are used in this book are shown here:
Class
AbstractButton
ButtonGroup
ImageIcon
JApplet
JButton
JCheckBox
JComboBox
JLabel
JRadioButton
JScrollPane
JTabbedPane
JTable
JTextField
JTree
Description
Abstract superclass for Swing buttons.
Encapsulates a mutually exclusive set of buttons.
Encapsulates an icon.
The Swing version of Applet.
The Swing push button class.
The Swing check box class.
Encapsulates a combo box (an combination of a
drop-down list and text field).
The Swing version of a label.
The Swing version of a radio button.
Encapsulates a scrollable window.
Encapsulates a tabbed window.
Encapsulates a table-based control.
The Swing version of a text field.
Encapsulates a tree-based control.
THE JAVA LANGUAGE
Chapter 12: I/O, Applets, and Other Topics 315
Byte Streams and Character Streams
Java 2 defines two types of streams: byte and character. Byte streams provide a
convenient means for handling input and output of bytes. Byte streams are used, for
example, when reading or writing binary data. Character streams provide a convenient
means for handling input and output of characters. They use Unicode and, therefore,
can be internationalized. Also, in some cases, character streams are more efficient than
byte streams.
The original version of Java (Java 1.0) did not include character streams and, thus,
all I/O was byte-oriented. Character streams were added by Java 1.1, and certain
byte-oriented classes and methods were deprecated. This is why older code that
doesn’t use character streams should be updated to take advantage of them, where
appropriate.
One other point: at the lowest level, all I/O is still byte-oriented. The
character-based streams simply provide a convenient and efficient means for handling
characters.
An overview of both byte-oriented streams and character-oriented streams is
presented in the following sections.
The Byte Stream Classes
Byte streams are defined by using two class hierarchies. At the top are two abstract
classes: InputStream and OutputStream. Each of these abstract classes has several
concrete subclasses, that handle the differences between various devices, such as disk
files, network connections, and even memory buffers. The byte stream classes are
shown in Table 12-1. A few of these classes are discussed later in this section. Others
are described in Part II. Remember, to use the stream classes, you must import java.io.
The abstract classes InputStream and OutputStream define several key methods
that the other stream classes implement. Two of the most important are read( ) and
write( ), which, respectively, read and write bytes of data. Both methods are declared
as abstract inside InputStream and OutputStream. They are overridden by derived
stream classes.
The Character Stream Classes
Character streams are defined by using two class hierarchies. At the top are two
abstract classes, Reader and Writer. These abstract classes handle Unicode character
streams. Java has several concrete subclasses of each of these. The character stream
classes are shown in Table 12-2.
The abstract classes Reader and Writer define several key methods that the other
stream classes implement. Two of the most important methods are read( ) and write( ),
which read and write characters of data, respectively. These methods are overridden
by derived stream classes.
THE JAVA LIBRARY
Chapter 22: Using AWT Controls, Layout Managers, and Menus 771
Here is a sample program that creates a 4×4 grid and fills it in with 15 buttons, each
labeled with its index:
// Demonstrate GridLayout
import java.awt.*;
import java.applet.*;
/*
*/
public class GridLayoutDemo extends Applet {
static final int n = 4;
public void init() {
setLayout(new GridLayout(n, n));
setFont(new Font("SansSerif", Font.BOLD, 24));
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
int k = i * n + j;
if(k > 0)
add(new Button("" + k));
}
}
Following is the output generated by the GridLayoutDemo applet:
572 Java™ 2: The Complete Reference
}
}
while ((c = f.read()) != -1) {
switch(c) {
case '=':
if ((c = f.read()) == '=')
System.out.print(".eq.");
else {
System.out.print("<-");
f.unread(c);
}
break;
default:
System.out.print((char) c);
break;
}
}
PrintWriter
PrintWriter is essentially a character-oriented version of PrintStream. It provides the
formatted output methods print( ) and println( ). PrintWriter has four constructors:
PrintWriter(OutputStream outputStream)
PrintWriter(OutputStream outputStream, boolean flushOnNewline)
PrintWriter(Writer outputStream)
PrintWriter(Writer outputStream, boolean flushOnNewline)
where flushOnNewline controls whether Java flushes the output stream every time
println( ) is called. If flushOnNewline is true, flushing automatically takes place. If false,
flushing is not automatic. The first and third constructors do not automatically flush.
Java’s PrintWriter objects support the print( ) and println( ) methods for all types,
including Object. If an argument is not a simple type, the PrintWriter methods will call
the object’s toString( ) method and then print out the result.
Using Stream I/O
The following example demonstrates several of Java’s I/O character stream classes and
methods. This program implements the standard wc (word count) command. The
program has two modes: if no filenames are provided as arguments, the program
SOFTWARE DEVELOPMENT
USING JAVA
Chapter 28: Migrating from C++ to Java 1001
Converting C++ Multiple-Inheritance
Hierarchies
C++ allows one class to inherit two or more base classes at the same time. Java does
not. To understand the difference, consider the two hierarchies depicted here:
In both cases, subclass C inherits classes A and B. However, in the hierarchy on the left,
C inherits both A and B at the same time. In the one on the right, B inherits A, and C
inherits B. By not allowing the inheritance of multiple base classes by a single subclass,
Java greatly simplifies the inheritance model. Multiple inheritance carries with it
several special cases that must be handled. This adds overhead to both the compiler
and the run-time system, while providing only marginal benefit for the programmer.
Since C++ supports multiple inheritance and Java does not, you may have to deal
with this issue when porting C++ applications to Java. While every situation is
different, two general pieces of advice can be offered. First, in many cases, multiple
inheritance is employed in a C++ program when there is actually no need to do so.
When this is the case, just convert the class structure to a single-inheritance hierarchy.
For example, consider this C++ class hierarchy that defines a class called House:
class Foundation {
// ...
};
class Walls {
// ...
};
class Rooms {
// ...
};
class House : public Foundation, Walls, Rooms {
// ...
};
THE JAVA LANGUAGE
Chapter 12: I/O, Applets, and Other Topics 331
}
}
g.drawString("A Simple Applet", 20, 20);
In general, you can quickly iterate through applet development by using these
three steps:
1. Edit a Java source file.
2. Compile your program.
3. Execute the applet viewer, specifying the name of your applet’s source file. The
applet viewer will encounter the APPLET tag within the comment and execute
your applet.
The window produced by SimpleApplet, as displayed by the applet viewer, is
shown in the following illustration:
While the subject of applets is more fully discussed later in this book, here are the
key points that you should remember now:
■ Applets do not need a main( ) method.
■ Applets must be run under an applet viewer or a Java-compatible browser.
■ User I/O is not accomplished with Java’s stream I/O classes. Instead, applets
use the interface provided by the AWT.
The transient and volatile Modifiers
Java defines two interesting type modifiers: transient and volatile. These modifiers are
used to handle somewhat specialized situations.
When an instance variable is declared as transient, then its value need not persist
when an object is stored. For example:
class T {
transient int a; // will not persist
THE JAVA LANGUAGE
Chapter 4: Operators 81
Operator
Result
^= Bitwise exclusive OR assignment
>>= Shift right assignment
>>>= Shift right zero fill assignment
<<= Shift left assignment
Since the bitwise operators manipulate the bits within an integer, it is important to
understand what effects such manipulations may have on a value. Specifically, it is
useful to know how Java stores integer values and how it represents negative numbers.
So, before continuing, let’s briefly review these two topics.
All of the integer types are represented by binary numbers of varying bit widths.
For example, the byte value for 42 in binary is 00101010, where each position represents
a power of two, starting with 2 0 at the rightmost bit. The next bit position to the left
would be 2 1 , or 2, continuing toward the left with 2 2 , or 4, then 8, 16, 32, and so on. So
42 has 1 bits set at positions 1, 3, and 5 (counting from 0 at the right); thus 42 is the sum
of 2 1 + 2 3 + 2 5 , which is 2 + 8 + 32.
All of the integer types (except char) are signed integers. This means that they can
represent negative values as well as positive ones. Java uses an encoding known as
two’s complement, which means that negative numbers are represented by inverting
(changing 1’s to 0’s and vice versa) all of the bits in a value, then adding 1 to the result.
For example, –42 is represented by inverting all of the bits in 42, or 00101010, which
yields 11010101, then adding 1, which results in 11010110, or –42. To decode a negative
number, first invert all of the bits, then add 1. –42, or 11010110 inverted yields 00101001,
or 41, so when you add 1 you get 42.
The reason Java (and most other computer languages) uses two’s complement is easy
to see when you consider the issue of zero crossing. Assuming a byte value, zero is
represented by 00000000. In one’s complement, simply inverting all of the bits creates
11111111, which creates negative zero. The trouble is that negative zero is invalid in
integer math. This problem is solved by using two’s complement to represent negative
values. When using two’s complement, 1 is added to the complement, producing
100000000. This producesa1bit too far to the left to fit back into the byte value, resulting
in the desired behavior, where –0 is the same as 0, and 11111111 is the encoding for –1.
Although we used a byte value in the preceding example, the same basic principle
applies to all of Java’s integer types.
Because Java uses two’s complement to store negative numbers—and because all
integers are signed values in Java—applying the bitwise operators can easily produce
unexpected results. For example, turning on the high-order bit will cause the resulting
value to be interpreted as a negative number, whether this is what you intended or not.
To avoid unpleasant surprises, just remember that the high-order bit determines the
sign of an integer no matter how that high-order bit gets set.
418 Java™ 2: The Complete Reference
The methods defined by Class are often useful in situations where run-time type
information about an object is required. As Table 14-13 shows, methods are provided
that allow you to determine additional information about a particular class, such as its
public constructors, fields, and methods. This is important for the Java Beans
functionality, which is discussed later in this book.
The following program demonstrates getClass( ) (inherited from Object) and
getSuperclass( ) (from Class):
// Demonstrate Run-Time Type Information.
class X {
int a;
float b;
}
class Y extends X {
double c;
}
class RTTI {
public static void main(String args[]) {
X x = new X();
Y y = new Y();
Class clObj;
clObj = x.getClass(); // get Class reference
System.out.println("x is object of type: " +
clObj.getName());
}
}
clObj = y.getClass(); // get Class reference
System.out.println("y is object of type: " +
clObj.getName());
clObj = clObj.getSuperclass();
System.out.println("y's superclass is " +
clObj.getName());
The output from this program is shown here:
462 Java™ 2: The Complete Reference
The output from the program is shown here:
J.W. West
11 Oak Ave
Urbana IL 61801
Ralph Baker
1142 Maple Lane
Mahomet IL 61853
Tom Carlton
867 Elm St
Champaign IL 61820
Aside from storing a user-defined class in a collection, another important thing to
notice about the preceding program is that it is quite short. When you consider that it
sets up a linked list that can store, retrieve, and process mailing addresses in about 50
lines of code, the power of the collections framework begins to become apparent. As
most readers know, if all of this functionality had to be coded manually, the program
would be several times longer. Collections offer off-the-shelf solutions to a wide variety
of programming problems. You should use them whenever the situation presents itself.
The RandomAccess Interface
Java 2, version 1.4 adds the RandomAccess interface. This interface contains no members.
However, by implementing this interface, a collection signals that it supports efficient
random access to its elements. Although a collection might support random access, it
might not do so efficiently. By checking for the RandomAccess interface, client code
can determine at run time whether a collection is suitable for certain types of random
access operations—especially as they apply to large collections. (You can use instanceof
to determine if a class implements an interface.) RandomAccess is implemented by
ArrayList and by the legacy Vector class.
Working with Maps
A map is an object that stores associations between keys and values, or key/value pairs.
Given a key, you can find its value. Both keys and values are objects. The keys must be
unique, but the values may be duplicated. Some maps can accept a null key and null
values, others cannot.
The Map Interfaces
Because the map interfaces define the character and nature of maps, this discussion of
maps begins with them. The following interfaces support maps:
216 Java™ 2: The Complete Reference
types of objects. In this case, if an object is derived from Figure, then its area can be
obtained by calling area( ). The interface to this operation is the same no matter what
type of figure is being used.
Using Abstract Classes
There are situations in which you will want to define a superclass that declares the
structure of a given abstraction without providing a complete implementation of every
method. That is, sometimes you will want to create a superclass that only defines a
generalized form that will be shared by all of its subclasses, leaving it to each subclass
to fill in the details. Such a class determines the nature of the methods that the
subclasses must implement. One way this situation can occur is when a superclass
is unable to create a meaningful implementation for a method. This is the case with
the class Figure used in the preceding example. The definition of area( ) is simply a
placeholder. It will not compute and display the area of any type of object.
As you will see as you create your own class libraries, it is not uncommon for a
method to have no meaningful definition in the context of its superclass. You can
handle this situation two ways. One way, as shown in the previous example, is to
simply have it report a warning message. While this approach can be useful in certain
situations—such as debugging—it is not usually appropriate. You may have methods
which must be overridden by the subclass in order for the subclass to have any meaning.
Consider the class Triangle. It has no meaning if area( ) is not defined. In this case, you
want some way to ensure that a subclass does, indeed, override all necessary methods.
Java’s solution to this problem is the abstract method.
You can require that certain methods be overridden by subclasses by specifying
the abstract type modifier. These methods are sometimes referred to as subclasser
responsibility because they have no implementation specified in the superclass. Thus,
a subclass must override them—it cannot simply use the version defined in the
superclass. To declare an abstract method, use this general form:
abstract type name(parameter-list);
As you can see, no method body is present.
Any class that contains one or more abstract methods must also be declared
abstract. To declare a class abstract, you simply use the abstract keyword in front of the
class keyword at the beginning of the class declaration. There can be no objects of an
abstract class. That is, an abstract class cannot be directly instantiated with the new
operator. Such objects would be useless, because an abstract class is not fully defined.
Also, you cannot declare abstract constructors, or abstract static methods. Any subclass
of an abstract class must either implement all of the abstract methods in the superclass,
or be itself declared abstract.
Here is a simple example of a class with an abstract method, followed by a class
which implements that method:
636 Java™ 2: The Complete Reference
Simple Applet Display Methods
As we’ve mentioned, applets are displayed in a window and they use the AWT to
perform input and output. Although we will examine the methods, procedures, and
techniques necessary to fully handle the AWT windowed environment in subsequent
chapters, a few are described here, because we will use them to write sample applets.
As we described in Chapter 12, to output a string to an applet, use drawString( ),
which is a member of the Graphics class. Typically, it is called from within either
update( ) or paint( ). It has the following general form:
void drawString(String message, int x, int y)
Here, message is the string to be output beginning at x,y. In a Java window, the
upper-left corner is location 0,0. The drawString( ) method will not recognize newline
characters. If you want to start a line of text on another line, you must do so manually,
specifying the precise X,Y location where you want the line to begin. (As you will see in
later chapters, there are techniques that make this process easy.)
To set the background color of an applet’s window, use setBackground( ).Toset the
foreground color (the color in which text is shown, for example), use setForeground( ).
These methods are defined by Component, and they have the following general forms:
void setBackground(Color newColor)
void setForeground(Color newColor)
Here, newColor specifies the new color. The class Color defines the constants shown
here that can be used to specify colors:
Color.black
Color.blue
Color.cyan
Color.darkGray
Color.gray
Color.green
Color.lightGray
Color.magenta
Color.orange
Color.pink
Color.red
Color.white
Color.yellow
For example, this sets the background color to green and the text color to red:
setBackground(Color.green);
setForeground(Color.red);
THE JAVA LIBRARY
Chapter 23: Images 829
}
return a.createImage(new FilteredImageSource(in.getSource(), this));
}
public int filterRGB(int x, int y, int rgb) {
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;
int k = (int) (.56 * g + .33 * r + .11 * b);
return (0xff000000 | k << 16 | k << 8 | k);
}
Invert.java
The Invert filter is also quite simple. It takes apart the red, green, and blue channels
and then inverts them by subtracting them from 255. These inverted values are packed
back into a pixel value and returned.
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
class Invert extends RGBImageFilter implements PlugInFilter {
public Image filter(Applet a, Image in) {
return a.createImage(new FilteredImageSource(in.getSource(), this));
}
public int filterRGB(int x, int y, int rgb) {
int r = 0xff - (rgb >> 16) & 0xff;
int g = 0xff - (rgb >> 8) & 0xff;
int b = 0xff - rgb & 0xff;
return (0xff000000 | r << 16 | g << 8 | b);
}
}
Figure 23-9 shows the image after it has been run through the Invert filter.
Contrast.java
The Contrast filter is very similar to Grayscale, except its override of filterRGB( ) is
slightly more complicated. The algorithm it uses for contrast enhancement takes the
red, green, and blue values separately and boosts them by 1.2 times if they are already
brighter than 128. If they are below 128, then they are divided by 1.2. The boosted
values are properly clamped at 255 by the multclamp( ) method.
152 Java™ 2: The Complete Reference
or how the data is actually managed within the class. In a sense, a class is like a “data
engine.” No knowledge of what goes on inside the engine is required to use the engine
through its controls. In fact, since the details are hidden, its inner workings can be
changed as needed. As long as your code uses the class through its methods, internal
details can change without causing side effects outside the class.
To see a practical application of the preceding discussion, let’s develop one of the
archetypal examples of encapsulation: the stack. A stack stores data using first-in, last-out
ordering. That is, a stack is like a stack of plates on a table—the first plate put down
on the table is the last plate to be used. Stacks are controlled through two operations
traditionally called push and pop. To put an item on top of the stack, you will use push.
To take an item off the stack, you will use pop. As you will see, it is easy to encapsulate
the entire stack mechanism.
Here is a class called Stack that implements a stack for integers:
// This class defines an integer stack that can hold 10 values.
class Stack {
int stck[] = new int[10];
int tos;
}
// Initialize top-of-stack
Stack() {
tos = -1;
}
// Push an item onto the stack
void push(int item) {
if(tos==9)
System.out.println("Stack is full.");
else
stck[++tos] = item;
}
// Pop an item from the stack
int pop() {
if(tos < 0) {
System.out.println("Stack underflow.");
return 0;
}
else
return stck[tos--];
}
THE JAVA LIBRARY
Chapter 15: java.util Part 1: The Collections Framework 497
}
}
// Deposit 1,000 into John Doe's account
bal = ((Double)balance.get("John Doe")).doubleValue();
balance.put("John Doe", new Double(bal+1000));
System.out.println("John Doe's new balance: " +
balance.get("John Doe"));
The output from this program is shown here:
Todd Hall: 99.22
Ralph Smith: -19.08
John Doe: 3434.34
Jane Baker: 1378.0
Tom Smith: 123.22
John Doe’s new balance: 4434.34
One important point: like the map classes, Hashtable does not directly support
iterators. Thus, the preceding program uses an enumeration to display the contents
of balance. However, you can obtain set-views of the hash table, which permits the
use of iterators. To do so, you simply use one of the collection-view methods defined
by Map, such as entrySet( ) or keySet( ). For example, you can obtain a set-view of the
keys and iterate through them. Here is a reworked version of the program that shows
this technique:
// Use iterators with a Hashtable.
import java.util.*;
class HTDemo2 {
public static void main(String args[]) {
Hashtable balance = new Hashtable();
String str;
double bal;
balance.put("John Doe", new Double(3434.34));
balance.put("Tom Smith", new Double(123.22));
balance.put("Jane Baker", new Double(1378.00));
balance.put("Todd Hall", new Double(99.22));
balance.put("Ralph Smith", new Double(-19.08));
// show all balances in hashtable
1028 Java™ 2: The Complete Reference
}
}
try { Thread.sleep(100); } catch (InterruptedException e) {}
createCellFromWorkPixels(c);
column_width += WIDTH_INCREMENT;
}
work_pixels = null;
void NextCell() {
int old_column_width = MAX_COLUMN_WIDTH - column_width;
for(int p = pixels_per_cell - cell_w; p >= 0; p -= cell_w) {
for (int x = 0; x < rightmost_columns_x_start; x +=
MAX_COLUMN_WIDTH) {
System.arraycopy(next_pixels, x + p, work_pixels,
old_column_width + x + p, column_width);
}
if(old_column_width <= rightmost_columns_max_width) {
System.arraycopy(next_pixels, rightmost_columns_x_start + p,
work_pixels, rightmost_columns_x_start +
old_column_width + p - 1,
rightmost_columns_max_width -
old_column_width + 1);
}
}
}
Here is what the column transition looks like before, during, and after:
Copyright © 2002 by The McGraw-HIll Companies, Inc. All rights reserved. Manufactured in the United States of
America. Except as permitted under the United States Copyright Act of 1976, no part of this publication may be
reproduced or distributed in any form or by any means, or stored in a database or retrieval system, without the prior
written permission of the publisher.
0-07-222858-X
The material in this eBook also appears in the print version of this title: 0-07-222420-7
All trademarks are trademarks of their respective owners. Rather than put a trademark symbol after every occurrence
of a trademarked name, we use names in an editorial fashion only, and to the benefit of the trademark
owner, with no intention of infringement of the trademark. Where such designations appear in this book, they
have been printed with initial caps.
McGraw-Hill eBooks are available at special quantity discounts to use as premiums and sales promotions, or for
use in corporate training programs. For more information, please contact George Hoare, Special Sales, at
george_hoare@mcgraw-hill.com or (212) 904-4069.
TERMS OF USE
This is a copyrighted work and The McGraw-Hill Companies, Inc. (“McGraw-Hill”) and its licensors reserve all
rights in and to the work. Use of this work is subject to these terms. Except as permitted under the Copyright Act
of 1976 and the right to store and retrieve one copy of the work, you may not decompile, disassemble, reverse
engineer, reproduce, modify, create derivative works based upon, transmit, distribute, disseminate, sell, publish
or sublicense the work or any part of it without McGraw-Hill’s prior consent. You may use the work for your
own noncommercial and personal use; any other use of the work is strictly prohibited. Your right to use the work
may be terminated if you fail to comply with these terms.
THE WORK IS PROVIDED “AS IS”. McGRAW-HILL AND ITS LICENSORS MAKE NO GUARANTEES
OR WARRANTIES AS TO THE ACCURACY, ADEQUACY OR COMPLETENESS OF OR RESULTS TO BE
OBTAINED FROM USING THE WORK, INCLUDING ANY INFORMATION THAT CAN BE ACCESSED
THROUGH THE WORK VIA HYPERLINK OR OTHERWISE, AND EXPRESSLY DISCLAIM ANY WAR-
RANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. McGraw-Hill and its licensors do not
warrant or guarantee that the functions contained in the work will meet your requirements or that its operation
will be uninterrupted or error free. Neither McGraw-Hill nor its licensors shall be liable to you or anyone else for
any inaccuracy, error or omission, regardless of cause, in the work or for any damages resulting therefrom.
McGraw-Hill has no responsibility for the content of any information accessed through the work. Under no circumstances
shall McGraw-Hill and/or its licensors be liable for any indirect, incidental, special, punitive, consequential
or similar damages that result from the use of or inability to use the work, even if any of them has been
advised of the possibility of such damages. This limitation of liability shall apply to any claim or cause whatsoever
whether such claim or cause arises in contract, tort or otherwise.
DOI: 10.1036/007222858X
Contents
xi
Creating a Multilevel Hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
When Constructors Are Called . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
Method Overriding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
Dynamic Method Dispatch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211
Why Overridden Methods? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Applying Method Overriding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
Using Abstract Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
Using final with Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
Using final to Prevent Overriding . . . . . . . . . . . . . . . . . . . . . . . . . . 219
Using final to Prevent Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . 220
The Object Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
9 Packages and Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224
Defining a Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
Finding Packages and CLASSPATH . . . . . . . . . . . . . . . . . . . . . . . . 226
A Short Package Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
Access Protection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
An Access Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
Importing Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
Defining an Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
Implementing Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236
Applying Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
Variables in Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
Interfaces Can Be Extended . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
10 Exception Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
Exception-Handling Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
Exception Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Uncaught Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Using try and catch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253
Displaying a Description of an Exception . . . . . . . . . . . . . . . . . . . . 254
Multiple catch Clauses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
Nested try Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
throw . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
throws . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
finally . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Java’s Built-in Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
Creating Your Own Exception Subclasses . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
Chained Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
Using Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
11 Multithreaded Programming . . . . . . . . . . . . . . . . . . . . . . . . . . 273
The Java Thread Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Thread Priorities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276
THE JAVA LIBRARY
Chapter 22: Using AWT Controls, Layout Managers, and Menus 763
Here is sample output from the TextAreaDemo applet:
Understanding Layout Managers
All of the components that we have shown so far have been positioned by the default
layout manager. As we mentioned at the beginning of this chapter, a layout manager
automatically arranges your controls within a window by using some type of algorithm.
If you have programmed for other GUI environments, such as Windows, then you are
accustomed to laying out your controls by hand. While it is possible to lay out Java
controls by hand, too, you generally won’t want to, for two main reasons. First, it is very
tedious to manually lay out a large number of components. Second, sometimes the width
and height information is not yet available when you need to arrange some control, because
the native toolkit components haven’t been realized. This is a chicken-and-egg situation;
it is pretty confusing to figure out when it is okay to use the size of a given component to
position it relative to another.
Each Container object has a layout manager associated with it. A layout manager
is an instance of any class that implements the LayoutManager interface. The layout
manager is set by the setLayout( ) method. If no call to setLayout( ) is made, then the
default layout manager is used. Whenever a container is resized (or sized for the first
time), the layout manager is used to position each of the components within it.
The setLayout( ) method has the following general form:
void setLayout(LayoutManager layoutObj)
206 Java™ 2: The Complete Reference
new Shipment(10, 20, 15, 10, 3.41);
Shipment shipment2 =
new Shipment(2, 3, 4, 0.76, 1.28);
double vol;
vol = shipment1.volume();
System.out.println("Volume of shipment1 is " + vol);
System.out.println("Weight of shipment1 is "
+ shipment1.weight);
System.out.println("Shipping cost: $" + shipment1.cost);
System.out.println();
}
}
vol = shipment2.volume();
System.out.println("Volume of shipment2 is " + vol);
System.out.println("Weight of shipment2 is "
+ shipment2.weight);
System.out.println("Shipping cost: $" + shipment2.cost);
The output of this program is shown here:
Volume of shipment1 is 3000.0
Weight of shipment1 is 10.0
Shipping cost: $3.41
Volume of shipment2 is 24.0
Weight of shipment2 is 0.76
Shipping cost: $1.28
Because of inheritance, Shipment can make use of the previously defined classes of
Box and BoxWeight, adding only the extra information it needs for its own, specific
application. This is part of the value of inheritance; it allows the reuse of code.
This example illustrates one other important point: super( ) always refers to the
constructor in the closest superclass. The super( ) in Shipment calls the constructor
in BoxWeight. The super( ) in BoxWeight calls the constructor in Box. In a class
hierarchy, if a superclass constructor requires parameters, then all subclasses must pass
those parameters “up the line.” This is true whether or not a subclass needs parameters
of its own.
xxviii Java™ 2: The Complete Reference
For Further Study
Java 2: The Complete Reference is your gateway to the Herb Schildt series of programming
books. Here are some others that you will find of interest:
To learn more about Java programming, we recommend the following:
Java 2: A Beginner's Guide
Java 2 Programmer's Reference
To learn about C++, you will find these books especially helpful:
C++: The Complete Reference
C++: A Beginner's Guide
Teach Yourself C++
C++ From the Ground Up
STL Programming From the Ground Up
To learn about C#, we suggest the following Schildt books:
C#: A Beginner's Guide
C#: The Complete Reference
If you want to learn more about the C language, the foundation of all modern
programming, then the following titles will be of interest:
C: The Complete Reference
Teach Yourself C
When you need solid answers, fast, turn to Herbert Schildt,
the recognized authority on programming.
THE JAVA LIBRARY
Chapter 24: New I/O, Regular Expressions, and Other Packages 875
The third source file, AddServer.java, contains the main program for the server
machine. Its primary function is to update the RMI registry on that machine. This is
done by using the rebind( ) method of the Naming class (found in java.rmi). That
method associates a name with an object reference. The first argument to the rebind( )
method is a string that names the server as “AddServer”. Its second argument is a
reference to an instance of AddServerImpl.
import java.net.*;
import java.rmi.*;
public class AddServer {
public static void main(String args[]) {
try {
AddServerImpl addServerImpl = new AddServerImpl();
Naming.rebind("AddServer", addServerImpl);
}
catch(Exception e) {
System.out.println("Exception: " + e);
}
}
}
The fourth source file, AddClient.java, implements the client side of this
distributed application. AddClient.java requires three command line arguments. The
first is the IP address or name of the server machine. The second and third arguments
are the two numbers that are to be summed.
The application begins by forming a string that follows the URL syntax. This URL
uses the rmi protocol. The string includes the IP address or name of the server and the
string “AddServer”. The program then invokes the lookup( ) method of the Naming
class. This method accepts one argument, the rmi URL, and returns a reference to an
object of type AddServerIntf. All remote method invocations can then be directed to
this object.
The program continues by displaying its arguments and then invokes the remote
add( ) method. The sum is returned from this method and is then printed.
import java.rmi.*;
public class AddClient {
public static void main(String args[]) {
try {
String addServerURL = "rmi://" + args[0] + "/AddServer";
AddServerIntf addServerIntf =
(AddServerIntf)Naming.lookup(addServerURL);
System.out.println("The first number is: " + args[1]);
APPLYING JAVA
Chapter 32: Scrabblet: A Multiplayer Word Game 1083
available players, so must we call server.delete( ). We take the first turn by setting
ourturn to true.
// our challenge was accepted.
void accept(String id, int seed) {
ourturn = true;
others_name = getName(id);
server.delete();
start_Game(seed);
}
chat( )
The chat( ) method is called by the server whenever the opponent types in his or her
chat window. In this implementation, the method simply shows the chat message in
the browser’s status message. In the future, it might be nice to log these into a
TextArea.
void chat(String id, String s) {
showStatus(others_name + ": " + s);
}
move( )
The move( ) method is called once for each tile your opponent plays. It looks through
the letters saved in theirs to find the one used. If the square is already occupied, the tile
is returned to the player’s tray. Otherwise, the opponent’s letter is moved onto the
board permanently. Next, the tile is replaced in theirs by bag.takeOut( ). If the bag is
empty, a status message appears. The board is repainted to show the new tiles on it.
Note that no scoring is done based on the placement of these tiles. The applet waits
until turn( ) is called to give the score.
// the other guy moved, and placed 'letter' at (x, y).
void move(String letter, int x, int y) {
for (int i = 0; i < 7; i++) {
if (theirs[i] != null && theirs[i].getSymbol().equals(letter)) {
Letter already = board.getLetter(x, y);
if (already != null) {
board.moveLetter(already, 15, 15); // on the tray.
}
board.moveLetter(theirs[i], x, y);
THE JAVA LIBRARY
Chapter 17: Input/Output: Exploring java.io 555
Filtered Byte Streams
Filtered streams are simply wrappers around underlying input or output streams that
transparently provide some extended level of functionality. These streams are typically
accessed by methods that are expecting a generic stream, which is a superclass of the
filtered streams. Typical extensions are buffering, character translation, and raw data
translation. The filtered byte streams are FilterInputStream and FilterOutputStream.
Their constructors are shown here:
FilterOutputStream(OutputStream os)
FilterInputStream(InputStream is)
The methods provided in these classes are identical to those in InputStream and
OutputStream.
Buffered Byte Streams
For the byte-oriented streams, a buffered stream extends a filtered stream class by attaching a
memory buffer to the I/O streams. This buffer allows Java to do I/O operations on more
than a byte at a time, hence increasing performance. Because the buffer is available,
skipping, marking, and resetting of the stream becomes possible. The buffered byte stream
classes are BufferedInputStream and BufferedOutputStream. PushbackInputStream also
implements a buffered stream.
BufferedInputStream
Buffering I/O is a very common performance optimization. Java’s BufferedInputStream
class allows you to “wrap” any InputStream into a buffered stream and achieve this
performance improvement.
BufferedInputStream has two constructors:
BufferedInputStream(InputStream inputStream)
BufferedInputStream(InputStream inputStream, int bufSize)
The first form creates a buffered stream using a default buffer size. In the second, the
size of the buffer is passed in bufSize. Use of sizes that are multiples of memory page,
disk block, and so on can have a significant positive impact on performance. This is,
however, implementation-dependent. An optimal buffer size is generally dependent on
the host operating system, the amount of memory available, and how the machine is
configured. To make good use of buffering doesn’t necessarily require quite this degree
of sophistication. A good guess for a size is around 8,192 bytes, and attaching even a
rather small buffer to an I/O stream is always a good idea. That way, the low-level
system can read blocks of data from the disk or network and store the results in your
buffer. Thus, even if you are reading the data a byte at a time out of the InputStream,
you will be manipulating fast memory over 99.9 percent of the time.
Chapter 26
A Tour of Swing
921
498 Java™ 2: The Complete Reference
Set set = balance.keySet(); // get set-view of keys
// get iterator
Iterator itr = set.iterator();
while(itr.hasNext()) {
str = (String) itr.next();
System.out.println(str + ": " +
balance.get(str));
}
System.out.println();
}
}
// Deposit 1,000 into John Doe's account
bal = ((Double)balance.get("John Doe")).doubleValue();
balance.put("John Doe", new Double(bal+1000));
System.out.println("John Doe's new balance: " +
balance.get("John Doe"));
Properties
Properties is a subclass of Hashtable.Itisused to maintain lists of values in which the
key is a String and the value is also a String. The Properties class is used by many other
Java classes. For example, it is the type of object returned by System.getProperties( )
when obtaining environmental values.
Properties defines the following instance variable:
Properties defaults;
This variable holds a default property list associated with a Properties object.
Properties defines these constructors:
Properties( )
Properties(Properties propDefault)
The first version creates a Properties object that has no default values. The second
creates an object that uses propDefault for its default values. In both cases, the property
list is empty.
In addition to the methods that Properties inherits from Hashtable, Properties
defines the methods listed in Table 15-14. Properties also contains one deprecated
method: save( ). This was replaced by store( ) because save( ) did not handle errors
correctly.
THE JAVA LIBRARY
Chapter 24: New I/O, Regular Expressions, and Other Packages 849
All buffers support various get( ) and put( ) methods, which allow you to get data
from a buffer or put data into a buffer. For example, Table 24-3 shows the get( ) and
Method
abstract byte get( )
ByteBuffer get(byte vals[ ] )
ByteBuffer get(byte vals[ ], int start,
int num)
abstract byte get(int idx)
abstract ByteBuffer put(byte b)
final ByteBuffer put(byte vals[ ] )
ByteBuffer put(byte vals[ ], int start,
int num)
ByteBuffer put(ByteBuffer bb)
abstract ByteBuffer put(int idx, byte b)
Description
Returns the byte at the current position.
Copies the invoking buffer into the array
referred to by vals. Returns a reference to
the buffer.
Copies num elements from the invoking
buffer into the array referred to by vals,
beginning at the index specified by start.
Returns a reference to the buffer. If there
are not num elements remaining in the
buffer, a BufferUnderflowException is
thrown.
Returns the byte at the index specified by
idx within the invoking buffer.
Copies b into the invoking buffer at the
current position. Returns a reference to
the buffer.
Copies all elements of vals into the
invoking buffer, beginning at the current
position. Returns a reference to the buffer.
Copies num elements from vals,
beginning at start, into the invoking
buffer. Returns a reference to the buffer. If
the buffer cannot hold all of the elements,
a BufferOverflowException is thrown.
Copies the elements in bb to the invoking
buffer, beginning at the current position.
If the buffer cannot hold all of the
elements, a BufferOverflowException is
thrown. Returns a reference to the buffer.
Copies b into the invoking buffer at the
location specified by idx. Returns a
reference to the buffer.
Table 24-3.
The get( ) and put( ) methods defined for ByteBuffer
THE JAVA LIBRARY
Chapter 18: Networking 615
}
fmt02d(tzhour) + fmt02d(tzmin) +
"] \"" +
cmd + " " +
url + " HTTP/1.0\" " +
code + " " +
size + "\n");
hits_served++;
bytes_served += size;
private void writeString(OutputStream out, String s)
throws IOException {
out.write(toBytes(s));
}
private void writeUCE(OutputStream out, UrlCacheEntry uce)
throws IOException {
HttpResponse hr = new HttpResponse(200, "OK", uce.mh);
writeString(out, hr.toString());
out.write(uce.data, 0, uce.length);
logEntry("GET", uce.url, 200, uce.length);
}
private boolean serveFromCache(OutputStream out, String url)
throws IOException {
UrlCacheEntry uce;
if ((uce = (UrlCacheEntry)cache.get(url)) != null) {
writeUCE(out, uce);
hits_to_cache++;
return true;
}
return false;
}
private UrlCacheEntry loadFile(InputStream in, String url,
MimeHeader mh)
throws IOException {
UrlCacheEntry uce;
byte file_buf[] = new byte[buffer_size];
uce = new UrlCacheEntry(url, mh);
THE JAVA LIBRARY
Chapter 24: New I/O, Regular Expressions, and Other Packages 881
The argument formatString describes how date and time information is displayed. An
example of its use is given here:
SimpleDateFormat sdf = SimpleDateFormat("dd MMM yyyy hh:mm:ss zzz");
The symbols used in the formatting string determine the information that is displayed.
Table 24-6 lists these symbols and gives a description of each.
In most cases, the number of times a symbol is repeated determines how that data
is presented. Text information is displayed in an abbreviated form if the pattern letter
is repeated less than four times. Otherwise, the unabbreviated form is used. For
Symbol Description
a
AM or PM
d Day of month (1–31)
h Hour in AM/PM (1–12)
k Hour in day (1–24)
m Minute in hour (0–59)
s Second in minute (0–59)
w Week of year (1–52)
y
Year
z
Time zone
D Day of year (1–366)
E
Day of week (for example, Thursday)
F
Day of week in month
G
Era (that is, AD or BC)
H Hour in day (0–23)
K Hour in AM/PM (0–11)
M
Month
S
Millisecond in second
W Week of month (1–5)
Z
Time zone in RFC822 format
Table 24-6.
Formatting String Symbols for SimpleDateFormat
THE JAVA LIBRARY
Chapter 21: Introducing the AWT: Working with Windows, Graphics, and Text 707
void fillRoundRect(int top, int left, int width, int height,
int xDiam, int yDiam)
A rounded rectangle has rounded corners. The upper-left corner of the rectangle
is at top,left. The dimensions of the rectangle are specified by width and height. The
diameter of the rounding arc along the X axis is specified by xDiam. The diameter of
the rounding arc along the Y axis is specified by yDiam.
The following applet draws several rectangles:
// Draw rectangles
import java.awt.*;
import java.applet.*;
/*
*/
public class Rectangles extends Applet {
public void paint(Graphics g) {
g.drawRect(10, 10, 60, 50);
g.fillRect(100, 10, 60, 50);
g.drawRoundRect(190, 10, 60, 50, 15, 15);
g.fillRoundRect(70, 90, 140, 100, 30, 40);
}
}
Sample output from this program is shown here:
THE JAVA LIBRARY
Chapter 15: java.util Part 1: The Collections Framework 471
The first form constructs a default LinkedHashMap. The second form initializes
the LinkedHashMap with the elements from m. The third form initializes the capacity.
The fourth form initializes both capacity and fill ratio. The meaning of capacity and fill
ratio are the same as for HashMap. The last form allows you to specify whether the
elements will be stored in the linked list by insertion order, or by order of last access. If
Order is true, then access order is used. If Order is false, then insertion order is used.
LinkedHashMap adds only one method to those defined by HashMap. This
method is removeEldestEntry( ) and it is shown here.
protected boolean removeEldestEntry(Map.Entry e)
This method is called by put( ) and putAll( ). The oldest entry is passed in e.Bydefault, this
method returns false and does nothing. However, if you override this method, then you
can have the LinkedHashMap remove the oldest entry in the map. To do this, have your
override return true.Tokeep the oldest entry, return false.
The IdentityHashMap Class
Java 2, version 1.4 adds the IdentityHashMap class. This class implements AbstractMap.
It is similar to HashMap except that it uses reference equality when comparing elements.
The Java 2 documentation explicitly states that IdentityHashMap is not for general use.
Comparators
Both TreeSet and TreeMap store elements in sorted order. However, it is the
comparator that defines precisely what “sorted order” means. By default, these classes
store their elements by using what Java refers to as “natural ordering,” which is
usually the ordering that you would expect. (A before B, 1 before 2, and so forth.) If
you want to order elements a different way, then specify a Comparator object when
you construct the set or map. Doing so gives you the ability to govern precisely how
elements are stored within sorted collections and maps.
The Comparator interface defines two methods: compare( ) and equals( ). The
compare( ) method, shown here, compares two elements for order:
int compare(Object obj1, Object obj2)
obj1 and obj2 are the objects to be compared. This method returns zero if the objects are
equal. It returns a positive value if obj1 is greater than obj2. Otherwise, a negative value
is returned. The method can throw a ClassCastException if the types of the objects are
not compatible for comparison. By overriding compare( ), you can alter the way that
objects are ordered. For example, to sort in reverse order, you can create a comparator
that reverses the outcome of a comparison.
254 Java™ 2: The Complete Reference
A try and its catch statement form a unit. The scope of the catch clause is restricted
to those statements specified by the immediately preceding try statement. A catch
statement cannot catch an exception thrown by another try statement (except in the
case of nested try statements, described shortly). The statements that are protected by
try must be surrounded by curly braces. (That is, they must be within a block.) You
cannot use try on a single statement.
The goal of most well-constructed catch clauses should be to resolve the
exceptional condition and then continue on as if the error had never happened.
For example, in the next program each iteration of the for loop obtains two random
integers. Those two integers are divided by each other, and the result is used to divide
the value 12345. The final result is put into a. If either division operation causes a
divide-by-zero error, it is caught, the value of a is set to zero, and the program
continues.
// Handle an exception and move on.
import java.util.Random;
class HandleError {
public static void main(String args[]) {
int a=0, b=0, c=0;
Random r = new Random();
}
}
for(int i=0; i<32000; i++) {
try {
b = r.nextInt();
c = r.nextInt();
a = 12345 / (b/c);
} catch (ArithmeticException e) {
System.out.println("Division by zero.");
a = 0; // set a to zero and continue
}
System.out.println("a: " + a);
}
Displaying a Description of an Exception
Throwable overrides the toString( ) method (defined by Object) so that it returns a
string containing a description of the exception. You can display this description in a
println( ) statement by simply passing the exception as an argument. For example, the
catch block in the preceding program can be rewritten like this:
THE JAVA LIBRARY
Chapter 20: Event Handling 657
used by the delegation event model. Its getID( ) method can be used to determine the
type of the event. The signature of this method is shown here:
int getID( )
Additional details about AWTEvent are provided at the end of Chapter 22. At this
point, it is important to know only that all of the other classes discussed in this section
are subclasses of AWTEvent.
To summarize:
■ EventObject is a superclass of all events.
■ AWTEvent is a superclass of all AWT events that are handled by the delegation
event model.
The package java.awt.event defines several types of events that are generated by
various user interface elements. Table 20-1 enumerates the most important of these event
classes and provides a brief description of when they are generated. The most commonly
used constructors and methods in each class are described in the following sections.
Event Class
ActionEvent
AdjustmentEvent
ComponentEvent
ContainerEvent
FocusEvent
InputEvent
ItemEvent
Description
Generated when a button is pressed, a list item is
double-clicked, or a menu item is selected.
Generated when a scroll bar is manipulated.
Generated when a component is hidden, moved, resized,
or becomes visible.
Generated when a component is added to or removed
from a container.
Generated when a component gains or loses
keyboard focus.
Abstract super class for all component input event classes.
Generated when a check box or list item is clicked; also
occurs when a choice selection is made or a checkable
menu item is selected or deselected.
Table 20-1.
Main Event Classes in java.awt.event
118 Java™ 2: The Complete Reference
}
// ...
if(interrupted()) done = true;
In this example, the for loop continues to run until the boolean variable done is set
to true. It does not test the value of i.
Here is another interesting for loop variation. Either the initialization or the
iteration expression or both may be absent, as in this next program:
// Parts of the for loop can be empty.
class ForVar {
public static void main(String args[]) {
int i;
boolean done = false;
}
}
i = 0;
for( ; !done; ) {
System.out.println("i is " + i);
if(i == 10) done = true;
i++;
}
Here, the initialization and iteration expressions have been moved out of the for. Thus,
parts of the for are empty. While this is of no value in this simple example—indeed, it
would be considered quite poor style—there can be times when this type of approach
makes sense. For example, if the initial condition is set through a complex expression
elsewhere in the program or if the loop control variable changes in a nonsequential
manner determined by actions that occur within the body of the loop, it may be
appropriate to leave these parts of the for empty.
Here is one more for loop variation. You can intentionally create an infinite loop
(a loop that never terminates) if you leave all three parts of the for empty. For example:
for( ; ; ) {
// ...
}
This loop will run forever, because there is no condition under which it will terminate.
Although there are some programs, such as operating system command processors,
850 Java™ 2: The Complete Reference
put( ) methods defined by ByteBuffer. (The other buffer classes have similar methods.)
All buffer classes also support methods that perform various buffer operations. For
example, you can allocate a buffer manually using allocate( ). You can wrap an array
inside a buffer using wrap( ). You can create a subsequence of a buffer using slice( ).
Channels
Channels are defined in java.nio.channels.Achannel represents an open connection to an
I/O source or destination. You obtain a channel by calling getChannel( ) on an object that
supports channels. Java 2, version 1.4 added getChannel( ) to the following I/O classes.
FileInputStream FileOutputStream RandomAccessFile
Socket ServerSocket DatagramSocket
Thus, to obtain a channel, you first obtain an object of one of these classes and then call
getChannel( ) on that object.
The specific type of channel returned depends upon the type of object getChannel( )
is called on. For example, when called on a FileInputStream, FileOuputStream, or
RandomAccessFile, getChannel( ) returns a channel of type FileChannel. When called
on a Socket, getChannel( ) returns a SocketChannel.
Channels such as FileChannel and SocketChannel support various read( ) and
write( ) methods that enable you to perform I/O operations through the channel. For
example, here are a few of the read( ) and write( ) methods defined for FileChannel.
All can throw an IOException.
Method
abstract int read(ByteBuffer bb)
abstract int read(ByteBuffer bb,
long start)
abstract int write(ByteBuffer bb)
abstract int write(ByteBuffer bb,
long start)
Description
Reads bytes from the invoking channel into bb
until the buffer is full, or there is no more input.
Returns the number of bytes actually read.
Beginning at the file location specified by start,
reads bytes from the invoking channel into
bb until the buffer is full, or there is no more
input. The current position is unchanged.
Returns the number of bytes actually read,
or –1 if start is beyond the end of the file.
Writes the contents of bb to the invoking
channel, starting at the current position.
Returns the number of bytes written.
Beginning at the file location specified by
start, writes the contents of bb to the invoking
channel. The current position is unchanged.
Returns the number of bytes written.
THE JAVA LIBRARY
Chapter 19: The Applet Class 651
at the specified URL. The method showDocument(URL, where) displays the specified
document at the specified location within the browser window. Valid arguments for
where are “_self” (show in current frame), “_parent” (show in parent frame), “_top”
(show in topmost frame), and “_blank” (show in new browser window). You can also
specify a name, which causes the document to be shown in a new browser window by
that name.
The following applet demonstrates AppletContext and showDocument( ).
Upon execution, it obtains the current applet context and uses that context to
transfer control to a file called Test.html. This file must be in the same directory
as the applet. Test.html can contain any valid hypertext that you like.
/* Using an applet context, getCodeBase(),
and showDocument() to display an HTML file.
*/
import java.awt.*;
import java.applet.*;
import java.net.*;
/*
*/
public class ACDemo extends Applet{
public void start() {
AppletContext ac = getAppletContext();
URL url = getCodeBase(); // get url of this applet
}
}
try {
ac.showDocument(new URL(url+"Test.html"));
} catch(MalformedURLException e) {
showStatus("URL not found");
}
The AudioClip Interface
The AudioClip interface defines these methods: play( ) (play a clip from the
beginning), stop( ) (stop playing the clip), and loop( ) (play the loop continuously).
After you have loaded an audio clip using getAudioClip( ), you can use these methods
to play it.
302 Java™ 2: The Complete Reference
}
}
System.out.println("Press Control-C to stop.");
Inside get( ), wait( ) is called. This causes its execution to suspend until the Producer
notifies you that some data is ready. When this happens, execution inside get( )
resumes. After the data has been obtained, get( ) calls notify( ). This tells Producer that
it is okay to put more data in the queue. Inside put( ), wait( ) suspends execution until
the Consumer has removed the item from the queue. When execution resumes, the
next item of data is put in the queue, and notify( ) is called. This tells the Consumer
that it should now remove it.
Here is some output from this program, which shows the clean synchronous behavior:
Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5
Deadlock
A special type of error that you need to avoid that relates specifically to multitasking
is deadlock, which occurs when two threads have a circular dependency on a pair of
synchronized objects. For example, suppose one thread enters the monitor on object X
and another thread enters the monitor on object Y. If the thread in X tries to call any
synchronized method on Y, it will block as expected. However, if the thread in Y, in
turn, tries to call any synchronized method on X, the thread waits forever, because to
access X, it would have to release its own lock on Y so that the first thread could
complete. Deadlock is a difficult error to debug for two reasons:
■ In general, it occurs only rarely, when the two threads time-slice in just the
right way.
■ It may involve more than two threads and two synchronized objects. (That is,
deadlock can occur through a more convoluted sequence of events than just
described.)
1108 Java™ 2: The Complete Reference
// find the center of the tile
x += dx + lw / 2;
y += dy + lh / 2;
// find the tile index
x = (x - lm) / (lw + lt);
y = (y - tm) / (lh + lt);
moveLetter(pick, x, y);
}
}
pick = null;
repaint();
dragLetter( )
The dragLetter( ) method is handled differently than the other mouse-related events.
This is mainly due to performance considerations. The goal is to have as smooth an
interaction with the user as possible. dragLetter( ) goes to some length to compute the
bounding box of where the tile was before this drag plus where it is now. It then
directly calls paint(getGraphics( )). This is nonstandard Java applet programming, but
it performs much more reliably.
private void dragLetter(int x, int y) {
if (pick != null) {
int ox = pick.x;
int oy = pick.y;
pick.move(x + dx, y + dy);
x0 = Math.min(ox, pick.x);
y0 = Math.min(oy, pick.y);
w0 = pick.w + Math.abs(ox - pick.x);
h0 = pick.h + Math.abs(oy - pick.y);
paint(getGraphics());
}
}
mousePressed( )
In the following code fragment, notice that MyMouseAdapter is an inner class that
extends MouseAdapter. It overrides the mousePressed( ) and mouseReleased( )
methods.
THE JAVA LIBRARY
Chapter 17: Input/Output: Exploring java.io 559
}
}
if ((c = f.read()) == '=')
System.out.print(".eq.");
else {
System.out.print("<-");
f.unread(c);
}
break;
default:
System.out.print((char) c);
break;
}
}
Here is the output for this example. Notice that = = was replaced by “.eq.” and = was
replaced by “<–”.
if (a .eq. 4) a <- 0;
PushbackInputStream has the side effect of invalidating the mark( ) or reset( )
methods of the InputStream used to create it. Use markSupported( ) to check any
stream on which you are going to use mark( )/reset( ).
SequenceInputStream
The SequenceInputStream class allows you to concatenate multiple InputStreams.
The construction of a SequenceInputStream is different from any other InputStream.
A SequenceInputStream constructor uses either a pair of InputStreams or an
Enumeration of InputStreams as its argument:
SequenceInputStream(InputStream first, InputStream second)
SequenceInputStream(Enumeration streamEnum)
Operationally, the class fulfills read requests from the first InputStream until it runs
out and then switches over to the second one. In the case of an Enumeration, it will
continue through all of the InputStreams until the end of the last one is reached.
Here is a simple example that uses a SequenceInputStream to output the contents
of two files:
// Demonstrate sequenced input.
import java.io.*;
import java.util.*;
974 Java™ 2: The Complete Reference