The Utilities package provides a collection of classes that implement various standard programming data structures. These classes are useful in a variety of ways and are the fundamental building blocks of the more complicated data structures used in the other Java packages and in your own applications. Unless otherwise noted, all of the interfaces and classes discussed in this chapter extend the java.lang.Object class. Table 19.1 lists the classes and interfaces implemented in this package along with a brief description of each.
Table 19.1. Utilities package interfaces and classes.
Interfaces | |
---|---|
Enumeration | Interface for classes that can enumerate a vector. |
Observer | Interface for classes that can observe observable objects. |
The Utilities package has two interfaces that can be used in classes of your own designEnumeration and Observer. Interfaces are a set of methods that must be written for any class that claims to implement the interface. This provides a consistent way of using all classes that implement the interface.
The Enumeration interface is used for classes that can retrieve data from a list, element by element. For example, there is an Enumeration class in the Utilities package that implements the Enumeration interface for use in conjunction with the Vector class. The Observer interface is useful in designing classes that can watch for changes that occur in other classes.
This interface specifies a set of methods used to enumeratethat is, iterate througha list. An object that implements this interface may be used to iterate through a list only once because the Enumeration object is consumed through its use.
For example, an Enumeration object can be used to print all the elements of a Vector object, v, as follows:
for (Enumeration e=v.elements();e.hasMoreElements();) System.out.print(e.nextElement()+ );
The Enumeration interface specifies only two methodshasMoreElements() and nextElement(). The hasMoreElements() method must return True if there are elements remaining in the enumeration. The nextElement() method must return an object representing the next element within the object that is being enumerated. The details of how the Enumeration interface is implemented and how the data is represented internally are left up to the implementation of the specific class.
See also: Dictionary, Hashtable, Properties, Vector.
This interface, if implemented by a class, allows an object of the class to observe other objects of the class Observable. The observer is notified whenever the Observable object that it is watching has been changed.
The interface only specifies one method, update(Observable, Object). This method is called by the observed object to notify the observer of changes. A reference to the observed object is passed along with any additional object that the observed object wishes to pass to the observer. The first argument enables the observer to operate on the observed object, while the second argument is used to pass information from the observed to the observer.
The Utilities package supplies ten different classes that provide a wide variety of functionality. While these classes dont generally have much in common, they all provide support for the most common data structures used by programmers.
This class implements a data type that represents a collection of bits. The collection will grow dynamically as more bits are required. It is useful for representing a set of True/False values. Specific bits are identified using non-negative integers. The first bit is bit 0 (see Figure 19.1).
FIGURE 19.1Example of a BitSet object.
This class is most useful for storing a group of related True/False values such as user responses to Yes/No questions. Individual bits in the set are turned on or off with the set() and clear() methods, respectively. Individual bits are queried with the get() method. These methods all take the specific bit number as their only argument. The basic Boolean operations AND, OR, and XOR can be performed on two BitSets using the and(), or(), and xor() methods. Because these methods modify one of the BitSets, one generally will use the clone() method to create a duplicate of one, and then AND, OR, or XOR the clone with the second BitSet. The result of the operation then will end up in the cloned BitSet. The BitSet1 program in Listing 19.1 illustrates the basic BitSet operations, whereas Table 19.2 summarizes all the various methods available in the BitSet class.
import java.io.DataInputStream; import java.util.BitSet; class BitSet1 { public static void main(String args[]) throws java.io.IOException { DataInputStream dis=new DataInputStream(System.in); String bitstring; BitSet set1,set2,set3; set1=new BitSet(); set2=new BitSet(); // Get the first bit sequence and store it System.out.println(Bit sequence #1:); bitstring=dis.readLine(); for (short i=0;i<bitstring.length();i++){ if (bitstring.charAt(i)==1') set1.set(i); else set1.clear(i); } // Get the second bit sequence and store it System.out.println(Bit sequence #2:); bitstring=dis.readLine(); for (short i=0;i<bitstring.length();i++){ if (bitstring.charAt(i)==1') set2.set(i); else set2.clear(i); } System.out.println(BitSet #1: +set1); System.out.println(BitSet #2: +set2); // Test the AND operation set3=(BitSet)set1.clone(); set3.and(set2); System.out.println(set1 AND set2: +set3); // Test the OR operation set3=(BitSet)set1.clone(); set3.or(set2); System.out.println(set1 OR set2: +set3); // Test the XOR operation set3=(BitSet)set1.clone(); set3.xor(set2); System.out.println(set1 XOR set2: +set3); } }
The output from this program looks like this:
Bit sequence #1: 1010 Bit sequence #2: 1100 BitSet #1: {0, 2} BitSet #2: {0, 1} set1 AND set2: {0} set1 OR set2: {0, 1, 2} set1 XOR set2: {1, 2}
Table 19.2. The BitSet interface.
Constructors | ||
---|---|---|
BitSet ( ) | Constructs an empty BitSet. | |
BitSet(int) | Constructs an empty BitSet of a given size. |
Methods | |
---|---|
and(BitSet) | Logically ANDs the objects bit set with another BitSet. |
clear(int) | Clears a specific bit. |
clone() | Creates a clone of the BitSet object. |
equals(Object) | Compares this object against another BitSet object. |
get(int) | Returns the value of a specific bit. |
hashCode() | Returns the hash code. |
or(BitSet) | Logically ORs the objects bit set with another BitSet. |
set(int) | Sets a specific bit. |
size() | Returns the size of the set. |
toString() | Converts bit values to a string representation. |
xor(BitSet) | Logically XORs the objects bit set with another BitSet. |
In addition to extending the java.lang.Object class, BitSet implements the java.lang.Cloneable interface.
This class is used to represent dates and times in a system-independent fashion. For example, the current date or a specific date can be printed as shown in Listing 19.2.
import java.util.Date; public class Date1{ public static void main (String args[]){ Date today=new Date(); System.out.println(Today is +today.toLocaleString()+ (+today.toGMTString()+)); Date birthday=new Date(89,10,14,8,30,00); System.out.println(My birthday is+ birthday.toString()+ (+birthday.toGMTString()+)); Date anniversary=new Date(Jun 21, 1986); System.out.println(My anniversary is + anniversary+ (+anniversary.toGMTString()+)); } }
The output from this program looks like this:
Today is 01/21/96 19:55:17 (22 Jan 1996 01:55:17 GMT) My birthday is Thu Nov 14 08:30:00 1989 (14 Nov 1989 14:30:00 GMT) My anniversary is Sat Jun 21 00:00:00 1989 (21 Jun 1986 05:00:00 GMT)
The default constructor is used when the current date and time are needed. A specific date and time can be used to initialize a Date object using the constructors that take three, five, and six integers. These constructors allow the date and time to be specified using YMD, YMDHM, or YMDHMS. Any parts of the time not specified by the three- and five-integer constructors will be set to zero.
NOTE |
---|
Date/time formats can be conveniently summarized using notations of the form YMD, YMDHMS, HMS, or MDY. These abbreviated formats indicate in what order the various numeric parts of the date will appear. Each letter refers to a specific component of the date/time: year (Y), month (M), day (D), hour (H), minute (M), and second (S). Whether the letter M refers to month or minute depends on the context. |
Alternately, a Date object can be constructed using a single string that represents a date and time using a variety of different syntax. One of the most important is the international standard date syntax of the form, Sun, 14 Aug 1995 9:00:00 GMT. Continental U.S. time zone abbreviations are understood, but time zone offsets should be considered for general usefor example, Sun, 14 Aug 1995 9:00:00 GMT+0600 (six hours west of the Greenwich meridian). The local time zone is assumed if none is supplied.
The date can be converted to a text representation using the methods toString(), toGMTString(), and toLocaleString(), which convert the date and time to the standard UNIX, GMT, or local time formats, respectively. When a date is being converted to a string by an automatic coercion, the toString() method will be used.
The Date class also has methods for setting and querying the date and time component values once the Date object is constructed. The individual parts of the date (month, date, year) and time (hours, minutes, seconds) always are specified in local time. When referring to the various parts of the date and time, the first letter of each part typically is used as an abbreviation. For example, YMDHMS would be used to indicate that all six parts (year, month, date, hour, minute, second) are present. Each of these parts of the date and time have a specific range of acceptable values, as illustrated in Table 19.3.
Year | Year minus 1900 |
Month | 0-11 (January=0) |
Date | 1-31 |
Day | 0-6 (Sunday=0) |
Hour | 0-23 |
Minute | 0-59 |
Second | 0-59 |
The date and time also can be specified using a single integer UTC value that represents the number of milliseconds that have elapsed since a specific starting date (which might vary from system to system). For UNIX systems this date is January 1, 1970. The program Date2 in Listing 19.3 shows how this single value corresponds to the normal YMDHMS representation.
import java.util.Date; public class Date2{ public static void main (String args[]){ Date beginning=new Date(0); Date anniversary=new Date(Jun 21, 1986); Date today=new Date(); System.out.println(beginning+=+beginning.getTime()); System.out.println(anniversary+=+anniversary.getTime()); System.out.println(today+=+today.getTime()); } }
The output from this program looks like this:
Wed Dec 31 18:00:00 1969=0 Sat Jun 21 00:00:00 1986=519714000000 Sun Jan 21 19:55:17 1996=822275717000
Dates can be compared to each other by using this UTC value or by using the methodsafter(), before(), or equals().
Table 19.4 summarizes the complete interface of the Date class.
Table 19.4. The Date interface.
Constructors | |
---|---|
Date() | Constructs a date using todays date and time. |
Date(long) | Constructs a date using a single UTC value. |
Date(int, int, int) | Constructs a date using YMD. |
Date(int, int, int, int, int) | Constructs a date using YMDHM. |
Date(int, int, int, int, int, int) | Constructs a date using YMDHMS. |
Date(string) | Constructs a date from a string. |
Static Methods | |
---|---|
UTC(int, int, int, int, int, int) | Calculates a UTC value from YMDHMS. |
parse(string) | Returns the single UTC value of a date in text format. |
Methods | |
---|---|
after(Date) | True if the date is later than the specified date. |
before(Date) | True if the date is earlier than the specified date. |
equals(Object) | True if the date and the specified date are equal. |
getDate() | Returns the day of the month. |
getDay() | Returns the day of the week. |
Hours() | Returns the hour. |
inutes() | Returns the minute. |
onth() | Returns the month. |
econds() | Returns the second. |
ime() | Returns the time as a single UTC value. |
imezoneOffset() | Returns the time zone offset, in minutes, for this locale. | ear() | Returns the year after 1900. |
hashcode() | Computes a hash code for the date. |
setDate(int) | Sets the date. |
setHours(int) | Sets the hours. |
setMinutes(int) | Sets the minutes. |
setMonth(int) | Sets the month. |
setSeconds(int) | Sets the seconds. |
setTime(long) | Sets the time using a single UTC value. |
setYear(int) | Sets the year. |
toGMTString() | Converts a date to text using Internet GMT conventions. |
toLocaleString() | Converts a date to text using locale conventions. |
toString() | Converts a date to text using UNIX ctime() conventions. |
This class implements a pseudo-random number data type used to generate a stream of seemingly random numbers. To create a sequence of different pseudo-random values each time the application is run, create the Random object as follows:
Random r=new Random();
This will seed the random generator with the current time. On the other hand, consider the following statement:
Random r=new Random(326); // Pick any value
This will seed the random generator with the same value each time, resulting in the same sequence of pseudo-random numbers each time the application is run. The generator can be reseeded at any time using the setSeed() method.
Pseudo-random numbers can be generated by using one of the functions: nextInt(), nextLong(), nextFloat(), nextDouble(), or nextGaussian(). For example, the program Random1 in Listing 19.4 will print out five pseudo-random uniformly distributed values using these functions.
import java.lang.Math; import java.util.Date; import java.util.Random; class Random1 { public static void main(String args[]) throws java.io.IOException { int count=6; Random randGen=new Random(); System.out.println(Uniform Random Integers); for (int i=0;i<count;i++) System.out.print(randGen.nextInt()+ ); System.out.println(\n); System.out.println(Uniform Random Floats); for (int i=0;i<count;i++) System.out.print(randGen.nextFloat()+ ); System.out.println(\n); System.out.println(Gaussian Random Floats); for (int i=0;i<count;i++) System.out.print(randGen.nextGaussian()+ ); System.out.println(\n); System.out.println(Uniform Random Integers [1,6]); for (int i=0;i<count;i++) System.out.print((Math.abs(randGen.nextInt())%6+1)+ ); System.out.println(\n); } }
The output from the preceding program looks like this:
Uniform Random Integers 1704667569 -1431446235 1024613888 438489989 710330974 -1689521238 Uniform Random Floats 0.689189 0.0579988 0.0933537 0.748228 0.400992 0.222109 Gaussian Random Floats -0.201843 -0.0111578 1.63927 0.205938 -0.365471 0.626304 Uniform Random Integers [1,6] 4 6 1 6 3 2
If you need to generate uniformly distributed random integers within a specific range, the output from nextInt(), nextLong(), or nextDouble() can be scaled to match the required range. A simpler approach is to take the remainder of the result of nextInt() divided by the number of different values plus the first value of the range. For example, if the values 10 to 20 are needed one can use the formula nextInt()%21+10. Unfortunately, though this method is much simpler than scaling the output of nextInt(), it only is guaranteed to work on truly randomvalues. Because the pseudo-random generator might have various undesired correlations, the modulus operator might not provide acceptable resultsone might get all odd numbers, for example.
Table 19.5 summarizes the complete interface of the Random class.
Table 19.5. The Random interface.
Constructors | |
---|---|
Random() | Creates a new random number generator. |
Random(long) | Creates a new random number generator using a seed. |
Methods | |
---|---|
nextDouble() | Returns a pseudo-random uniformly distributed Double. |
nextFloat() | Returns a pseudo-random uniformly distributed Float. |
nextGaussian() | Returns a pseudo-random Gaussian distributed Double. |
nextInt() | Returns a pseudo-random uniformly distributed Int. |
nextLong() | Returns a pseudo-random uniformly distributed Long. |
setSeed(long) | Sets the seed of the pseudo-random number generator. |
Refer also to Random().
The StringTokenizer class breaks up a string into tokens. The delimiter set can be specified when the StringTokenizer object is created or can be specified on a per-token basis. The default delimiter set is the set of whitespace characters. For example, the StringTokenizer1 code in Listing 19.5 prints out each word of the string on a separate line.
import java.io.DataInputStream; import java.util.StringTokenizer; class StringTokenizer1 { public static void main(String args[]) throws java.io.IOException { DataInputStream dis=new DataInputStream(System.in); System.out.println(Enter a sentence: ); String s=dis.readLine(); StringTokenizer st=new StringTokenizer(s); while (st.hasMoreTokens()) System.out.println(st.nextToken()); } }
The output from this listing will look like this:
Enter a sentence: Four score and seven Four score and seven
The method countTokens() returns the number of tokens remaining in the string using the current delimiter setthat is, the number of times nextToken() can be called before generating an exception. This is an efficient method because it does not actually construct the substrings that nextToken() must generate.
In addition to extending the java.lang.object class, the StringTokenizer class implements the java.util.Enumeration interface. Table 19.6 summarizes the methods of the StringTokenizer class.
Table 19.6. The StringTokenizer interface.
Constructors | |
---|---|
StringTokenizer(string) | Constructs a StringTokenizer given a string using whitespace as delimiters. |
StringTokenizer(string, string) | Constructs a StringTokenizer given a string and a delimiter set. |
StringTokenizer(string, string, boolean) | Constructs a StringTokenizer given a string and a delimiter set. |
Methods | |
---|---|
countTokens() | Returns the number of tokens remaining in the string. |
hasMoreTokens() | Returns True if more tokens exist. |
nextToken() | Returns the next token of the string. |
nextToken(string) | Returns the next token, given a new delimiter set. |
hasMoreTokens() | Returns True if more elements exist in the enumeration. |
nextElement() | Returns the next element of the enumeration using the currentdelimiter set. |
The Vector class implements a dynamically allocated list of objects. It attempts to optimize storage by increasing the storage capacity of the list when needed by increments larger than just one object. With this mechanism, there typically is some excess capacity in the list. When this capacity is exhausted, the list is reallocated to add another block of objects at the end of the list. Setting the capacity of the Vector object to the needed size before inserting a large number of objects will reduce the need for incremental reallocation. Because of this mechanism, it is important to remember that the capacity (available elements in the Vector object) and the size (number of elements currently stored in the Vector object) usually are not the same.
For example, in Figure 19.2, a Vector with capacityIncrement equal to three has been created. As objects are added to the Vector, new space is allocated in chunks of three objects. After five elements have been added, there still will be room for one more element without the need for any additional memory allocation. After the sixth element has been added, there is no more excess capacity. When the seventh element is added, a new allocation will be made that adds three additional elements, giving a total capacity of nine. After the seventh element is added, there will be two remaining unused elements.
FIGURE 19.2.Vector objects with varying number of elements.
The initial storage capacity and the capacity increment both can be specified in the constructor. Even though the capacity is automatically increased as needed, the ensureCapacity() method can be used to increase the capacity to a specific minimum number of elements, whereas trimToSize() can be used to reduce the capacity to the minimum needed to store the current elements. New elements can be added to the Vector using the addElement() and insertElementAt() methods. The elements passed to be stored in the Vector must be derived from type Object. Elements can be changed using the setElementAt() method. Removal of elements is accomplished with the removeElement(), removeElementAt(), and removeAllElements() methods. Elements can be accessed directly using the elementAt(), firstElement(), and lastElement() methods, whereas elements can be located using the indexOf() and lastIndexOf() methods. Information about the size and the capacity of the Vector are returned by the size() and capacity() methods respectively. The setSize() method can be used to directly change the size of the Vector.
For example, the Vector1 code in Listing 19.6 creates a Vector of integers by adding new elements to the end. It then, using a variety of techniques, prints the Vector.
import java.lang.Integer; import java.util.Enumeration; import java.util.Vector; class Vector1 { public static void main(String args[]){ Vector v=new Vector(10,10); for (int i=0;i<20;i++) v.addElement(new Integer(i)); System.out.println(Vector in original order using an Enumeration); for (Enumeration e=v.elements();e.hasMoreElements();) System.out.print(e.nextElement()+ ); System.out.println(); System.out.println(Vector in original order using elementAt); for (int i=0;i<v.size();i++) System.out.print(v.elementAt(i)+ ); System.out.println(); // Print out the original vector System.out.println(\nVector in reverse order using elementAt); for (int i=v.size()-1;i>=0;i--) System.out.print(v.elementAt(i)+ ); System.out.println(); // Print out the original vector System.out.println(\nVector as a String); System.out.println(v.toString()); } }
The output from this program looks like this:
Vector in original order using an Enumeration 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Vector in original order using elementAt 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Vector in reverse order using elementAt 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Vector as a String [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
NOTE |
---|
The expression new Integer() was used to create integer objects to store because the fundamental types, such as int, are not objects in Java. This technique is used many times throughout this chapter. |
Notice the use of the Enumeration object as one way to access the elements of a Vector. Look at the following lines:
for (Enumeration e=v.elements();e.hasMoreElements();) System.out.print(e.nextElement()+ );
One can see that an Enumeration object that represents all of the elements in the Vector is created and returned by the Vector method elements(). With this Enumeration object, the loop can check to see if there are more elements to process using the Enumeration method hasMoreElements() and can get the next element in the Vector using the Enumeration method nextElement().
The Vector2 program in Listing 19.7 illustrates some of the vector-accessing techniques. It first generates a vector of random integers, then allows the user to search for a specific value. The location of the first and last occurrences of the value is printed by the program using the indexOf() and lastIndexOf() methods.
import java.io.DataInputStream; import java.lang.Integer; import java.lang.Math; import java.util.Enumeration; import java.util.Random; import java.util.Vector; class Vector2 { public static void main(String args[]) throws java.io.IOException { int numElements; DataInputStream dis=new DataInputStream(System.in); Vector v=new Vector(10,10); Random randGen=new Random(); System.out.println(How many random elements? ); numElements=Integer.valueOf(dis.readLine()).intValue(); for (int i=0;i<numElements;i++) v.addElement(new Integer(Math.abs( randGen.nextInt())%numElements)); System.out.println(v.toString()); Integer searchValue; System.out.println(Find which value? ); searchValue=Integer.valueOf(dis.readLine()); System.out.println(First occurrence is element + v.indexOf(searchValue)); System.out.println(Last occurrence is element + v.lastIndexOf(searchValue)); } }
The output from this program looks like this:
How many random elements? 10 [0, 2, 8, 4, 9, 7, 8, 6, 3, 2] Find which value? 8 First occurrence is element 2 Last occurrence is element 6
In addition to extending the java.lang.Object class, the Vector class implements the java.lang.Cloneable interface. Table 19.7 summarizes the methods of the Vector class.
Variables | |
---|---|
capacityIncrement | Size of the incremental allocations, in elements. |
elementCount | Number of elements in Vector. |
elementData | Buffer where the elements are stored. |
Constructors | |
---|---|
Vector() | Constructs an empty vector. |
Vector(int) | Constructs an empty vector with the specified storage capacity. |
Vector(int, int) | Constructs an empty vector with the specified storage capacity and capacityIncrement. |
Methods | |
---|---|
addElement(Object) | Adds the specified object at the end of the Vector. |
capacity( ) | Returns the capacity of the Vector. |
clone( ) | Creates a clone of the Vector. |
contains(Object) | True if the specified object is in the Vector. |
copyInto(Object[]) | Copies the elements of this vector into an array. |
elementAt(int) | Returns the element at the specified index. |
elements( ) | Returns an Enumeration of the elements. |
ensureCapacity(int) | Ensures that the Vector has the specified capacity. |
firstElement( ) | Returns the first element of the Vector. |
indexOf(Object) | Returns the index of the first occurrence of the specified object within the Vector. |
indexOf(Object, int) | Returns the index of the specified object within the Vector starting the search at the index specified and proceeding toward the end of the Vector. |
insertElementAt(Object, int) | Inserts an object at the index specified. |
isEmpty( ) | True if the Vector is empty. |
lastElement( ) | Returns the last element of the Vector. |
lastIndexOf(Object) | Returns the index of the last occurrence of the specified object within the Vector. |
lastIndexOf(Object, int) | Returns the index of the specified object within the Vector starting the search at the index specified and proceeding toward the beginning of the Vector. |
removeAllElements( ) | Removes all elements of the Vector. |
removeElement(Object) | Removes the specified object from the Vector. |
removeElementAt(int) | Removes the element with the specified index. |
setElementAt(Object, int) | Stores the object at the specified index in the Vector. |
setSize(int) | Sets the size of the Vector. |
size( ) | Returns the number of elements in the Vector. |
toString( ) | Converts the Vector to a string. |
trimToSize( ) | Trims the Vectors capacity down to the specified size. |
Refer also to Vector, Hashtable.
This class implements a Last In, First Out (LIFO) stack of objects. Even though it is based on (extends) the Vector class, Stacks are typically not accessed in a direct fashion. Instead, values are pushed onto and popped off of the top of the stack. The net effect is that values that were most recently pushed are the first ones to be popped. For example, the Stack1 code in Listing 19.8 pushes strings onto the stack, and then retrieves them. The strings will end up being printed in the reverse order that they were stored.
import java.io.DataInputStream; import java.util.Stack; import java.util.StringTokenizer; class Stack1 { public static void main(String args[]) throws java.io.IOException { DataInputStream dis=new DataInputStream(System.in); System.out.println(Enter a sentence: ); String s=dis.readLine(); StringTokenizer st=new StringTokenizer(s); Stack stack=new Stack(); while (st.hasMoreTokens()) stack.push(st.nextToken()); while (!stack.empty()) System.out.print((String)stack.pop()+ ); System.out.println(); } }
The output from this program looks like this:
Enter a sentence: The quick brown fox jumps over the lazy dog dog lazy the over jumps fox brown quick The
Even though Stack objects normally are not accessed in a direct fashion, it is possible to search the Stack for a specific value using the search() method. It accepts an object to find and returns the distance from the top of the Stack where the object was found. It will return -1 if the object is not found.
The method peek() will return the top object on the Stack without actually removing it from the Stack. The peek() method will throw an EmptyStackException if the Stack has no items.
Table 19.8 summarizes the complete interface of the Stack class.
Constructors | |
---|---|
Stack( ) | Constructs an empty Stack. |
Methods | ||
---|---|---|
empty( ) | True if the Stack is empty. | |
peek( ) | Returns the top object on the Stack. | |
pop( ) | Pops an element off the Stack. | |
push(Object) | Pushes an element onto the Stack. | |
search(Object) | Finds an object on the Stack. |
This class is an abstract class that is used as a base for the Hashtable class. It implements a data structure that allows a collection of key and value pairs to be stored. Any type of object can be used for the keys or the values. Typically, the keys are used to find a particular corresponding value. Figure 19.3 illustrates a Dictionary where product codes and names are stored.
FIGURE 19.3.Example of a Dictionary object.
Because this class is an abstract class that cannot be used directly, the code examples presented cannot actually be run. They are presented only to illustrate the purpose and use of the methods declared by this class. The following code would, hypothetically, be used to create aDictionary with these values illustrated:
Dictionary products = new Dictionary(); products.put(new Integer(342), Widget); products.put(new Integer(124), Gadget); products.put(new Integer(754), FooBar);
The put() method is used to insert a key and value pair into the Dictionary. The two arguments both must be derived from the class Object. The key is the first argument and the value is the second.
A value can be retrieved using the get() method and a specific key to find. It returns the null value if the specified key is not found. For example:
String name = products.get(new Integer(124)); if (name != null) { System.out.println(Product name for code 124 is + name); }
While an individual object can be retrieved with the get() method, sometimes it is necessary to access all of the keys or all of the values. There are two methods, keys() and elements(), that will return Enumerations that can be used to access the keys and the values, respectively.
Table 19.9 summarizes the complete interface of the Dictionary class.
Table 19.9. Dictionary interface.
Constructors | |
---|---|
Dictionary( ) | Constructs an empty Dictionary. | Methods |
elements ( ) | Returns an Enumeration of the values. |
get(Object) | Returns the object associated with the specified key. |
isEmpty( ) | True if the Dictionary has no elements. |
keys( ) | Returns an Enumeration of the keys. |
put(Object, Object) | Stores the specified key and value pair in the Dictionary. |
remove(Object) | Removes an element from the Dictionary by its key. |
size( ) | Returns the number of elements stored. |
Refer also to Enumeration, Hashtable, Properties.
This class implements a hash table storage mechanism for storing key and value pairs. Hash tables are designed to quickly locate and retrieve information stored using a key. Keys and values may be of any object type but the key objects class must implement the hashCode() and equals() methods.
The example Hashtable1 in Listing 19.9 creates a Hashtable object and stores 10 key and value pairs using the put() method. It then uses the get() method to return the value corresponding to a key entered by the user.
import java.io.DataInputStream; import java.lang.Integer; import java.lang.Math; import java.util.Random; import java.util.Hashtable; class Hashtable1 { public static void main(String args[]) throws java.io.IOException { DataInputStream dis=new DataInputStream(System.in); int numElements=10; String keys[]={Red,Green,Blue,Cyan,Magenta, Yellow,Black,Orange,Purple,White}; Hashtable ht; Random randGen=new Random(); ht=new Hashtable(numElements*2); for (int i=0;i<numElements;i++) ht.put(keys[i],new Integer(Math.abs( randGen.nextInt())%numElements)); System.out.println(ht.toString()); String keyValue; System.out.println(Which key to find? ); keyValue=dis.readLine(); Integer value=(Integer)ht.get(keyValue); if (value!=null) System.out.println(keyValue+ = +value); } }
The output from this program looks like this:
{Cyan=4, White=0, Magenta=4, Red=5, Black=3, Green=8, Purple=3, Orange=4, Yellow=2, ÂBlue=6} Which key to find? Red Red = 5
In addition to the get() method, the contains() and containsKey() methods can be used to search for a particular value or key respectively. Both return True or False depending on whether or not the search was successful. The contains() method must perform an exhaustive search of the table and is not as efficient as the containsKey() method, which can take advantage of the hash tables storage mechanism to find the key quickly.
Because hash tables need to allocate storage for more data than actually is stored, a measurement called the load factor is used to indicate the number of used storage spaces as a fraction of the total available storage spaces. It is expressed as a value between 0 and 100 percent. Typically the load factor should not be higher than about 50 percent for efficient retrieval of data from a hash table. When specifying the load factor in a program, a fractional value in the range 0.0 to 1.0 should be used to represent load factors in the range 0 to 100 percent.
Hash tables can be constructed in three different ways: by specifying the desired initial capacity and load factor, by specifying only the initial capacity, or by specifying neither. If the load factor is not specified, the Hashtable will be rehashed into a larger table when it is full; otherwise it is rehashed when it exceeds the load factor. The constructors will throw an IllegalArgumentException if the initial capacity is less than or equal to zero, or if the load factor is less than or equal to zero.
The clone() method can be used to create a copy (clone) of the Hashtable. However, it creates a shallow copy of the Hashtablethat is, the keys and values themselves are not clones. It overrides the inherited clone() method.
The Hashtable class extends the java.util.Dictionary class and implements the java.lang.Cloneable interface. Table 19.10 summarizes the methods of the Hashtable class.
Table 19.10. The Hashtable interface.
Constructors | |
---|---|
Hashtable( ) | Constructs an empty Hashtable. |
Hashtable(int) | Constructs an empty Hashtable with the specified capacity. |
Hashtable(int, float) | Constructs an empty Hashtable given capacity and load factor. |
Methods | |
---|---|
clear( ) | Deletes all elements from the Hashtable. |
clone( ) | Creates a clone of the Hashtable. |
contains(Object) | True if the specified object is an element of the Hashtable. |
containsKey(Object) | True if the Hashtable contains the specified key. |
elements( ) | Returns an Enumeration of the Hashtables values. |
get(Object) | Returns the object associated with the specified key. |
isEmpty( ) | True if the Hashtable has no elements. |
keys( ) | Returns an Enumeration of the keys. |
put(Object, Object) | Stores the specified key and value pair in the Hashtable. |
rehash( ) | Rehashes the contents of the table into a bigger table. |
remove(Object) | Removes an element from the Hashtable by its key. |
size( ) | Returns the number of elements stored. |
toString( ) | Converts the contents to a very long string. |
Refer also to hashCode, equals.
This class is a Hashtable that can be stored and restored from a stream. It is used to implement persistent properties. It also allows for an unlimited level of nesting by searching a default property list if the required property is not found.
The example program Properties1 in Listing 19.10 creates two Properties lists. One will be the default property list and the other will be the user-defined property list. When the user property list is created, the default Properties object is passed. When the user property list is searched, if the key value is not found, the default Properties list will be searched.
import java.io.DataInputStream; import java.lang.Integer; import java.util.Properties; class Properties1 { public static void main(String args[]) throws java.io.IOException { int numElements=4; String defaultNames[]={Red,Green,Blue,Purple}; int defaultValues[]={1,2,3,4}; String userNames[]={Red,Yellow,Orange,Blue}; int userValues[]={100,200,300,400}; DataInputStream dis=new DataInputStream(System.in); Properties defaultProps=new Properties(); Properties userProps=new Properties(defaultProps); for (int i=0;i<numElements;i++){ defaultProps.put(defaultNames[i], Integer.toString(defaultValues[i])); userProps.put(userNames[i], Integer.toString(userValues[i])); } System.out.println(Default Properties); defaultProps.list(System.out); System.out.println(\nUser Defined Properties); userProps.list(System.out); String keyValue; System.out.println(\nWhich property to find? ); keyValue=dis.readLine(); System.out.println(Property +keyValue+ is + userProps.getProperty(keyValue)+); } }
Notice that the getProperties() method is used instead of the inherited get() method. The get() method only searches the current Properties object. The getProperties() method must be used in order to have the default Properties list searched. An alternative form of the getProperties() method has a second argument that is a default Properties list to search instead of the default specified when the Properties object was created.
The propertyNames() method can be used to return an Enumeration that can be used to index through all of the property names. This Enumeration includes the property names from the default Properties list. Likewise, the list() method, which prints the Properties list tothe standard output, will list all of the properties of the current Properties object and thosein the default Properties object.
Properties objects can be written to and read from a stream using the save() and load() methods respectively. In addition to the output or input stream, the save method has an additional string argument that will be written to the beginning of the stream as a header comment.
The Properties class extends the Hashtable class. Table 19.11 summarizes the methods of the Properties class.
Table 19.11. The Properties interface.
Variables | |
---|---|
defaults | Default Properties list to search. |
Constructors | |
---|---|
Properties( ) | Constructs an empty property list. |
Properties(Properties) | Constructs an empty property list with specified default. |
Methods | ||
---|---|---|
getProperty(string) | Returns a property given the key. | |
getProperty(string, string) | Returns a property given the specified key and default. | |
list(PrintStream) | Lists the properties to a stream for debugging. | |
load(InputStream) | Reads the properties from an InputStream. | .|
propertyNames( ) | Returns an Enumeration of all of the keys. | |
save(OutputStream, string) | Writes the properties to an OutputStream. |
This class acts as a base class for objects that wish to be observed by other objects that implement the Observer interface. An Observable object can notify its Observers whenever theObservable object is modified using the notifyObservers() method. This method accomplishes the notification by invoking the update() method of all of its Observers, optionally passing a data object which is passed to notifyObservers. Observable objects may have any number of Observers.
Table 19.12 summarizes the complete interface of the Observable class.
Table 19.12. Observable interface.
Constructors |
---|
Observable( ) |
Methods | |
---|---|
addObserver(Observer) | Adds an Observer to the observer list. |
clearChanged( ) | Clears an observable change. |
countObservers( ) | Returns the number of Observers. |
deleteObserver(Observer) | Deletes an Observer from the observer list. |
deleteObservers( ) | Deletes all Observers from the observer list. |
hasChanged( ) | True if an observable change occurred. |
notifyObservers( ) | Notifies all observers if an observable change occurred. |
notifyObservers(Object) | Notifies all observers of a specific observable change. |
setChanged( ) | Sets a flag to indicate that an observable change occurred. |
Refer also to Observer.
This chapter has described the classes that make up the Java Utilities package. This package provides complete implementations of some of the most useful data types (other than the fundamental numeric types) and the basic data structures needed by programmers. Many of the data types and data structures that you will develop using Java will be based on the classes found in the Utilities package. This chapter should be a good starting point for understanding the utility of these important Java classes and for understanding how to use them effectively.