The Java Class Libraries

This chapter will answer the following questions:


Introduction

Most programming languages rely on pre-built libraries to support certain functionality. For example, C has no built-in support for I/O functions. JDK 1.1 comes with a very impressive library that includes support for database connectivity, GUI design, I/O, and network programming. Although JDK 1.1 contains numerous support packages, there are ten standard packages that warrant further discussion. The following table briefly describes these packages.

Package

Description

Language

The main core of the Java language

Utilities

Support for utility data structures

I/O

Supports various types of input/output

Networking

TCP/IP support and socket programming

AWT

GUI design and event-handling

Text

Support for internationalization

Security

Support for cryptographic security

RMI

Support for distributed programming

Reflection

Used to obtain run-time class information

SQL

Support for querying databases using SQL

This chapter will primarily focus on the Language, Utilities and I/O packages. Aspects of the security package will be discussed in the "Java Virtual Machine Security" chapter.


The Language Package

One of the most important packages in the Java class library is the java.lang package. This Language package contains the language's main support classes. It is virtually impossible to write a Java program without using the Language package. The following sections discuss some of the more important classes contained in the Language package.

The Object Class

The Object class is the parent class of all Java classes. This simply means that all Java classes are derived from the Object class. The object class itself contains several methods of importance. These methods include clone, equals, and toString.

An object that uses the clone method simply makes a copy of itself. To accomplish this, new memory is allocated for the clone, then contents of the original object is copied into the clone object. For example, a copy of the Document class that contains a text and author property needs to be created. To create a new instance of the Document class that contains both properties and the values associated with the object, the clone method should be used. The following code demonstrates how this would be accomplished.

Document document1 = new Document ("docText.txt", "Joe Smith");
Document document2 = document1.clone();

The equals method compares two objects of the same type for equality by comparing the properties of both objects. It simply returns a Boolean value depending on the results of the object that calls it and the object that is passed to it. For instance, if equals is called by an object that passes it an object that is completely identical, the equals method would return a true value.

The toString method returns a String representing the value of the object. For this method to return proper information about different types of objects, the object's class must override it.

Type Wrapper Classes

Primitive data types are not used as objects in Java. These primitive data types include numbers, booleans, and characters. The reasoning behind not including these data types as objects, lies in performance.

Treating these primitive data types as objects would greatly impact the language's performance (due to the overhead of processing objects). However, some Java classes and methods require primitive data types to be objects. Also, it would be useful in some cases to add custom methods to these types. For these reasons, the Java type wrapper classes can be instantiated. The following lists the primitive data types that the Language packages support as objects.

Type Wrapper Classes

Description

Boolean

True or False (1 Bit)

Byte

-128 to 127 (8 bit signed integer)

Character

Unicode character (16 bit)

Double

+1.79769313486231579E+308 to +4.9406545841246544E-324 (64 bit)

Float

+3.40282347E+28 to +1.40239846E-45 (32 bit)

Integer

-2147483648 to 2147483647 (32 bit signed integer)

long

-9223372036854775808 to 9223372036854775807 (64 bit signed integer)

short

-32768 to 32767 (16 bit signed integer)

Although each one of these classes contains its own methods, several methods are standard throughout each object. These methods include ClassType, typeValue, toString and Equals.

The ClassType method is the constructor for the wrapper classes. It simply takes an argument of the class type it is wrapping. For example, the following code demonstrates how a Character wrapper class is constructed.

Character charWrapper = new Character ('T');

The typeValue method returns the primitive type of the wrapper class. The following code demonstrates using the charWrapper object. Notice that charPrimitive is a primitive data type (declared as a char).

However, using this method, primitive data types can be assigned to type wrappers.

char charPrimitive = charWrapper.charValue();

The toString and Equals methods are used similarly as in the Object class. They are typically used for debugging purposes.

The Math Class

The Math class provides useful methods that implement common math functions. This class is not instantiated, and it is declared final, so it cannot be subclassed. Some of the methods included in this class are: sin, cos, exp, log, max, min, random, sqrt and tan. Some of these methods are overloaded to accept and return different data types. Here are examples of using some of the methods.

