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 true--they 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 26.1 shows an example class with an equals method that does an attribute-by-attribute comparison of two objects.
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 object's 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 employee's 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 itself--it 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
CAUTION:
Make sure that your finalize method calls super.finalize at some point; otherwise, the resources allocated by the superclass will not be freed correctly.
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; // Don't serialize this attribute
In order for an object to be serialized, it must implement the java.io.Serializable interface. Like the Cloneable interface, the java.io.Serializable interface does not contain any methods. It serves only as a flag to indicate that an object can be serialized. Oddly enough, although the java.io.Serializable interface does not contain any methods, there are two methods you must implement if your object requires custom serialization:
private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
Your readObject and writeObject methods must be declared exactly as they are above. The serialization code contains special checks for these methods. You probably won't have to implement your own readObject and writeObject methods, but it is nice to know that you can if you need to. There are cases where you can take shortcuts in serializing an object, or you may want to prevent certain attributes contained in the object from being serialized, but you don't want to mark those attributes as transient (for instance, you may want the serialization of those attributes to be dependent on the current state of the object).
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, it's 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 object's hash code.
CAUTION:
If you create your own hashCode method, make sure that it returns the same hash value for two objects that are equivalent. The Hashtable class uses the hashCode to help locate equivalent objects, and if the hash values for two objects are different, the Hashtable class assumes that they are different and never even checks the equals method.
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.
CAUTION:
The notify, notifyAll, and wait methods must be called from synchronized methods or synchronized blocks. In addition, notify must be called from a method or block that is synchronized on the same object as the corresponding wait. In other words, if some object, myObject, calls wait and another object calls myObject.notify(), the calling block or method must be synchronized on myObject.
/** * 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 } signalCoun--; // one fewer signal pending } }
If you are familiar with Java's synchronization method, you may be wondering how notify can ever be called in the Signaler class. If you aren't wondering that, either you know the answer or you don't 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 can't 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 object's 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 can't. There is no public constructor for the Class object. You can, however, get 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 can't do in C++. You typically instantiate a class with a statement like this:
Object vehicle = new Car();
Suppose, however, that you would like to create a vehicle 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.
CAUTION:
You can only use newInstance to instantiate objects that provide an empty constructor (a constructor that takes no parameters). If you try to use newInstance to instantiate an object that does not have an empty constructor, you get a NoSuchMethodError error. You should be ready to catch the NoSuchMethodError. Remember that it is an error and not an exception, so just catching Exception will not grab it.
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 Reflection API introduced in Java 1.1 adds a number of methods to the Class class for examining the attributes and methods of a class. These methods are:
public Class[] getInterfaces() public Class getComponentType() public int getModifiers() public Class getDeclaringClass() public Class[] getClasses() public Field[] getFields() throws SecurityException public Method[] getMethods() throws SecurityException public Constructor[] getConstructors() throws SecurityException public Field getField(String name) throws NoSuchFieldException, SecurityException public Method getMethod(String name, Class parameterTypes[]) throws NoSuchMethodException, SecurityException public Constructor getConstructor(Class parameterTypes[]) throws NoSuchMethodException, SecurityException public Class[] getDeclaredClasses() throws SecurityException public Field[] getDeclaredFields() throws SecurityException public Method[] getDeclaredMethods() throws SecurityException public Constructor[] getDeclaredConstructors() throws SecurityException public Field getDeclaredField(String name) throws IllegalArgumentException, SecurityException public Method getDeclaredMethod(String name, Class parameterTypes[]) throws NoSuchMethodException, SecurityException public Constructor getDeclaredConstructor(Class parameterTypes[]) throws NoSuchMethodException, SecurityException
These Reflection API methods are discussed in depth in Chapter 20.
See "Reflection," Chapter 20
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 can't 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 "Foo":
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 lastIndexOf 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 it's true that you don't 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()
NOTE: When you use the toString method in StringBuffer to create a String, the String and the StringBuffer share the same buffer to avoid excess copying. If the StringBuffer is subsequently changed, it first makes a copy of the buffer before making the change.
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 you may want to use to be able to tell threads apart. You can pass null as the thread name if you don't 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.
CAUTION:
Java allows you to catch the ThreadDeath error, which you should only do in the very rare circumstance that a finalize method will not suffice. If you catch ThreadDeath, you must make sure you throw it again; otherwise, your thread will not die.
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 thread's 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 + 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 threads:
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 }
NOTE: You are not required to call yield in order to give other threads a chance to run. Most Java implementations support pre-emptive scheduling, which allow other threads to run occasionally, even when one executes a loop like the previous one. Not all implementations support pre-emptive scheduling, so a strategically placed yield statement will help those implementations run smoothly.
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.
NOTE: The word daemon is pronounced either "day-mon" or "dee-mon." It originated back in the pre-UNIX days and supposedly stood for "Disk And Execution MONitor." Under UNIX, a daemon is a program that runs in the background and performs a useful service, which is similar to the concept of a Java daemon thread.
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 thread's 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()
Java's thread scheduling is very simple. Whenever a thread blocks--that is, when a thread either suspends, goes to sleep, or has to wait for something to happen--Java 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 thread's 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 thread's 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 thread's 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 thread's 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 26.3 displays the threads in the current thread group:
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 throwable's 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 caught--if you want to hide the lower-level details, for instance--use 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.");
NOTE: While it is possible to compute the current date and time using currentTimeMillis, you are much better off using the Date class in java.util to get the current date and time.
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 don't have to kill off all the threads--you can just make the VM terminate by calling System.exit:
public static void exit(int exitCode)
The exitCode parameter is the exit code used by the VM 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 doesn't 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 isn't set:
public static String getProperty(String propertyName, String defaultValue)
The program in Listing 26.4 illustrates how to use getProperty:
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)
See "The Properties Class," Chapter 33
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 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
Unlike the System class methods, the Runtime class methods are not static, which means you must have an instance of Runtime in order to call them. Instead of using new to create an instance, use the Runtime.getRuntime method.
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 VM's 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 program's 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 logarithms and trig functions.
The min and max functions, which return the lesser and greater of two numbers, come in four flavors--int, 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
See "The Random Class," Chapter 33
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 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.
TIP: You can use the pow method to take the Nth root of a number. Just use pow(x, 1.0/N), where N is the root you want to take. For example, to take the square root, use N=2, so pow(x, 1.0/2.0) returns the square root of x. For a cube root, use N=3, or pow(x, 1.0/3.0). But remember that if you use this technique, x must be a positive 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, 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).
TIP: A base-10 logarithm is another common type of logarithm. Where the log of a number is the power you would raise e to, a base-10 logarithm is the power you raise 10 to. The Math class does not provide a log base-10 function, but you can use a simple mathematical property to compute the log base-10. The property is this: "The log base-N of a number is the natural log of the number divided by the natural log of N". So, the log base-10 of x is log(x) / log(10). If you need to compute the log base-2 of x, another common log, it is log(x) / log(2).
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 doesn't 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. Each of the wrapper classes contains a static attribute named TYPE that contains the wrapper's Class object. The definition for the TYPE attribute in each wrapper class is identical:
public final static Class TYPE;
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, and so on. 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 0-9. |
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. |
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 constructors--one 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 lowercase 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 TRUE public final static Boolean FALSE
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 byte byteValue() public short shortValue() 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.
Many times you will need to convert a string into a number without knowing the number base ahead of time. The decode method understands decimal, hexadecimal, and octal numbers:
public static Integer decode(String str) throws NumberFormatException
The decode method figures out the base by looking at the beginning of the number. If it starts with 0x or 0X, it is assumed to be a hex number. If it starts with 0, the number is assumed to be octal, otherwise the number is assumed to be decimal.
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 Byte class also bears a striking similarity to the Integer class. The Byte class has two constructors:
public Byte(byte value) public Byte(String s) throws NumberFormatException
Unlike the Integer and Long classes, the Byte class does not contain any methods to fetch information from the system properties. You can, however, parse strings into bytes. The parseByte and valueOf methods convert strings into byte data types and Byte objects, respectively:
public static byte parseByte(String s) throws NumberFormatException public static byte parseByte(String s, int radix) throws NumberFormatException public static Byte valueOf(String s) throws NumberFormatException public static Byte valueOf(String s, int radix) throws NumberFormatException
Once again, you can use decode to convert a decimal/hex/octal string into a Byte:
public static Byte decode(String s) throws NumberFormatException
The toString static methods convert byte data types into strings:
public String toString() public static String toString(byte l)
Finally, the Byte.MIN_VALUE and Byte.MAX_VALUE constants define the minimum and maximum values for long numbers:
public final static byte MIN_VALUE public final static byte MAX_VALUE
By this time, you have probably noticed a pattern for the Integer, Long, and Byte classes. The Short class follows this same pattern. In other words, the Short class supports the following methods:
public Short(short value) public Short(String s) throws NumberFormatException public static short parseShort(String s) throws NumberFormatException public static short parseShort(String s, int radix) throws NumberFormatException public static Short valueOf(String s) throws NumberFormatException public static Short valueOf(String s, int radix) throws NumberFormatException public static Short decode(String s) throws NumberFormatException public String toString() public static String toString(short l) public final static short MIN_VALUE public final static short 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 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
To round out the set of wrappers for primitive types, Sun created a Void class. Since a void type contains no information, you might expect that the Void class would have no constructors or methods. Things are exactly as you would expect. The only thing contained in the Void class is the TYPE attribute that is common to all wrapper classes.
Although it is a subclass of Number, the BigInteger class is not a wrapper class for an existing data type. Instead, it implements a large set of arithmetic operations for very large integer numbers. These operations are often used for cryptography applications where you work with numbers containing hundreds or even thousands of bits. BigInteger is not actually a part of the java.lang package, but is instead in java.math, along with the BigDecimal class which implements very large fixed-point numbers.
A BigInteger value is essentially as large as it needs to be. If you need 927 digits, you got it! You can create a BigInteger object in a variety of ways. In the simple case, you can create a BigInteger from an existing long value:
public BigInteger valueOf(long l)
The valueOf method performs the same function as a constructor in that it creates a new instance of a BigInteger. The reason it isn't implemented as a constructor is that it is able to use existing constant BigInteger objects for numbers like 0 and 1.
public BigInteger(String str)
You can create a BigInteger from an array of bytes:
In this case, the array of bytes is really like an array of bits. The leftmost bit in the first byte is the most significant bit in the number. Remember that these bytes are not ASCII representations of digits, they contain the actual number. You can fetch a byte array containing the representation of a BigInteger with:
public byte[] toByteArray()
When performing cryptography, you often need to create a large random number. The BigInteger class has the ability to create such a number:
When you create the random number, the bits parameter indicates the size in bits of the number you are creating. The randomSource object is used to generate the random bits. The resulting number is always positive.
An important aspect of random number generation, especially in the area of cryptography, is the probability that a number is prime. You can generate a random number that has a certain probability of being prime:
public BigInteger(int bits, int certainty, Random randomSource)
This additional certainty parameter indicates how certain the constructor should be that a number is prime. The probability is given as 1 - ( 1 / (2 ^ certainty)). A certainty value of 0 would generate a 0 probability (2 ^ 0 = 1, so the formula is 1 - 1/1), meaning the number is probably not prime. A certainty of 1 generates a probability of 0.5, and a certainty of 10 gives a probability of 0.999 (1 - 1/1024). For this constructor, the bits parameter must be at least 2.
Since there is no built-in support for big numbers in Java, the BigInteger class must provide methods for common numerical operations. Here are the available methods:
public BigInteger add(BigInteger otherValue) public BigInteger subtract(BigInteger otherValue) public BigInteger multiply(BigInteger otherValue) public BigInteger divide(BigInteger otherValue) public BigInteger remainder(BigInteger otherValue) public BigInteger[] divideAndRemainder(BigInteger otherValue) public BigInteger pow(int exponent) public BigInteger gcd(BigInteger otherValue) public BigInteger abs() public BigInteger negative() public BigInteger signum() public BigInteger mod(BigInteger modValue) public BigInteger modPow(BigInteger exponent, BigInteger modValue) public BigInteger modInverse(BigInteger modValue) public BigInteger shiftLeft(numBits) public BigInteger shiftRight(numBits) public BigInteger and(BigInteger otherValue) public BigInteger or(BigInteger otherValue) public BigInteger xor(BigInteger otherValue) public BigInteger not() public BigInteger andNot(BigInteger otherValue) public boolean testBit(int bitNumber) public BigInteger setBit(int bitNumber) public BigInteger clearBit(int bitNumber) public BigInteger flipBit(int bitNumber) public int getLowestSetBit() public int bitLength() public int bitCount() public boolean isProbablePrime(int certainty) public int compareTo(BigInteger otherValue) public boolean equals(Object x) public BigInteger min(BigInteger otherValue) public BigInteger max(BigInteger otherValue)
Finally, you can convert a BigInteger value into a numeric data type, but you may lose precision if the number is too large to fit in the data type:
public int intValue() public long longValue() public float floatValue() public double doubleValue()
The BigDecimal class represents a large, fixed-point number. Like BigInteger, it is also a subclass of Number, but is not a wrapper for a native Java type. A BigDecimal number is similar to a BigInteger number, except that it has an extra scale parameter that indicates how many digits are to the right of the decimal point.
You can create a BigDecimal number from a double, or from a string of digits:
public BigDecimal(double doubleValue) public BigDecimal(String digits)
You can also create a BigDecimal from a BigInteger. You can supply an optional scale parameter that indicates the number of digits to the right of the decimal point. For example, a number 123456789 with a scale of 4 would be the number 12345.6789:
public BigDecimal(BigInteger bigVal) public BigDecimal(BigInteger bigVal, int scale)
You can also create a BigDecimal from a long value with the valueOf method:
public BigDecimal valueOf(long longValue) public BigDecimal valueOf(long longValue, int scale)
One of the issues you must deal with when performing fixed-point calculations is rounding. The BigDecimal class has several different rounding options:
ROUND_DOWN | Always round down |
ROUND_HALF_UP | Round up when last digit >= 5 |
ROUND_HALF_DOWN | Round up when last digit > 5 |
ROUND UP | Always round up |
ROUND_CEILING | Round positive numbers up, negative numbers down |
ROUND_FLOOR | Round positive numbers down, negative numbers up |
ROUND_HALF_EVEN | If the number immediately left of the decimal point is odd, works like ROUND_HALF_UP. If the number to the left of the decimal is even, works like ROUND_HALF_DOWN. |
ROUND_UNNECESSARY | Don't round at all |
Like the BigInteger class, the BigDecimal class must provide methods for common numerical operations. Here are the available methods:
public BigDecimal add(BigDecimal otherValue) public BigDecimal subtract(BigDecimal otherValue) public BigDecimal multiply(BigDecimal otherValue) public BigDecimal divide(BigDecimal otherValue, int roundingMode) public BigDecimal divide(BigDecimal otherValue, int scale, int roundingMode) public BigDecimal abs() public BigDecimal negate() public int signum() public BigDecimal setScale(int scale) public BigDecimal setScale(int scale, int roundingMode) public BigDecimal movePointLeft(int numPositions) public BigDecimal movePointRight(int numPositions) public int compareTo(BigDecimal otherValue) public boolean equals(Object x) public BigDecimal min(BigDecimal otherValue) public BigDecimal max(BigDecimal otherValue)
You can convert a BigDecimal value into a numeric data type, but you may lose precision if the number is too large to fit in the data type:
public int intValue() public long longValue() public float floatValue() public double doubleValue() public BigInteger toBigInteger()
The ClassLoader class contains methods for loading new classes into the Java runtime environment. One of Java's 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 26.5 shows a sample class loader that loads classes from an alternate directory.
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, you don't // have to load it again, but you 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 you 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 you 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, you create // a File instance first so you 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 26.6 shows a simple class for testing the loader.
public class LoadMe extends Object { public LoadMe() { } public String toString() { return "Hello! This is the LoadMe object!"; } }
The TestLoader program, shown in Listing 26.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.
// // 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 Java's 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 isn't 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 don't 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)