by Mark Wutka
Of all the Java API packages, java.lang is the most important. It contains classes that provide a solid foundation for the other Java packages. It is safe to say that the java.lang package is the one package in Java that does not require any other packages to exist.
The java.lang package includes the following classes:
In addition to these classes, the java.lang package defines two interfaces:
The Object class is the base class of every class in Java. It defines the methods that every class in Java supports.
You should already be aware that the == operator only tells whether two objects are really the same object. This is not the same as testing whether the objects contain the same information. The equals method in the Object class enables you to define a way to tell if two objects contain the same information. For instance, you and I might both own the same model of car, but myCar == yourCar is not truethey are two different objects. However, if you test this with myCar.equals(yourCar), they would contain the same information. The format of the equals method is:
public boolean equals(Object ob)
Listing 27.1 shows an example class with an equals method that does an attribute-by-attribute comparison of two objects:
Listing 27.1 Source code for EqualityTest.java.
public class EqualityTest
{
protected String someName;
protected int someNumber;
protected Object someObject;
public boolean equals(Object otherOb)
{
EqualityTest other;
// First, test to see if these are the same object
if (otherOb == this) return true;
// Next, make sure the other object is the same class
if (!(otherOb instanceof EqualityTest)) return false;
// Cast otherOb to this kind of object (EqualityTest) for accessing
// the attributes.
other = (EqualityTest) otherOb;
// Now, compare each attribute of the objects to see if they are equal.
// Notice that on primitive data types like int you should use ==
if (someName.equals(other.someName) &&
(someNumber == other.someNumber) &&
(someObject.equals(other.someObject))) return true;
// Looks like they are not the same object, so the compare result is false
return false;
}
}
Many times, especially during debugging, you need to print out an object to an output stream. The toString method in Object was created just for this purpose. The format of toString is:
public String toString()
The default implementation of toString prints out the objects class name and its hash code. You may want to provide additional information in your own objects. For instance, if you defined an Employee object, you might want the toString method to print out the employees ID number:
public String toString()
{
return Employee #+this.employeeID;
}
The toString method is a convenience for creating a string representation of objects. It is not intended to be a mechanism for saving all of the information for an object, thus there is no corresponding fromString method.
The clone method creates a duplicate copy of an object. In order for an object to be cloned, it must support the Cloneable interface. The Cloneable interface does not have any methods itselfit serves only as an indicator to show that an object may be cloned. An object can choose to implement Cloneable but still not support the cloning operation by throwing a CloneNotSupportedException in the clone method. The format for the clone method is:
protected Object clone()
throws CloneNotSupportedException, OutOfMemoryError
Because the clone method copies only primitive data types and references to objects, there are times when you will need to create your own clone method. For example, take the following class:
public class StoogesFilm extends Object implements Cloneable
{
public String[] stooges;
public StoogesFilm()
{
stooges = new String[3];
stooges[0] = "Moe";
stooges[1] = "Larry";
stooges[2] = "Curly";
}
}
The default clone method for StoogesFilm copies only the reference to the stooges array. Unfortunately, if the newly cloned object decides that Shemp will be the third stooge instead of Curly and thus changes the stooges array, it will change for both copies:
StoogesFilm film1 = new StoogesFilm(); // Create a StoogesFilm
System.out.println(The third stooge in film 1 is +film1.stooges[2]);
StoogesFilm film2 = (StoogesFilm) film1.clone(); // Create a copy of the first film
film2.stooges[2] = Shemp; // Substitute Shemp for Curly
System.out.println(The third stooge in film 1 is now +film1.stooges[2]);
System.out.println(The third stooge in film 2 is +film2.stooges[2]);
The output from this code segment would be:
The third stooge in film 1 is Curly
The third stooge in film 1 is now Shemp
The third stooge in film 2 is now Shemp
You can solve this problem by creating a clone method that clones the stooges array:
public Object clone() throws CloneNotSupportedException
{
// Create an initial clone of the object using the default clone method
StoogesFilm returnValue = (StoogesFilm)super.clone();
// Now create a separate copy of the stooges array
returnValue.stooges = (String[])stooges.clone();
return returnValue;
}
After you add this method, the output from the previous code segment becomes:
The third stooge in film 1 is Curly
The third stooge in film 1 is now Curly
The third stooge in film 2 is now Shemp
The finalize method is called in an object when it is about to be removed from memory by the garbage collector. Normally, your objects will not need a special finalize method, but if you have allocated resources outside of the Java virtual machine (usually via native methods) you may need to implement a finalize method to free up those resources. The format of the finalize method is:
protected void finalize() throws Throwable
A typical finalize method would look like:
protected void finalize() throws Throwable
{
super.finalize(); // ALWAYS do this in a finalize method
// (other code to free up external resources)
}
The notion of serializing objects appears in version 1.1 of the Java API. Object serialization refers to the storage and retrieval of the data stored in the object. You would use object serialization to save the contents of an object in a file or to send an object over a network. You can protect attributes from being serialized. For instance, you may have a handle to an open file, which may not make sense when the object is retrieved on some other system. You can mark attributes as being transient, which will prevent the system from serializing them. For example, suppose you have an InputStream that you do not want to be serialized. You can declare it as transient:
public transient InputStream myStream;
// Dont serialize this attribute
The hashCode method in an object returns an integer that should be fairly unique for each object. The hashCode value is used by the Hashtable class when storing and retrieving objects. You can usually just rely on the default implementation, but just in case you decide you have a much better way to compute a hash code for your object, the format for the hashCode method is:
public int hashCode()
A hash table is an associative array that uses non-numeric keys as indices. In other words, its similar to an array whose index values can be something other than numbers. It uses hash codes to group objects into buckets. When it searches for an object, it only searches through the bucket for that objects hash code.
The wait and notify methods provide a way for objects to signal each other when something interesting occurs. For instance, one object might be writing information into an array that another object is reading. The reader calls wait to wait until the writer is finished. When the writer is finished, it calls notify to signal to the reader that it is done. The idea may sound simple, but there are several important items to consider:
The wait method comes in three forms:
public final void wait()
throws InterruptedException, IllegalMonitorStateException
waits forever until a notify is sent.
public final void wait(long timeout)
throws InterruptedException, IllegalMonitorStateException
waits timeout seconds for a notify, then returns.
public final void wait(long timeout, int nano)
throws InterruptedException, IllegalMonitorStateException
waits timeout seconds and nano nanoseconds for a notify, then returns.
The notify method comes in two forms:
public final void notify() throws IllegalMonitorStateException
sends a notification to a thread that is waiting on this object. If multiple threads are waiting, it sends the notification to the thread that has waited the longest.
public final void notifyAll() throws IllegalMonitorStateException
sends a notification to every thread waiting on this object.
Listing 27.2 shows an example use of wait and notify for implementing a signaling system:
Listing 27.2 Source code for Signaler.java.
/**
* This class provides a signaling mechanism for objects.
* An object wishing to send a signal calls the signal method.
* An object receiving the signal would wait for a signal with
* waitForSignal. If there is no signal pending, waitForSignal
* will wait for one. If there are multiple signals sent, the
* class will keep track of how many were sent and will not call
* wait until there are no more pending signals.
* There should only be one object waiting for a signal at any given
* time.
* @version 1.0
* @author Mark Wutka
*/
public class Signaler extends Object
{
protected int signalCount; // the number of pending signals
protected boolean isWaiting; // is an object waiting right now?
protected boolean sentNotify; // Did someone send a notify?
/**
* Creates an instance of a signaler
*/
public Signaler()
{
signalCount = 0; // no pending signals
isWaiting = false; // no one waiting
}
/**
* Sends a signal to the object waiting for a signal.
* @exception Exception if there is an error sending a notification
*/
public synchronized void signal()
throws Exception
{
signalCount++; // Increment the number of pending signals
if (isWaiting) // If an object is waiting, notify it
{
try {
sentNotify = true;
notify();
} catch (Exception IllegalMonitorStateException) {
throw new Exception("Error sending notification");
}
}
}
/**
* Waits for a signal. If there are signals pending, this method will
* return immediately.
*/
public synchronized void waitForSignal()
{
while (signalCount == 0) // If there are no signals
// pending, wait for a signal
{
sentNotify = false;
isWaiting = true; // Yes, someone is waiting
// Want to keep looping until a notify is actually sent, it is possible
// for wait to return without a notify, so use sentNotify to see if we
// should go back to waiting again.
while (!sentNotify)
{
try {
wait();
} catch (Exception waitError) {
// Shouldn't really ignore this, but...
}
}
isWaiting = false; // I'm not waiting any more
}
signalCount--; // one fewer signal pending
}
}
If you are familiar with Javas synchronization method, you may be wondering how notify can ever be called in the Signaler class. If you arent wondering that, either you know the answer or you dont see the problem. The problem is that waitForSignal and signal are both synchronized. If some thread is blocked on the wait call in the middle of the waitForSignal method, the signal method cant be called because of the synchronization lock. The reason why the Signaler class works is that the wait method releases the synchronization lock when it is called and acquires it again when it returns.
You can retrieve the instance of the Class object that corresponds to an objects class using the getClass method:
public final Class getClass()
The Class class contains information that describes a Java class. Every class in Java has a corresponding instance of Class. There is even an instance of Class that describes Class itself. In case you are wondering what would happen if you tried the line:
Class newClass = new Class();
you cant. There is no public constructor for the Class object. You can, however, get a hold of an instance of Class in one of three ways:
The Class class is a very powerful construct that allows you to do things that you cant do in C++. You typically instantiate a class with a statement like this:
Object thingy = new Thingamajig();
Suppose, however, that you would like to create thingy using the name of the class you want to instantiate. You could do something like this:
String vehicleClass = (some string representing a class name)
Object vehicle;
if (vehicleClass.equals(Car)
{
vehicle = new Car();
}
else if (vehicleClass.equals(Airplane)
{
vehicle = new Airplane();
}
This is better, but it is still not flexible enough. Suppose that you add a new class called Train. You do not want to have to add an else if to check for Train. This is where Class comes in. You can perform the equivalent of the code using Class.forName() and Class.newInstance():
Object vehicle;
// First get the class named by vehicleClass
Class whichClass = Class.forname(vehicleClass);
// Now ask the class to create a new instance
vehicle = whichClass.newInstance();
The forName method in Class is defined as:
public static Class forName(String className)
throws ClassNotFoundException
and returns the instance of Class that corresponds to className, or it throws a ClassNotFoundException. The newInstance method is defined as:
public Object newInstance()
throws InstantiationException, IllegalAccessException
and returns a new instance of the class, or throws an exception if there was an error instantiating the class.
You can also use Class to get interesting information about a class:
public String getName()
returns the name of the class.
public boolean isInterface()
returns true if the class is actually an interface.
public Class getSuperclass()
returns the superclass of the class.
public Class[] getInterfaces()
returns an array containing Class instances for every interface the class supports.
public ClassLoader getClassLoader()
returns the instance of ClassLoader responsible for loading this class into the runtime environment.
The String class is one of the most useful classes in the Java API. It enables you to create and manipulate strings of characters. One thing to keep in mind is that Java strings are immutable; in other words, you cannot change the contents of a string. On the surface, this makes the String class look useless. After all, what good is it to create strings that you cant change? The way you manipulate strings in Java is to create new strings based on other strings. In other words, instead of changing the string father to grandfather, you create a new string that is grand + father. The StringBuffer class provides ways to directly manipulate string data.
Java provides a number of string constructors:
public String()
creates an empty string.
public String(String value)
creates a new string that is a copy of value.
public String(char[] value)
creates a new string from the characters in value.
public String(char[] value, int from, int count)
throws StringIndexOutOfBoundsException
creates a new string from the characters in value, starting at offset from that is count characters long.
public String(byte[] value, int hibyte)
creates a new string from the characters in value, using hibyte as the upper 8 bits in each character (remember that Java characters are 16 bits, not 8 as in C).
public String(byte[] value, int hibyte, int from, int count)
throws StringIndexOutOfBoundsException
creates a new string from the characters in value, starting at offset from, count characters long, and using hibyte as the upper 8 bits in each character.
public String(StringBuffer buffer)
creates a new string from the contents of a StringBuffer.
Here is an example of different ways to create the string Foo94":
String foo1 = new String(Foo);
char foochars[] = { F, o, o };
String foo2 = new String(foochars);
char foo2chars[] = { B, a, r, e, F, o, o, t };
String foo3 = new String(foo2chars, 4, 3); // from offset 4, length of 3
byte foobytes[] = { 70, 111, 111 }; // ascii bytes for Foo
String foo4 = new String(fooBytes, 0); // use 0 as upper 8 bits
byte foo2bytes[] = { 66, 97, 114, 101, 70, 111, 111, 116 }; // ascii BareFoot
String foo5 = new String(foo2Bytes, 0, 4, 3); // 0 as upper 8 bytes, offset 4, length 3
StringBuffer fooBuffer = new StringBuffer();
fooBuffer.append(F);
fooBuffer.append(oo);
String foo6 = new String(fooBuffer);
The String class also provides a number of static methods for creating strings from other objects. The following valueOf methods create a string representation from a primitive data type:
public static String valueOf(boolean b);
public static String valueOf(char c);
public static String valueOf(int i);
public static String valueOf(long l);
public static String valueOf(float f);
public static String valueOf(double d);
Some of the valueOf methods are equivalent to other methods in String and Object. For instance:
public static String valueOf(Object ob)
is the same as the toString method in Object. The methods
public static String valueOf(char[] data);
public static String copyValueOf(char[] data);
are the same as the String constructor:
public String(char[] data)
Likewise, the methods
public static String valueOf(char[] data, int from, int count)
public static String copyValueOf(char[] data, int from, int count)
are equivalent to the String constructor:
public String(char[] data, int from, int count)
The length method returns the length of a string:
public int length()
Notice that unlike the length attribute for arrays, length in the String class is a method. The only time you access length as an attribute is on an array. Any time you are using a standard Java class, length will be a method call.
Because strings are Java objects, you can use == and the equals method to compare strings. You should be extremely careful about using == to compare two strings. For instance, in the following code segment:
String a = new String(Foo);
String b = new String(Foo);
the comparison a == b would be false, since a and b are two different objects, even though they have the same value. The comparison a.equals(b) would be true, however, because they both have a value of Foo.
The String class also provides a handy case-free comparison:
public boolean equalsIgnoreCase(String anotherString)
This method compares two strings but ignores the case of the letters, so where Foo.equals(FOO) is false, Foo.equalsIgnoreCase(FOO) is true.
If you want to find out if one string comes before another alphabetically, you can use the compareTo method:
public int compareTo(String anotherString)
This method returns 0 if the two strings are equal, a number less than 0 if the string comes before anotherString, or a number greater than 0 if the string comes after anotherString. For example, foo.compareTo(bar) would return a positive number because foo comes after bar.
You can also compare portions of strings. The startsWith method returns true if the beginning of the string starts with another string:
public boolean startsWith(String anotherString)
A variation on startsWith returns true if the string matches another string starting at a certain position:
public boolean startsWith(String anotherString, int offset)
For instance, barefoot.startsWith(foo, 4) would be true, because foo appears in barefoot starting at Location 4 (remember that string offsets start at 0).
You can also use endsWith to see if a string ends with another string:
public boolean endsWith(String anotherString)
Sometimes you want to compare part of a string with part of another string. You can use regionMatches to do this:
public boolean regionMatches(int from, String anotherString, int otherFrom, int len)
This method compares the characters in the string starting at offset from with the characters in anotherString starting at offset otherFrom. It compares len characters.
You can also do case-free comparisons with an alternate version of regionMatches:
public boolean regionMatches(boolean ignoreCase, int from, String anotherString,
int otherFrom, int len)
The only difference between this version of regionMatches and the previous one is the ignoreCase parameter, which, when set to true, causes the comparison to ignore the case of letters and considers a and A to be equivalent.
Many times you need to find out if a certain string or character is present within a string and, if so, where. The indexOf method searches through a string for a character or string and returns the offset of the first occurrence:
public int indexOf(int ch)
public int indexOf(String anotherString)
These methods return the location in the string where the first match occurred or -1 if the character or string was not found. Because you probably want to search for more than just the first occurrence, you can call indexOf with the starting location for the search:
public int indexOf(int ch, int startingOffset)
public int indexOf(String anotherString, int startingOffset)
The last IndexOf methods perform a similar search, only starting from the end of the string and working backwards:
public int lastIndexOf(int ch)
public int lastIndexOf(String anotherString)
You can also give the starting offset of the search. lastIndexOf searches backwards from the offset:
public int lastIndexOf(int ch, int startingOffset)
public int lastIndexOf(String anotherString, int startingOffset)
The String class provides several methods for extracting sections from a string. The charAt function allows you to get the character at offset index from the string:
public char charAt(int index) throws StringIndexOutOfBoundsException
For example, bar.charAt(1) would return the character a. You can get the entire string as an array of characters using toCharArray:
public char[] toCharArray()
Remember that the array returned by toCharArray is a copy of the characters in the string. You cannot change the contents of the string by changing the array. The substring method returns the portion of a string starting from offset index:
public String substring(int index)
You may also call substring with an ending index. This version of substring returns the portion of the string starting at startIndex and going up to, but not including, endIndex:
public String substring(int startIndex, int endIndex)
throws StringIndexOutOfBoundsException
While its true that you dont actually change strings in Java, there are several methods that create new strings based on the old string. The concat method, for instance, appends a string to the current string and returns the new combined string:
public String concat(String otherString)
The method call foo.concat(bar) would return the string foobar.
The toLowerCase and toUpperCase return copies of a string with all the letters converted to lower and uppercase, respectively:
public String toLowerCase()
public String toUpperCase()
FooBar.toLowerCase() would return foobar, while FooBar.toUpperCase() would return FOOBAR.
The trim method removes the leading and trailing whitespace from a string. Whitespace is made up of spaces, tabs, form feeds, newlines, and carriage returns. In other words, , \t, \f, \n, and \r:
public String trim()
For example, Hi Ceal! .trim() would return Hi Ceal!.
Finally, you can replace all occurrences of one character with another using replace:
public String replace(char oldChar, char newChar)
fooble.replace(o, e) would return feeble.
The StringBuffer class is a workbench for building strings. It contains methods to add new characters to the buffer and then convert the final result to a string. Unlike the String class, when you add characters to a StringBuffer, you do not create a new copy of the StringBuffer. This makes it more efficient for building strings.
The easiest way to create a StringBuffer is using the empty constructor:
public StringBuffer()
You can also create a StringBuffer with an initial length:
public StringBuffer(int length)
Finally, you can create a StringBuffer from a string, where the contents of the string are copied to the StringBuffer:
public StringBuffer(String str)
The insert methods allow you to insert characters, strings, and numbers into a StringBuffer. You can insert a character representation of one of the primitive data types with one of these insert methods:
public StringBuffer insert(int offset, boolean b) throws StringOutOfBoundsException
public StringBuffer insert(int offset, char c) throws StringOutOfBoundsException
public StringBuffer insert(int offset, int i) throws StringOutOfBoundsException
public StringBuffer insert(int offset, long l) throws StringOutOfBoundsException
public StringBuffer insert(int offset, float f) throws StringOutOfBoundsException
public StringBuffer insert(int offset, double d) throws StringOutOfBoundsException
In each of these methods, the offset parameter indicates the position in the StringBuffer where the characters should be inserted. The instance of StringBuffer returned by each of these is not a copy of the old StringBuffer, but another reference to it. You can safely ignore the return value.
You can insert a string into a StringBuffer with:
public StringBuffer insert(int offset, String str)
throws StringOutOfBoundsException
You may also insert a string representation of an object with:
public StringBuffer insert(int offset, Object ob)
throws StringOutOfBoundsException
This method uses the toString method in the Object to create a string representation of the object. Finally, you can insert an array of characters into a StringBuffer with
public StringBuffer insert(int offset, char[] data)
throws StringOutOfBoundsException
For each insert method, there is a corresponding append method that adds characters to the end of a StringBuffer:
public StringBuffer append(boolean b)
public StringBuffer append(char c)
public StringBuffer append(int i)
public StringBuffer append(long l)
public StringBuffer append(float f)
public StringBuffer append(double d)
public StringBuffer append(String str)
public StringBuffer append(Object ob)
public StringBuffer append(char[] data)
A StringBuffer has two notions of length:
The length method returns the total number of characters currently in the buffer:
public int length()
The capacity method returns the maximum capacity of the buffer:
public int capacity()
The StringBuffer automatically grows when you add characters, so why should you be concerned with the capacity? Whenever the buffer grows, it must allocate more memory. If you specify the capacity up front to be at least as large as you expect the string to be, you will avoid the overhead of allocating additional space. The ensureCapacity method tells the StringBuffer the minimum amount of characters it needs to be able to store:
public void ensureCapacity(int minimumAmount)
You can use the setLength method to change the length of a StringBuffer:
public void setLength(int newLength)
throws StringOutOfBoundsException
If the new length is shorter than the previous length, any characters beyond the new length are lost.
You can manipulate individual characters in a StringBuffer using the charAt and setCharAt methods. The charAt method returns the character at a particular offset in the StringBuffer:
public char charAt(int offset)
throws StringIndexOutOfBoundsException
The setCharAt method changes the character at a particular offset in the buffer:
public void setCharAt(int offset, char newChar)
throws StringIndexOutOfBoundsException
The getChars method allows you to copy a range of characters from a StringBuffer into an array of characters. You must specify the beginning and ending offsets in the StringBuffer, the destination array of characters, and the offset in the array to copy to:
public void getChars(int beginOffset, int endOffset, char[] dest, int destOffset)
throws StringIndexOutOfBoundsException
Once you have built up a string in a StringBuffer, you can turn it into a String with the toString method, which overrides the toString method in the Object class:
public String toString()
A thread represents a single thread of execution in a Java program. A thread has an associated Runnable interface, which may be the thread itself. The Runnable interface implements a run method, which contains the code executed by the thread. Think of the thread as a motor that drives a Runnable interface. Threads also have a notion of thread groups, which implement a security policy for threads. You do not want a rogue thread to go around putting other threads to sleep or changing their priority. A thread may only manipulate threads in its own thread group or in a subgroup of its own thread group.
You can create a thread using the empty constructor:
public Thread()
When you create a thread without specifying a Runnable interface, the thread uses itself as the Runnable interface. The default implementation of the run method in the Thread class just returns without doing anything. To specify an alternate Runnable interface, use this variation of the Thread constructor:
public Thread(Runnable target)
When the thread is started, it invokes the run method in target. When you create a thread, it gets added to the thread group of the current thread. If you want the thread to belong to a different group, you must do it when you create the thread:
public Thread(ThreadGroup group, String name)
The name parameter is an optional thread name that you may want to use to be able to tell threads apart. You can pass null as the thread name if you dont feel like naming it. The other thread constructors are combinations of the previous constructors:
public Thread(String name)
public Thread(Runnable target, String name)
public Thread(ThreadGroup group, Runnable target)
public Thread(ThreadGroup group, Runnable target, String name)
The start and stop methods control the initial startup and final ending of a thread:
public synchronized void start()
throws IllegalThreadStateException
public final void stop()
public final void stop(Throwable stopThrowable)
The start method throws an IllegalThreadStateException if the thread is already running. Typically, you stop a thread by calling the stop method with no arguments, which throws a ThreadDeath error to the thread. You can throw something other than ThreadDeath by using the second variation of the stop method. A thread may also throw a ThreadDeath error instead of calling its own stop method.
Sometimes you want to stop a thread but be able to have it start back up where it left off. You can temporarily suspend a threads execution with:
public final void suspend()
When you want the thread to pick back up where it left off, call the resume method:
public final void resume()
Suppose you have an application that does some heavy computation and then does some other work before using the computation. You could split the heavy computation off into its own thread, but then how do you know when it is finished? You use the join method:
public final void join() throws InterruptedException
The following code segment illustrates a possible use of the join method:
Double finalResult; // place for computation thread to store result
Thread computeThread = new HeavyComputationThread(finalResult);
computeThread.start();
// do some other stuff
computeThread.join(); // Wait for the heavy computations to finish
Because you may not want to wait forever, join also supports a timeout value:
public final synchronized void join(long millis)
throws InterruptedException
public final synchronized void join(long millis, int nanos)
throws InterruptedException
These join methods only wait for millis milliseconds, or millis milliseconds + nanos nanoseconds.
If you want your thread to wait for a period of time before proceeding, use the sleep method:
public static void sleep(long millis)
throws InterruptedException
public static void sleep(long millis, int nanos)
throws InterruptedException
These methods suspend execution of the thread for the millis milliseconds, or millis milliseconds and nanos nanoseconds. The sleep method is very often used for animation loops:
public void run()
{
while (true) { // do animation forever
changeCurrentFrame(); // do the next animation frame
repaint(); // redraw the screen
try {
sleep(100); // Wait 100 ms (1/10th of a second)
} catch (InterruptedException insomnia) {
// got interrupted while sleeping
}
}
}
If you have a thread that hogs the CPU by performing a large number of computations, you may want to have it yield the CPU for other threads to get in some execution time. You can do this with the yield method:
public static void yield()
For example, suppose you have a loop like this:
int sum = 0;
for (int i=0; i < 10000; i++) {
for (int j=0; j < 10000; j++) {
sum = sum + (i * j);
}
}
This loop is going to run for a long time, and if it is running as one thread in a larger program, it could hog the CPU for extended periods of time. If you place a call to Thread.yield() after the inner loop, the thread politely relinquishes the CPU occasionally for other thread:
int sum = 0;
for (int i=0; i < 10000; i++) {
for (int j=0; j < 10000; j++) {
sum = sum + (i * j);
}
Thread.yield(); // give other threads a chance to run
}
A Java program usually runs until all of its threads die. Sometimes, however, you have threads that run in the background and perform cleanup or maintenance tasks that never terminate. You can flag a thread as a daemon thread, which tells the Java virtual machine to ignore the thread when checking to see if all the threads have terminated. In other words, a Java program runs until all of its non-daemon threads die. Non-daemon threads are referred to as user threads.
To flag a thread as a daemon thread, use the setDaemon method:
public final void setDaemon(boolean on)
throws IllegalThreadStateException
The on parameter should be true to make the flag a daemon thread or false to make it a user thread. You may change this setting at any time during the threads execution. The isDaemon method returns true if a thread is a daemon thread or false if it is a user thread:
public final boolean isDaemon()
Javas thread scheduling is very simple. Whenever a thread blocksthat is, when a thread either suspends, goes to sleep, or has to wait for something to happenJava picks a new thread from the set of threads that are ready to run. It picks the thread with the highest priority. If more than one thread has the highest priority, it picks one of them. You can set the priority of a thread with the setPriority method:
public final void setPriority(int newPriority)
throws IllegalArgumentException
A threads priority must be a number between Thread.MIN_PRIORITY and Thread.MAX_PRIORITY. Anything outside that range triggers an IllegalArgumentException. Threads are assigned a priority value of Thread.NORM_PRIORITY by default. You can query a threads priority with getPriority:
public final int getPriority()
The Thread class provides a number of static methods to help you examine the current thread and the other threads running in a threads group. The currentThread method returns a Thread object for the currently executing thread:
public static Thread currentThread()
The dumpStack method prints a stack trace for the current thread:
public static void dumpStack()
You can use the countStackFrames method to find out how many stack frames a thread has. This is the number of frames that would be dumped by the dumpStack method:
public int countStackFrames()
Because the countStackFrames method is an instance method, while the dumpStack method is a static method that dumps the current threads stack frame, the following call always returns the number of stack frames that would be dumped by an immediate call to dumpStack:
int numFrames = Thread.currentThread().countStackFrames();
The enumerate method fills an array with all the Thread objects in the current thread group:
public static int enumerate(Thread[] threadArray)
You need to know how many threads will be returned, because you have to allocate the threadArray yourself. The activeCount method tells you how many threads are active in the current thread group:
public static int activeCount()
The program in listing 27.3 displays the threads in the current thread group:
Listing 27.3 Source code for DumpThreads.java.
public class DumpThreads
{
public static void main(String[] args)
{
// Find out how many threads there are right now
int numThreads = Thread.activeCount();
// Allocate an array to hold the active threads
Thread threadArray[] = new Thread[numThreads];
// Get references to all the active threads in this thread group
numThreads = Thread.enumerate(threadArray);
// Print out the threads
for (int i=0; i < numThreads; i++) {
System.out.println("Found thread: "+threadArray[i]);
}
}
}
The ThreadGroup class implements a security policy that only allows threads in the same group to modify one another. For instance, a thread can change the priority of a thread in its group or put that thread to sleep. Without thread groups, a thread could wreak havoc with other threads in the Java runtime environment by putting them all to sleep or, worse, terminating them. Thread groups are arranged in a hierarchy where every thread group has a parent group. Threads may modify any thread in their own group or in any of the groups that are children of their group. You can create a thread group simply by giving it a name:
public ThreadGroup(string groupName)
You can also create a ThreadGroup as a child of an existing ThreadGroup:
public ThreadGroup(ThreadGroup existingGroup, String groupName)
throws NullPointerException
Several of the ThreadGroup operations are identical to Thread operations, except that they operate on all the threads in the group:
public final synchronized void suspend()
public final synchronized void resume()
public final synchronized void stop()
public final void setDaemon(boolean daemonFlag)
public final boolean isDaemon()
You can limit the maximum priority any thread in a group can have by calling setMaxPriority:
public final synchronized void setMaxPriority(int priority)
You can query the maximum priority for a thread group with getMaxPriority:
public final int getMaxPriority()
You can find out the parent of a thread group with getParent:
public final ThreadGroup getParent()
The different enumerate methods let you find out what threads and thread groups belong to a particular thread group:
public int enumerate(Thread[] threadList)
public int enumerate(Thread[] threadList, boolean recurse)
public int enumerate(ThreadGroup[] groupList)
public int enumerate(ThreadGroup[] groupList, boolean recurse)
The recurse parameter in the enumerate methods causes enumerate to trace down through all the child groups to get a complete list of its descendants. You can get an estimate of how many threads and thread groups are active in this group by using activeCount and activeGroupCount:
public synchronized int activeCount()
public synchronized int activeGroupCount()
The Throwable class is not very big, but the part it plays in Java is huge. Every error and exception in Java is a subclass of Throwable. Although you will usually create a subclass of Throwable, you can instantiate one using one of these two constructors:
public Throwable()
public Throwable(String message)
The message parameter is an optional error message that is associated with the throwable. You can fetch a throwables message with the getMessage method:
public String getMessage()
One of the handy features of the Throwable class, especially during debugging, is the printStackTrace method:
public void printStackTrace()
public void printStackTrace(PrintStream stream)
These methods print a traceback of the method calls that led to the exception. The default output stream for the stack trace is System.out. You can use the second version of the method to print to any stream you want, such as System.err. You may have a case where you catch an exception, perform some cleanup work, and then throw the exception for another object to catch. If you throw the exception that you caught, the stack trace shows where the exception originally occurred. If you would prefer the stack trace to show only where the exception was first caughtif you want to hide the lower-level details, for instanceuse the fillInStackTrace method:
public Throwable fillInStackTrace()
The following code segment shows how you can use fillInStackTrace to hide where an exception was originally thrown:
try {
// do something interesting
} catch (Throwable somethingBadHappened) {
// do some cleanup work
throw somethingBadHappened.fillInStackTrace();
}
In this example, a stack trace would show the exception originally being thrown at the point of the fillInStackTrace and not within the try statement or one of the methods it calls.
The System class is a grab bag of useful utility methods that generally deal with the runtime environment. Some of the methods in the System class are also found in the Runtime class.
The System class contains three public data streams that are used quite frequently:
public static InputStream in
public static PrintStream out
public static PrintStream err
C programmers should recognize these as the Java equivalents of stdin, stdout, and stderr. When you are running a Java application, these streams usually read from and write to the window where you started the application. You are probably safest not trying to use the System.in stream within an applet, because different browsers treat the stream differently. As for the System.out and System.err streams, Netscape sends them to the Java console window, while Appletviewer sends them to the window where Appletviewer was started. System.err is typically used for printing error messages, while System.out is used for other information. This is only a convention used by developers. You may, if you desire, print error messages to System.out and print other information to System.err.
The arraycopy method is another frequently used member of the System class:
public static void arraycopy(Object source, int sourcePosition,
Object dest, int destPosition, int length)
throws ArrayIndexOutOfBoundsException, ArrayStoreException
This method provides a quick way to copy information from one array to another. It copies length elements from the array source, starting at offset sourcePosition, into the array dest, starting at offset destPosition. This method saves time over copying elements individually within a loop. For example, consider the following loop:
int fromArray[] = { 1, 2, 3, 4, 5 };
int toArray[] = new int[5];
for (int i=0; i < fromArray.length; i++) {
toArray[i] = fromArray[i];
}
This can be implemented more efficiently using arraycopy:
int fromArray[] = { 1, 2, 3, 4, 5 };
int toArray[] = new int[5];
System.arraycopy(fromArray, 0, toArray, 0, fromArray.length);
If you have ever wondered exactly how many milliseconds have elapsed since midnight GMT on January 1, 1970, the currentTimeMillis method would be more than happy to tell you:
public static long currentTimeMillis()
Other than being the dawning of the Age of Aquarius, there is nothing significant about that particular time, it was just picked as a reference point by the original UNIX wizards. The most common use of the currentTimeMillis function is in determining elapsed time. For example, if you want to figure out how many milliseconds a loop took to execute, get the time before executing the loop, then get the time after executing the loop, and subtract the time values:
long startTime = System.currentTimeMillis(); // record starting time
int sum = 0;
for (int i=0; i < 100000; i++) {
sum += i;
}
long endTime = System.currentTimeMillis(); // record end time
System.out.println(The loop took +
(endTime - startTime) + milliseconds.);
A Java program normally exits when all its user threads finish running. If you have spawned a large number of threads and decide that you want the program to quit, you dont have to kill off all the threadsyou can just make the virtual machine terminate by calling System.exit:
public static void exit(int exitCode)
The exitCode parameter is the exit code used by the virtual machine when it terminates. You should only use this method from Java applications: applets are typically forbidden from calling this method and get a SecurityException thrown back in their face if they try it.
System properties are roughly the Java equivalents of environment variables. When you start a Java program, you can define properties that a Java application can read. The getProperty method returns a string that corresponds to a property or null if the property doesnt exist:
public static String getProperty(String propertyName)
To save you the trouble of having to check for null each time, you can call getProperty with a default value that is returned instead of null if the property isnt set:
public static String getProperty(String propertyName,
String defaultValue)
The program in listing 27.4 illustrates how to use getProperty:
Listing 27.4 Source code for PrintProperty.java.
public class PrintProperty extends Object
{
public static void main(String[] args)
{
String prop = System.getProperty("MyProperty",
"My Default Value");
System.out.println("MyProperty is set to: "+prop);
}
}
When you run the program with the java command, use the -D option to set properties. For example:
java -DMyProperty=Hi There PrintProperty
This command causes the application to print out
MyProperty is set to: Hi There
If you run the program without setting MyProperty, it prints:
MyProperty is set to: My Default Value
The getProperties and setProperties let you query and set the system properties using a Properties class:
public static Properties getProperties()
public static void setProperties(Properties prop)
The garbage collector normally just runs in the background, occasionally collecting unused memory. You can force the garbage collector to run using the gc method:
public static void gc
Similarly, you can force the finalize methods to be executed in objects that are ready to be collected using the runFinalization method:
public static void runFinalization()
When you have a class that calls native methods, you need to load the libraries containing the methods. The loadLibrary method searches through your path for a library matching libname:
public static void loadLibrary(String libname) throws UnsatisfiedLinkError
If you already know the full path name of the library, you can save a little time by calling the load method instead of loadLibrary:
public static void load(String filename) throws UnsatisfiedLinkError
The Runtime class provides many of the same functions as the System class but adds the ability to query the amount of memory available and also to run external programs. The Runtime methods that are the same as the methods in System are:
public void exit(int exitCode)
public void gc()
public void runFinalization()
public synchronized void load(String filename)
throws UnsatisfiedLinkError
public synchronized void loadLibrary(String libname)
throws UnsatisfiedLinkError
The freeMemory and totalMemory methods tell you how much memory is free for you to use and how much memory is available to the Java VM:
public long freeMemory()
public long totalMemory()
The following code segment prints the percentage of memory that is free:
Runtime r = Runtime.getRuntime();
int freePercent = 100 * r.freeMemory() / r.totalMemory();
System.out.println(freePercent + % of the VMs memory is free.);
Even though Java is a wonderful and powerful programming environment, you may occasionally have to run external programs from your application. The exec methods allow you to do just that:
public Process exec(String command) throws IOException
public Process exec(String command, String[] envp) throws IOException
public Process exec(String[] cmdArray) throws IOException
public Process exec(String[] cmdArray, String[] envp) throws IOException
The envp parameter in the exec methods contains environment-variable settings for the program to be run. The strings in envp should be in the form name=value. The instance of the Process class returned by exec allows you to communicate with the external program, wait for it to complete, and get its exit code. The following methods in the Process class return input and output streams for you to send data to and receive data from the external program:
public abstract InputStream getInputStream()
public abstract InputStream getErrorStream()
public abstract OutputStream getOutputStream()
The getInputStream method returns a stream that is hooked to the output of the external program. If the external program was a Java program, the input stream would receive everything written to the external programs System.out stream. Similarly, the getErrorStream returns a stream that is hooked to the error output of the external program, or what would be the System.err for a Java program. The getOutputStream returns a stream that supplies input to the external program. Everything written to this stream goes to the external programs input stream, similar to the System.in stream.
If you want to kill off the external program before it completes, you can call the destroy method:
public abstract void destroy()
If you would rather be polite and let the program complete on its own, use the waitFor method to wait for it to complete:
public abstract int waitFor() throws InterruptedException
The value returned by waitFor is the exit code from the external program. You can also check the exit code with the exitValue method:
public abstract int exitValue() throws IllegalThreadStateException
If the external program is still running, the exitValue method will throw an IllegalThreadStateException.
If the term math class makes you squeamish, you better sit down for this section. The Math class is a collection of useful numeric constants and functions, from simple minimum and maximum functions to logarithm and trig functions.
The min and max functions, which return the lesser and greater of two numbers, come in four flavorsint, long, float, and double:
public static int min(int a, int b)
public static long min(long a, long b)
public static float min(float a, float b)
public static double min(double a, double b)
public static int max(int a, int b)
public static long max(long a, long b)
public static long max(float a, float b)
public static double max(double a, double b)
abs, the absolute value function, which converts negative numbers into positive numbers while leaving positive numbers alone, also comes in four flavors:
public static int abs(int a)
public static long abs(long a)
public static float abs(float a)
public static double abs(double a)
It is difficult to write a good game without a random number generator, so the Math class kindly supplies the random method:
public static synchronized double random()
The random method returns a number between 0.0 and 1.0. Some of the other variations you might want are as follows:
int num = (int)(10.0 * Math.random()); // random number from 0 to 9
int num = (int)(10.0 * Math.random()) + 1; // random number between 1 and 10
Rounding sounds like a simple process, but there are quite a few options available for rounding numbers. First of all, you can round off a float and turn it into an int with:
public static int round(float a)
This code rounds to the closest whole number, which means that 5.4 gets rounded to 5, but 5.5 gets rounded to 6. You can also round off a double and turn it into a long with:
public static long round(double a)
The other rounding functions work exclusively with the double type. The floor method always rounds down, such that Math.floor(4.99) is 4.0:
public static double floor(double a)
Conversely, ceil always rounds numbers up, such that Math.ceil(4.01) is 5.0:
public static double ceil(double a)
Finally, the rint method rounds to the closest whole number:
public static double rint(double a)
One of the most familiar power-related functions is the square root, which is returned by the sqrt method:
public static double sqrt(double a) throws ArithmeticException
You, of course, get an ArithmeticException if you try to take the square root of a negative number. This is a mathematical no-no. The pow function lets raises x to the y power:
public static double pow(double x, double y) throws ArithmeticException
The pow function requires a bit of care. If x == 0.0, y must be greater than 0. If x < 0.0, y must be a whole number. If either of these two conditions is violated, you receive a friendly ArithmeticException as a reminder not to do it again.
The log method returns the natural log of a number:
public static double log(double a) throws ArithmeticException
To refresh your memory, if the natural log of x is equal to y, then the constant e (about 2.718) raised to the y power equals x. For example, the natural log of e is 1.0, since e to the first power equals e. The natural log of 1.0 is 0.0, since e to the zero power is 1 (as it is for any number raised to the zero power). You cannot take the log of 0 or any number less than 0. After all, there is no power you can raise e to and come up with 0. The same is true for negative numbers. Even though you can use the pow method to raise any number to any power, the Math class provides the exp method as a shortcut for raising e to a power:
public static double exp(double a)
The log and exp functions are inverses of each other. In other words, they cancel each other out. In other words, log(exp(x)) == x, for any x. Also, exp(log(x)) == x, for any x > 0 (remember, you cannot take a log of a number <= 0).
The old favorite trig functions of sine, cosine, and tangent are available in the Math class:
public static double sin(double angle)
public static double cos(double angle)
public static double tan(double angle)
These functions take their angle value in radians, which is a number between 0 and 6.2831 (2 * pi). You can convert a degree value to radians by multiplying it by pi/180.0, or 0.017453. Trig angles have a period of 6.2831, which means that some angle x is the same as x + 6.2831, and also the same as x - 6.2831, and generally, x + 6.2831 * any whole number.
The inverse functions of sine, cosine, and tangent are arcsin, arccosine, and arctangent. They are available in the following methods:
public static double asin(double x)
public static double acos(double x)
public static double atan(double x)
public static double atan2(double y, doubly x)
The asin and acos functions return a radian value between -3.1415 and 3.1415. If you prefer to have your radians go from 0 to 6.2831, you can always add 6.2831 to any negative radian value. It doesnt matter to the trig functions. The atan is a little less accurate. It only returns values between -1.5708 and 1.5708 (-pi/2 to pi/2). The atan2 function, however, returns values from -3.1415 to 3.1415. Where the atan function usually takes a ratio of y/x and turns it into an angle, atan2 takes y and x separately. This allows it to make the extra calculations to return an angle in the full -pi to pi range.
The Math class defines the constants PI and E for you since they are used so frequently:
public static final double E;
public static final double PI;
Many Java classes prefer to work with objects and not the primitive data types. The wrapper classes provide object versions of the primitive data types. In addition to making the primitive types look like objects, these wrapper classes also provide methods for converting strings to the various data types and also type-specific methods.
The Character class provides a wrapper for the char data type. In addition, it contains methods for converting characters to numeric digits and vice versa. This class also contains methods for testing whether a character is a letter, digit, etc. The only constructor available for the Character class takes the value of the character it represents as its only parameter:
public Character(char value)
You can use the charValue method to get the char value stored in a Character object:
public char charValue()
The Character class contains many static methods to classify characters:
Method Description
isDigit A numeric digit between 09.
isLetter An alphabetic character.
isLetterOrDigit An alphabetic character or numeric digit.
isLowerCase A lowercase alphabetic character.
isUpperCase An uppercase alphabetic character.
isJavaLetter A letter, $, or _.
isJavaLetterOrDigit A letter, digit, $, or _.
isSpace A space, new line, return, tab, or form feed.
isTitleCase Special two-letter upper and lowercase letters.
Each of these classification methods returns a boolean value that is true if the letter belongs to that classification. For example, isLetter(a) returns true, but isDigit(a) returns false. The toUpperCase and toLowerCase methods return an uppercase or lowercase version of a character:
public static char toUpperCase(char ch)
public static char toLowerCase(char ch)
The Character class also supplies some digit conversion methods to help convert numbers into strings and strings into numbers:
public static int digit(char ch, int radix)
public static char forDigit(int digit, int radix)
The digit method returns the numeric value that a character represents in the specified radix (the radix is the number base, like 10 for decimal or 8 for octal). For instance, Character.digit(f, 16) would return 15. You can use any radix between Character.MIN_RADIX and Character.MAX_RADIX, which are 2 and 36 respectively. If the character does not represent a value in that radix, digit returns -1.
The forDigit method converts a numeric value to the character that would represent it in a particular radix. For example, Character.forDigit(6, 8) would return 6, while Character.forDigit(12, 16) would return c.
The Boolean class is the object wrapper for the boolean data type. It has two constructorsone that takes a boolean value, and one that takes a string representation of a boolean:
public Boolean(boolean value)
public Boolean(String str)
In the second version of the constructor, the value of the Boolean class created is false unless the string is equal to true. The string is converted to lower case before the comparison, so a value of tRuE would set the Boolean object to true. You can retrieve the boolean value stored in a Boolean object with the booleanValue method:
public boolean booleanValue()
The Boolean class even has object wrapper versions of true and false:
public final static Boolean FALSE;
public final static Boolean TRUE;
The valueOf method is an alternate way of creating a Boolean object from a string:
public static Boolean valueOf(String str)
This method is equivalent to the Boolean constructor that takes a string as an argument. You can also fetch boolean system parameters using the getBoolean method:
public static boolean getBoolean(String propName)
This method looks for the property named by propName in the system properties, and if it finds a property with that name, it tries to convert it to a boolean using the valueOf method. If the value of the property is true, the method returns true. If the value of the property is not true, or if there was no such property, this method returns false.
The object wrappers for the int, long, float, and double types are all subclasses of the abstract Number class. This means that any class that expects an instance of a Number may be passed an Integer, Long, Float, or Double class. The four public methods in the Number class are responsible for converting a number to a particular primitive type:
public abstract int intValue();
public abstract long longValue();
public abstract float floatValue();
public abstract double doubleValue();
The Integer class implements an object wrapper for the int data type, provides methods for converting integers to strings, and vice-versa. You can create an Integer object from either an int or a string:
public Integer(int value)
public Integer(String s) throws NumberFormatException
When creating an integer from a string, the Integer class assumes that the radix (number base) is 10, and if the string contains non-numeric characters, you receive a NumberFormatException. Like the getBoolean method in the Boolean class, the getInteger method converts a string from the system properties. If the property is not set, it returns 0 or a default value that you can pass as the second parameter. The default value can be passed either as an int or as an Integer:
public static Integer getInteger(String paramName)
public static Integer getInteger(String paramName, int defaultValue)
public static Integer getInteger(String paramName, Integer defaultValue)
The Integer class also provides methods for converting strings into integers, either as an int or an Integer. You may also specify an alternate radix (number base):
public static int parseInt(String s) throws NumberFormatException
public static int parseInt(String s, int radix) throws NumberFormatException
public static Integer valueOf(String s) throws NumberFormatException
public static Integer valueOf(String s, int radix) throws NumberFormatException
The only difference between parseInt and valueOf is that parseInt returns an int, while valueOf returns an Integer.
You can use the toString method to convert an integer to a string. There are two static versions of the toString method that should not be confused with the instance method toString that is defined for all subclasses of Object. The static methods take an int as a parameter and convert it to a string, allowing you to specify an alternate radix. The instance method toString converts the value of the Integer instance into a base-10 string representation:
public static String toString(int i)
public static String toString(int i, int radix)
Finally, the Integer.MIN_VALUE and Integer.MAX_VALUE constants contain the minimum and maximum values for integers in Java:
public final static int MIN_VALUE
public final static int MAX_VALUE
The Long class is identical to the Integer class, except that it works a wrapper for long values instead of int values. The constructors for Long are:
public Long(long value)
public Long(String s) throws NumberFormatException
You can fetch Long values from the system properties using getLong:
public static Long getLong(String paramName)
public static Long getLong(String paramName, long defaultValue)
public static Long getLong(String paramName, Long defaultValue)
The parseLong and valueOf methods convert strings into long data types and Long objects, respectively:
public static long parseLong(String s) throws NumberFormatException
public static long parseLong(String s, int radix) throws NumberFormatException
public static Long valueOf(String s) throws NumberFormatException
public static Long valueOf(String s, int radix) throws NumberFormatException
The toString static methods convert long data types into strings:
public static String toString(long l)
public static String toString(long l, int radix)
Finally, the Long.MIN_VALUE and Long.MAX_VALUE constants define the minimum and maximum values for long numbers:
public final static long MIN_VALUE
public final static long MAX_VALUE
The Float class provides an object wrapper for the float data type. In addition to string conversions, it provides a way to directly manipulate the bits in a float. You can create a Float by giving either a float, double, or string representation of the number:
public Float(float value)
public Float(double value)
public Float(String s) throws NumberFormatException
The Float class lacks the methods for fetching system properties that are present in the Integer and Long classes, but it does provide methods for converting to and from strings. There is no float equivalent of the parseInt and parseLong methods, however:
public static Float valueOf(String s) throws NumberFormatException
public static String toString(float f)
Floating point numbers have a special notation for infinity, as well as for Not a Number. You can test for these values with isInfinite and isNaN, which come in both static and instance varieties:
public static boolean isInfinite(float f)
public static boolean isNaN(float f)
public boolean isInfinite()
public boolean isNan()
If you have the desire to manipulate the individual bits of a floating point number, you can convert it to an int using the floatToIntBits method:
public static int floatToIntBits(float f)
Both float and double values are stored in IEEE 754 format. This method is probably not very useful to you unless you are familiar with the format, but there are applications that depend on getting a hold of this information. After you have manipulated the bits in the int version of the number, you can convert it back to a float with:
public static float intBitsToFloat(int bits)
You should keep in mind that this bitwise representation is not the same as converting a float to an int. For example, Float.floatToIntBits((float)42) returns an integer value of 1109917696, which is a few orders of magnitude different from the original value.
In addition to the typical MIN_VALUE and MAX_VALUE constants, the Float class also provides constants for NEGATIVE_INFINITY, POSITIVE_INFINITY, and Not a Number, or NaN:
public final static float MIN_VALUE
public final static float MAX_VALUE
public final static float NEGATIVE_INFINITY
public final static float POSITIVE_INFINITY
public final static float NaN
The Double class provides the same functionality as the Float class, except that it deals with the double data type instead of float. You can create a Double using either a double or a string:
public Double(double value)
public Double(String s) throws NumberFormatException
You can convert a double to a string and vice-versa with toString and valueOf:
public static String toString(double d)
public static Double valueOf(String s) throws NumberFormatException
Double also provides methods to check for infinity and Not a Number with static and instance versions of isInfinite and isNan:
public static boolean isInfinite(double d)
public static boolean isNaN(double d)
public boolean isInfinite()
public boolean isNan()
You can manipulate the bits of a double, which are also stored in IEEE 754 format, using the doubleToLongBits and longBitsToDouble methods:
public static long doubleToLongBits(double d)
public static double longBitsToDouble(long bits)
Finally, the Double class also defines its own MIN_VALUE, MAX_VALUE, POSITIVE_INFINITY, NEGATIVE_INFINITY, and NaN constants:
public final static double MIN_VALUE
public final static double MAX_VALUE
public final static double NEGATIVE_INFINITY
public final static double POSITIVE_INFINITY
public final static double NaN
The ClassLoader class contains methods for loading new classes into the Java runtime environment. One of Javas most powerful features is its ability to load new classes on-the-fly. This class, along with the Class class makes dynamic class loading possible. All of the methods in ClassLoader are protected, which means that they are only accessible to subclasses of ClassLoader. In fact, all but one of the methods in ClassLoader are final, leaving a single abstract method to be implemented by the individual class loaders. This abstract method is loadClass:
protected abstract Class loadClass(String className, boolean resolve)
throws ClassNotFoundException
The loadClass method is responsible for finding the class information, whether in a local file or across the network, and creating a class from it. The loadClass method obtains an array of bytes that represent the entire contents of the .class file for the class to be loaded and then calls defineClass to create an instance of Class for the new class:
protected final Class defineClass(byte data[], int offset, int length)
The length parameter is the number of bytes that define the class, and offset is the location of the first byte of the data for the class in the data array.
If the resolve parameter in loadClass is true, the loadClass method is responsible for calling the resolveClass method before returning:
protected final void resolveClass(Class c)
The resolveClass method makes sure that all classes referenced by class c have been loaded and resolved. A class cannot be used until it has been resolved. When a class is resolved, its class loader is responsible for locating any other classes it references. This is not very convenient when a class references java.lang.Object, for instance. Rather than forcing you to write class loaders that know how to load all of the system classes, the ClassLoader class gives you a hook into the system class loader, so if you are unable to locate a class, you can try the system class loader before giving up:
protected final Class findSystemClass(String name)
throws ClassNotFoundException
Listing 27.5 shows a sample class loader that loads classes from an alternate directory.
Listing 27.5 Source code for MyClassLoader.java.
import java.io.*;
import java.util.*;
// This class loader uses an alternate directory for loading classes.
// When a class is resolved, its class loader is expected to be able
// to load any additional classes, but this loader doesn't want to have
// to figure out where to find java.lang.Object, for instance, so it
// uses Class.forName to locate classes that the system already knows
// about.
public class MyClassLoader extends ClassLoader
{
String classDir; // root dir to load classes from
Hashtable loadedClasses; // Classes that have been loaded
public MyClassLoader(String classDir)
{
this.classDir = classDir;
loadedClasses = new Hashtable();
}
public synchronized Class loadClass(String className,
boolean resolve) throws ClassNotFoundException
{
Class newClass = (Class) loadedClasses.get(className);
// If the class was in the loadedClasses table, we don't
// have to load it again, but we better resolve it, just
// in case.
if (newClass != null)
{
if (resolve) // Should we resolve?
{
resolveClass(newClass);
}
return newClass;
}
try {
// Read in the class file
byte[] classData = getClassData(className);
// Define the new class
newClass = defineClass(classData, 0,
classData.length);
} catch (IOException readError) {
// Before we throw an exception, see if the system already knows
// about this class
try {
newClass = findSystemClass(className);
return newClass;
} catch (Exception any) {
throw new ClassNotFoundException(className);
}
}
// Store the class in the table of loaded classes
loadedClasses.put(className, newClass);
// If we are supposed to resolve this class, do it
if (resolve)
{
resolveClass(newClass);
}
return newClass;
}
// This version of loadClass uses classDir as the root directory
// for where to look for classes, it then opens up a read stream
// and reads in the class file as-is.
protected byte[] getClassData(String className)
throws IOException
{
// Rather than opening up a FileInputStream directly, we create
// a File instance first so we can use the length method to
// determine how big a buffer to allocate for the class
File classFile = new File(classDir, className+".class");
byte[] classData = new byte[(int)classFile.length()];
// Now open up the input stream
FileInputStream inFile = new FileInputStream(classFile);
// Read in the class
int length = inFile.read(classData);
inFile.close();
return classData;
}
}
Listing 27.6 shows a simple class for testing the loader:
Listing 27.6 Source code for LoadMe.java.
public class LoadMe extends Object
{
public LoadMe()
{
}
public String toString()
{
return "Hello! This is the LoadMe object!";
}
}
The TestLoader program, shown in listing 27.7, uses MyClassLoader to load the LoadMe class and print it out. It expects the LoadMe.class file to be in a subdirectory called TESTDIR.
Listing 27.7 Source code to TestLoader.java.
//
// This program uses MyTestLoader to load the LoadMe class.
//
public class TestLoader extends Object
{
public static void main(String[] args)
{
// Create the class loader. Note: myLoader must be declared as MyClassLoader
// and not ClassLoader because the loadClass method in ClassLoader is
// protected, not public.
MyClassLoader myLoader = new MyClassLoader("testdir");
try {
// Try to load the class
Class loadMeClass = myLoader.loadClass("LoadMe", true);
// Create a new instance of the class
Object loadMe = loadMeClass.newInstance();
// Print out the string representation of the instance
System.out.println(loadMe);
} catch (Exception oops) {
// If there was an error, just print a whole stack trace
oops.printStackTrace();
}
}
}
The SecurityManager class is one of the keys to Javas security. It contains an assortment of methods to check to see whether a particular operation is permitted. The various Java system classes, such as the Applet class, the network classes, and the file classes, all check with the security manager before performing potentially hazardous operations. If the security manager decides that something is not permitted, it will throw a SecurityException. The System class provides methods for accessing the current security manager and for setting the security manager if one isnt already defined. You may not change security managers once one has been set. These methods are in the System class, not the SecurityManager class:
public static SecurityManager getSecurityManager()
public static void setSecurityManager(SecurityManager)
throws SecurityException
If Java were to remain an interpreted-only language, it would not survive in the business world against compiled languages like C++. Just-In-Time (JIT) compilers give Java that extra speed boost it needs. A JIT compiles methods to native machine instructions before executing them. The compilation only occurs once per method. Some JITs may compile entire classes, rather than one method at a time. The Compiler class lets you exercise a little control over the JIT.
You can ask the JIT to compile a specific class by passing a Class instance to the compileClass method:
public static boolean compileClass(Class clazz)
The compileClass method returns true if the compilation succeeded, or false if either the compilation failed or there is no JIT available. This is useful if you need to invoke a method and you dont want to take the one-time compilation hit when you invoke the method. You ask the JIT to pre-compile the entire class before you start invoking methods.
The compileClasses method is similar to the compileClass method, except that it compiles a set of classes:
public static boolean compileClasses(String classes)
The classes parameter contains the name of the classes you want to compile. This might be something like java.lang.*. You should consult the documentation for your JIT (if it is available) to find out more on this method.
You can selectively disable and enable the JIT compiler with the disable and enable methods:
public static void disable()
public static void enable()
Finally, the command method allows you to pass arbitrary commands to the compiler. This method is JIT-specific, so you should consult the documentation for a particular JIT to find out what commands it supports. The format for the command method is
public static Object command(Object any)
| Previous Chapter | Next Chapter |
| Table of Contents | Book Home Page |
| Que Home Page | Digital Bookshelf | Disclaimer |
To order books from QUE, call us at 800-716-0044 or 317-361-5400.
For comments or technical support for our books and software, select Talk to Us.
© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company