double d1 = Math.sin (45);
double d2 = 23.4;
double d3 = Math.exp (d2);
double d4 = Math.log (d3);
double d5 = Math.max (d2, Math.pow (d1, 10);

The Math class also declares the constants PI and E. This can easily be used within any calculations.

Do not confuse the Math class with the java.math package. The java.math package provides support classes for working with large numbers.

The String Class

The String class is used to declare and manipulate strings. Unlike C/C++, Java does not use character arrays to represent strings. The String class is used for constant strings and is typically constructed when the Java compiler encounters a string in quotes. However, strings can be constructed several ways. The following lists some of the strings constructors and what they accept.

Constructor

Parameters

String

()

String

(String)

String

(char value[])

String

(char value[], int off, int count)

String

(StringBuffer)

The String class contains several important methods that are essential when dealing with strings.

The following table lists some of the more crucial methods and declares what they accept and return.

Method

Accepts

Returns

length

()

int

charAt

(int index)

char

compareTo

(String)

int

startsWith

(String prefix)

boolean

endsWith

(String suffix)

boolean

indexOf

(int ch)

int

substring

(int beginIndex, int endIndex)

String

concat

(String)

String

toLowerCase

()

String

toUpperCase

()

String

valueOf

(Object)

String

A very efficient and feature associated with many of these methods is that they are overloaded for different data types. The following demonstrates how the string class and some of its methods can be used.

String s1 = new String ("Hello World.");
 
char cArray[] = {'J', 'B', 'u', 'i', 'l', 'd', 'e', 'r'};
String s2 = new String (cArray); //s2 = "JBuilder"
 
int i = s1.length();		//i = 12
char c = s1.charAt(4);	 //c = 'o'
i = s1.indexOf('l');	 //i = 2 (the first 'l')
 
String s3 = "abcdef".substring (2, 5)	//s3 = "cde"
String s4 = s3.concat ("f");//s4 = "cdef"
String s5 = valueOf (i); //s5 = "2" (valueOf()is static)

The StringBuffer Class

The StringBuffer class differs from the String class in that StringBuffer objects can be modified. Like the String class, the StringBuffer class has several constructors. The following table lists these constructors for the StringBuffer class.

Constructor Accepts

StringBuffer

()

StringBuffer

(int length)

StringBuffer

(String)

There are several important methods that separate the StringBuffer class from the String class. These methods include: Length, Capacity, setLength, charAt, setCharAt, Append, Insert and toString.

One method that is used quite often when dealing with StringBuffers' is the Append method. The Append method is used to add text to the StringBuffer. Fortunately, the Append method is heavily overloaded.

Another important method that is commonly used with the StringBuffer is the Capacity method. This method returns the amount of memory allocated for the StringBuffer. This value can be greater than the value returned by the Length method. This is due to the fact that memory allocated for a StringBuffer can be controlled with the StringBuffer (int length) constructor. The following code demonstrates some of the methods associated with the StringBuffer class.

StringBuffer s1 = new StringBuffer(10);
 
int c = s1.capacity();	//c = 10
int l = s1.length();	//l = 0
 
s1.append("Bor");		//s1 = "Bor"
s1.append("land");	//s1 = "land"
 
c = s1.capacity();	//c = 10
l = s1.length();		//l = 7
 
s1.setLength(2);		//s1 = "Bo"
 
StringBuffer s2 = new StringBuffer("Helo World");
s2.insert (3, "l");	//s2 = "Hello World"

The System Class

The System class provides access to system platform independent resources. It is a declared as a final class, so it can't be sub-classed. It also declares its methods and variables as static. This simply allows it to be available, without it being instantiated.

The methods in the system class provide many uses. One important feature is the ability to get the current system time, using the currentTimeMillis method. It is also possible to retrieve and change system resources using the Get and Set Properties methods. Another convenient feature that the System class provides is being able to force garbage collection with the gc method; and finally, the System class allows developers to load dynamic link libraries with the loadLibrary method.

The most useful aspect of the System class is the variables it declares. These variables are used to interact with the system. These variables include in, out, err. The in variable represents the system's standard input stream, whereas the out variable represents the standard output stream. The err variable is the standard error stream. Streams will be discussed in more detail in the I/O Package section.


The Utilities Package

The java.util package contains various utility classes and interfaces that are crucial for Java development. For the most part, they aid the developer in designing different types of data structures. The following table describes some of the classes associated with the Utilities Package.

Class

Description

Calendar

Allows use of calendar features

Date

Represents dates and times

Dictionary

An abstract class that is the parent class of Hashtable

Hashtable

Allows key associations with values

SimpleTimeZone

Represents a time zone

Stack

Allows arrangement of objects in a stack

StringTokenizer

Breaks String up into tokens

Vector

Implements a dynamic array of objects

The Utility Package also declares three interfaces. These interfaces are Enumeration, EventListener and Observable. In this section, we will only cover the Vector class and the Enumeration interface.

The Enumeration Interface

The Enumeration interface is used to implement a class capable of enumerating values. A class that implements the Enumeration interface can facilitate the traversal of data structures.

The methods defined in the Enumeration interface allow the Enumeration object to continuously retrieve all the elements from a data structure, one by one. There are only two methods declared in the Enumeration interface, hasMoreElements and nextElement.

The hasModeElements method returns true if more elements remain in the data structure. The nextElement method is used to return the next object in the structure being enumerated.

A simple example will be used to illustrate the implementation of the Enumeration interface. This example will contain a class called canEnumerate, which implements the Enumeration interface. An instance of that class can be used to print all the elements of a Vector object (in this case v).

canEnumerate enum = v.elements();
 
while (enum.hasMoreElements()) {
System.out.print (enum.nextElement());
}

There is one limitation on an Enumeration object; it can only be used once. There is no method defined in the interface that allows the Enumeration object to backtrack to previous elements. So, once it enumerates the entire list, it is consumed.

The Vector Class

JDK 1.1 does not include support for many dynamic data structures, such as linked lists and queues; it only defines a Stack class. However, the Vector class provides an easy way to implement dynamic data structures. The following table lists some of the more important methods of the Vector class and declares what they accept.

Method

Accepts

Vector

(int initialCapacity)

Vector

(int initialCapacity, int capacityIncrement)

setSize

(int newSize)

capacity

()

size

()

elements

()

elementAt

(int)

firstElement

()

lastElement

()

removeElementAt

(int index)

addElement

(Object)

toString

()

The Vector class is efficient because it allocates more memory than needed when adding new elements. A Vector's capacity, therefore, is usually greater than its actual size. The capacityIncrement parameter in the second constructor indicates a Vector's capacity increase whenever an element is added to it.

The following code demonstrates the use of the Vector class. In the code, a Vector object is created called vector1, and enumerates its elements in three ways: using Enumeration's nextElement method, using Vector's elementAt method, and using Vector's toString method. To display the output, an AWT component is created called textArea, and the text property is set using the setText method. Here is the code added to the end of the VectorTest1 constructor.

Vector vector1 = new Vector (10, 2); //initial size is 10,
//capacityIncrement is 2
for (int i=0; i<10;i++)
vector1.addElement(new Integer(i)); //addElement doesn't 
//accept
//int types 
//enumerate vector1
Enumeration e = vector1.elements();
 
frame.textArea1.setText ("The elements using Enumeration's 
nextElement():\n");
 
while (e.hasMoreElements())
frame.textArea1.setText (frame.textArea1.getText()+ 
e.nextElement()+ " | ");
 
frame.textArea1.setText (frame.textArea1.getText()+ "\n\n");
 
//enumerate using the elementAt() method
frame.textArea1.setText (frame.textArea1.getText()+ "The 
elements using Vector's elementAt():\n");
 
for (int i=0; i< vector1.size();i++)
frame.textArea1.setText (frame.textArea1.getText()+ 
vector1.elementAt(i) + " | ");
 
frame.textArea1.setText (frame.textArea1.getText()+ "\n\n");
 
//enumerate using the toString() method
frame.textArea1.setText (frame.textArea1.getText()+ "Here's 
the vector as a String:\n");
 
frame.textArea1.setText (frame.textArea1.getText()+ 
vector1.toString());

The following figure demonstrates what this code would accomplish if it was used within an application.

Figure A.1 - Vector and Enumeration example


The I/O Package

The java.io package provides support for reading and writing data to and from different devices. The classes in this package can be divided into three different packages. These packages are Input stream classes, Output stream classes, File classes and the StreamTokenizer class.

Input Stream Classes

An Input stream is used to read data from an input source (e.g. a file, a string, memory, etc.). There are several classes encapsulated in this definition. These input stream classes include: InputStream, BufferedInputStream, DataInputStream, FileInputStream and StringBufferInputStream.

The basic method of reading data using an Input stream class is always the same: (1) create an instance of an input stream class, then (2) tell it where to read the data. Input stream classes read data as a continuous stream of bytes. If no data is currently available, the Input stream class blocks (waits until some data becomes available).

In addition to the Input stream classes, the I/O package provides reader classes that correspond to all the Input stream classes (except for DataInputStream). These reader classes are as followed: Reader, BufferedReader, FileReader and StringReader. Reader classes are identical to Input stream classes, except that they read Unicode characters instead of bytes.

The InputStream class is an abstract class from which all other Input stream classes are derived. It provides the basic interface for reading a stream of bytes. The following table lists some of the InputStream methods and what they except. Each of these methods returns an int value, except for the close method.

Method

Accepts

read

()

read

(byte b[])

read

(byte b[], int off, int len)

available

()

skip

(long)

close

()

The first method, abstract int read, reads a byte from the input stream and returns it as an integer (you can cast the return type to char). It returns -1 when it reaches the end of the stream. The second method, int read(byte b[]), reads multiple bytes and stores them in its array parameter. It returns the number of bytes read, or -1 when the end of the stream is reached. The last read method, int read(byte b[], int off, int len), allows the developer to set the maximum number of bytes to read and directs where in the array to store them.

The int available method, returns the number of input bytes that can be read without blocking. The skip method skips a specified number of bytes from the stream. Finally, the close method is used to close the input stream. This method is normally called automatically, but it is safer to call it, manually.

The FileInputStream class is very similar to the InputStream class, only it is designed for reading from files. It contains two constructors. These constructors are FileInputStream(String name) and FileInputStream(File file). The first constructor takes the file's name as a parameter. The second simply takes a file object. The file class will be discussed later. The following example demonstrates the use of the FileInputStream class.

import java.io.*;
 
class fileReader {
 
public static void main (string args[]) {
 
byte buff[] = new byte [80];
try { 
 
InputStream fileIn = new FileInputStream("Readme.txt");
int i = fileIn.read(buff); 
 
}
catch(FileNotFoundException e) {
}
catch(IOException e) {
}	
 
String s = new String(buff);
System.out.println(s);
}
}

In this example, a character array was created that will store the input data. Then a FileInputStream object was instantiated and passed the input file's name to its constructor. Next, the FileInputStreams' read() method was used to read a stream of characters and store them in the buff array. The first 80 bytes are read from the Readme.txt file and stored in the buff array. The FilerReader class could be used in place of the FileInputStream method. The only changes needed would be a char array used in place of the byte array, and the reader object would be instantiated as follows.

Reader fileIn = new FileReader("Readme.txt");

Finally, in order to see the result of the read call, a string object is created using the buff array, and then it is passed to the System.out.println method.

As mentioned earlier, the class System is defined in java.lang and provides access to system resources. System.out is a static member of System and represents the standard output device. The println method was called to send the output to the standard output device. The System.out object is of type PrintStream, which will be discussed in the Output Stream Classes section.

Another static member of the System class is the System.in object, which is of type InputStream. Naturally, this object represents the standard input device.

Output Stream Classes

The Output stream classes are the counterparts to the Input stream classes. They are used to output streams of data to the various output sources. The main output stream classes in Java are: OutputStream, PrintStream, BufferedOutputStream, DataOutputStream and FileOutputStream.

To output a stream of data, an output stream object is created and is directed to output the data to a particular output source. As expected, there are also writer classes. There is a corresponding writer class for all, except the DataOutputStream class. Since the OutputStream class is the counterpart to the InputStream class, it defines the following methods.

Method

Accepts

write

(int)

write

(byte b[])

write

(byte b[], int off, int len)

flush

()

close

()

The flush method is used to flush the output stream (i.e. it forces the output of any buffered data). The PrintStream class is primarily designed to output data as text. It has two constructors. These constructors are PrintStream(OutputStream) and PrintStream(OutputStram, boolean autoflush).

There is one difference between the two constructors. The first causes the PrintStream object to flush the buffered data based on specified conditions, while the second flushes the data when it encounters a new line character (if autoflush is set to true).

Here are some of the methods PrintStream defines.

Method

Accepts

checkError

()

print

(Object obj)

print

(String s)

println

()

println

(Object obj)

The print and println methods are overloaded for different data types. The checkerror method flushes the stream and returns a false value if an error was encountered.

File Classes

The FileInputStream and FileOutputStream classes only provide basic functions for handling file input and output. The java.io package provides the File class and RandomAccessFile class for more advanced file support. The File class provides easy access to file attributes and functions. The RandomAccessFile class provides various methods for reading and writing to and from a file. The File class has three constructors: File(String path), File(String path, String name) and File(File dir, String name). The File class also implements many important methods. The following table lists these methods and declares what they return.

Method

Returns

delete

boolean

canRead

boolean

canWrite

boolean

exists

boolean

isDirectory

boolean

renameTo

boolean

long lastModified

long

long length

long

getName

String

getParent

String

getPath

String

The RandomAccessFile class is more powerful than the FileInputStream and FileOutputStream classes. It implements reading and writing methods for all the primitive types. It has two constructors that are as followed: RandomAccessFile(String name, String mode) and RandomAccessFile(File file, String mode). The mode parameter indicates whether the RandomAccessFile object is used for reading ("r"), or reading/writing ("rw"). There are many powerful methods implemented by RandomAccessFile.

The following table lists some of these methods and what they accept.

Method

Accepts

skipBytes

(int)

getFilePointer

()

seek

(long pos)

read

()

read

(byte b[], int off, int len)

readType

()

write

()

write

(byte b[], int off, int len)

length

()

close

()

The StreamTokenizer Class

This class is used to break up a stream into individual tokens. The StreamTokenizer class implements methods used to define the lexical syntax of tokens. This technique of processing streams into tokens is perhaps most commonly used in writing compilers.


The JBCL Packages

The Java Beans Component Library is a powerful API that extends the JDK 1.1. The JBCL package includes UI components, database connectivity components, and specialized I/O components. The components in the JBCL can be broken up into the following categories: Controls, Dataset components, I/O components, Layout managing components, Model components, View components and Utility components

Controls

The borland.jbcl.control package contains various UI components such as containers, dialogs, and controls. Many of the components in this package are basically enhanced versions of their AWT counterparts. They differ from equivalent AWT components in that they are composite, based on the model-view architecture (covered later), data-aware and allow sharing of data among multiple UI components. Some of the classes defined in this package are:

Class

Component

ButtonBar

ButtonControl

CheckBoxControl

CheckBoxPanel

ListControl

ChoiceControl

GridControl

StatusBar

TextAreaControl

TextFieldControl

Dataset Components

The borland.jbcl.dataset package supports database connectivity in JBuilder. It defines classes that provide access to different types of data sources. Some of the functionality its classes implement includes logging on to remote data servers, retrieving data through queries and stored procedures, navigating and editing data locally and copying the local data set to the original source. Some of the classes defined in the dataset package are DataBase, DataSet, StorageDataSet, ProcedureDataSet, QueryDataSet, DataFile, ReadRow, ReadWriteRow, RowFilterResponse, RowStatus and QueryResolver.

I/O Components

The borland.jbcl.io package contains specialized classes for handling input and output. Some of the classes included in this package are AsciiInputStream, AsciiOutputStream, EncodedInputStream, EncodedOutputStream, SimpleCharInputStream and SimpleCharOutputStream.

Layout Components

The borland.jbcl.layout package contains layout managing and constraint classes. These classes provide various methods for defining how components are laid out in container classes. The containers in the Component Palette use a default layout. This default layout can be changed to one of the classes defined in the Layout package. Some of the layout classes are GridBagConstraints, PaneConstraints, XYConstraints and XYLayout.

Model and View Components

The borland.jbcl.model package contains interfaces and classes used for building components based on the model-view architecture. The model-view approach encapsulates different functionality into separate objects. These objects include: a object that contains the data (a model), a object responsible for UI-based events and functionality (a view), a object that manages the visual display of different data types (a view manager), and a object that actually displays the data (a painter).

When a model object needs to display a certain data type, the view object is notified. The view object gets the data object from the model and passes on to the view manager. The view manager determines the type of the data, and returns to the view the proper painter object. The view calls on the painter, which finally displays the data in the model object.

The following table lists the four model types.

Model Type

Description

Singleton

A single data item used by a checkbox component

Vector

A list of data items used by a list control

Matrix

A table of data items used by a grid control

Graph

A tree of data items used by a tree control

The model package provides two interfaces used for each of these model types. One interface provides read-only access to the data. The other interface provides read and write access to the data. This package also contains several classes that provide the functionality needed for the four model types, two view manager classes, and several item painter classes.

Utility Components

The borland.jbcl.util package contains various utility classes and constants. The classes can be categorized as Two dimensional alignment managing classes, Event-dispatching classes, Exception-related classes, I/O classes, Multicaster classes or Timer classes.

Multicaster classes provide an efficient way for beans to manage their events. A multicaster class uses an array instead of a vector to keep a list of Event Listener objects. It also implements efficient methods for dispatching events, and for checking whether a particular Event Listener exists. These multicaster class types include the ActionMulticaster, EventMulticaster, FocusMulticaster, ItemMulticaster, MouseMotionMulticaster and the MouseMulticaster.


Java Generic Library (JGL)

The JDK 1.1 has support for only three types of data structures: Vector, Stack, and Hashtable. The JDK's support for various algorithms, such as sorting and filtering, is not very strong. The freely distributed Java Generic Library (JGL) can overcome these shortcomings. Some of the JGL's most beneficial features include support for Serialization, multi-thread safe, optimal performance, 11 data structures, 40 algorithms and it is completely compatible with the JDK 1.1.

The JGL also includes a several data structures. The following table defines each data structures.

Data Structure

Description

Array

Linear, contiguous storage

Deque

Linear, non-contiguous storage; inserts elements at both ends

Dlist

Doubly-linked list

Slist

Singly-linked list

HashMap

Stores mappings using a hash table

OrderedMap

Stores mappings in order

HashSet

Stores a set using a hash table

OrderedSet

Stores a set in order

PriorityQueue

Pops elements in a sorted order

Queue

First-in, first-out (FIFO) data structure

Stack

First-in, last-out (LIFO) data structure

The JGL also contains several types of algorithms. The following table describes each algorithm in detail.

Algorithm

Description

Applying

Applies a function to all elements of a sequence

Copying

Copies a sequence

Filling

Fills a sequence with a single element

Filtering

Filters a sequence

Finding

Finds an element based on a condition

Heap

Manipulates a heap

Replacing

Replaces an element

Reversing

Reverses a sequence

Set operations

Performs union, intersection, inclusion, and difference

Shuffling

Shuffles a sequence randomly

Sorting

Sorts a sequence

Swapping

Swaps elements or sequences

In addition to containers and algorithms, the JGL defines a number of interfaces and exceptions. It also contains iterators that support different ways of iterating through the containers and function objects.


Summary

What was covered in this chapter: