This chapter will answer the following questions:
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.
This chapter will primarily focus on the Language, Utilities and I/O packages. Aspects of the security package will be discussed in "Java Virtual Machine security."
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 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.
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.
+1.79769313486231579E+308 to +4.9406545841246544E-324 (64 bit) | |
-9223372036854775808 to 9223372036854775807 (64 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 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.
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.
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.
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 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.
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 provides access to system platform independent resources. It is a declared as a final class, so it can't be subclassed. 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 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.
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 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.
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.
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.
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 the following packages: Input stream classes, Output stream classes, File classes, and the StreamTokenizer class.
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 follows: 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.
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.
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.
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.
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.
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.
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.
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.
What was covered in this chapter:
pubsweb@borland.com
Copyright © 1997, 1999, Inprise Corporation. All rights reserved.