The previous chapter gives an overview of the Java API. This chapter explores the java.applet and java.lang packages. The Applet class library-java.applet-controls applets. The Java language class library-java.lang-has two main purposes: to provide functionality for primitive data types and other Java structures and to provide exceptions.
Use this chapter as a guide to help locate more information and to understand the breadth and power of the Java API.
The Applet class is used to create, execute, and stop running applets. It is part of the format and structure that enables applets to run. The Applet class also provides applet-specific methods.
Most of the code in an applet is no different from that in an application. Both use java.lang classes, for example, to do arithmetic functions and string manipulations. Some methods, however, are applet specific and require the presence of a Java-enabled browser. For example, one of these methods is used to retrieve and play an audio clip from across the Net. All the Applet methods are described in the following sections.
More information on these methods can be found in the online API documentation. Be sure to "truth test" the information found in the documentation. Java is a young product, and its methods and classes are still undergoing revision.
The destroy() method schedules with the Java interpreter to notify the garbage collector to sweep up unused resources.
The getAppletContext() method returns the environment in which the applet is running. This is usually the browser or applet viewer name. Listing 10.1 shows the use of the Applet.getAppletContext method.
Listing 10.1. The Applet.getAppletContext method.
import java.applet.*;
import java.awt.*;
public class AnApplet extends Applet {
AppletContext myAppletContext;
public void init() {
//get context in which applet is running
myAppletContext = this.getAppletContext();
//disply status message using context
myAppletContext.showStatus("entering init");
sleep(2000);
}
public void start() {
myAppletContext.showStatus("entering start");
sleep(2000);
}
public void paint(Graphics g) {
g.drawString("Hello World!", 10,20);
sleep(2000);
}
public void sleep (int period) {
try {Thread.sleep(period);}
catch(InterruptedException e) {}
}
}
The getAppletInfo() method returns a string that was passed to it. It is called when the applet information is requested from the applet viewer. I recommend overriding the default information, which is a null value. Listing 10.2 is an example of overriding the getAppletInfo method of java.applet.Applet.
Listing 10.2. Overriding the getAppletInfo method of java.applet.Applet.
import java.applet.*;
import java.awt.*;
public class AnApplet extends Applet implements Runnable {
Thread myThread;
public void start() {
if (myThread == null) {
myThread = new Thread(this);
myThread.start();
}
}
public void stop() {
if (myThread != null) {
myThread.stop();
myThread = null;
}
}
public void run() {
repaint();
}
public String getAppletInfo() {
return("Applet:getAppletInfo; Author:Mr. X; Version:1.0;
ÂCopyright 1996, Macmillan");
}
public void paint (Graphics g) {
g.drawString(getAppletInfo(),10,20);
}
}
The getAudioClip(URL) and getAudioClip(URL, String) methods get an audio clip. Listing 10.3 is an example of the use of these methods. Be sure to read the notes about Java-recognized and -playable audio clips.
Listing 10.3. Retrieving and playing audio clips from across the Internet.
/*
This example will retrieve two audio clips from the Internet.
One it will play in a loop, the other it will play once. They
will play simultaneously.
Notes:
Java only understands how to play .au files that are recorded
as 8Khz, 8bit, mono. Many .au files on the web are 16 bit.
These will not play, but no error messages are generated.
*/
import java.applet.*;
import java.awt.*;
import java.net.*;
import java.awt.image.*;
public class AnApplet extends Applet implements Runnable {
Thread myThread;
String aURL;
URL myURL;
AudioClip myAudioClip;
String errTxt = "Initializing";
int x,y,ix;
MediaTracker mt;
public void start() {
if (myThread == null) {
myThread = new Thread(this);
myThread.start();
}
}
public void stop() {
if (myThread != null) {
this.showStatus("Applet stopped");
myThread.stop();
myThread = null;
}
}
public void run() {
resize(400,400);
// set aURL to audioclip location string
aURL = "http://www.geffen.com/beck/Sounds/paynomind.au";
updateDisplay("running new URL");
// generate URL object using aURL location
try {myURL = new URL(aURL);}
catch(MalformedURLException e) {
updateDisplay("new URL Failure");
this.stop();
}
updateDisplay("running getAudioClip");
myAudioClip = getAudioClip(myURL); // actually retrieve audioclip
if (myAudioClip == null) {
updateDisplay("getAudioClip returned null");
this.stop();
}
updateDisplay("Playing "+aURL);
myAudioClip.loop(); // play audioclip in endless loop
updateDisplay("audo clip complete");
// location of new audio clip
aURL = "http://java.internetone.com/blimp.au";
updateDisplay("running new URL");
// generate URL object using new location
try {myURL = new URL(aURL);}
catch(MalformedURLException e) {
updateDisplay("new URL Failure");
this.stop();
}
updateDisplay("running play");
// play audio clip once. will mix in with already playing clip
play(myURL);
updateDisplay("play complete");
}
public void updateDisplay(String txt) {
errTxt = new String(txt);
this.showStatus(errTxt);
repaint();
}
public void repaint(Graphics g) {
paint(g);
}
public void paint (Graphics g) {
ix+=20;
g.drawString(errTxt,10,ix);
}
public void sleep (int period) {
try {Thread.sleep(period);}
catch(InterruptedException e) {}
}
}
The getCodeBase() method gets the base URL-that is, it returns the directory path in which the applet was started. The code shown in Listing 10.4 uses the Applet.getCodeBase method to return the CodeBase or directory in which the applet was started.
Listing 10.4. Using the Applet.getCodeBase method to return the CodeBase.
import java.applet.*;
import java.awt.*;
public class AnApplet extends Applet {
public void paint(Graphics g) {
g.drawString("This applet is URL - " + this.getCodeBase(), 10,20);
}
}
getDocumentBase gets the document URL. The code shown in Listing 10.5 uses the Applet.getDocumentBase method to print the document base for this applet to the screen.
Listing 10.5. Using the Applet.getDocumentBase method to print the document base.
import java.applet.*;
import java.awt.*;
public class AnApplet extends Applet {
public void paint(Graphics g) {
g.drawString("This applet is embedded in URL - " +
Âthis.getDocumentBase(), 10,20);
}
}
getImage gets an image retrieved from the URL argument location. Listing 10.6 demonstrates the use of the java.applet.Applet.getImage method.
Listing 10.6. Using the java.applet.Applet.getImage method.
/*
This example retrieves a gif image from the Internet and displays it
on the screen. Height and Width return -1 until image has completely
arrived.
*/
import java.applet.*;
import java.awt.*;
import java.net.*;
import java.awt.image.*;
public class AnApplet extends Applet implements Runnable {
Thread myThread;
Image myImage;
URL myURL;
String errTxt = "Initializing";
int x,y;
MediaTracker mt;
public void start() {
if (myThread == null) {
myThread = new Thread(this);
myThread.start();
}
}
public void stop() {
if (myThread != null) {
myThread.stop();
myThread = null;
}
}
public void run() {
// location of image
try {myURL = new URL("http://www.tvp.com/vpttlb.gif");}
catch(MalformedURLException e) {
errTxt = new String("new URL Failure");
this.showStatus(errTxt);
this.stop();
}
myImage = getImage(myURL);// request retrieval of image
if (myImage == null) {
errTxt = new String("getImage returned null");
this.showStatus(errTxt);
this.stop();
}
else {
// create MediaTracker object to monitor retrieval
mt = new MediaTracker(this);
mt.addImage(myImage,1);
// wait for image to arrive
try {mt.waitForID(1);}
catch (InterruptedException e) {}
x = myImage.getWidth(this);// get image width
y = myImage.getHeight(this);// get image height
if ((x != -1) && (y != -1)) {// insure image is complete
resize(x,y);// resize screen to size of image
repaint();
}
}
}
public void paint(Graphics g) {
if (myImage != null) {
g.drawImage(myImage,10,20,this);// draw image on screen
}
else {
g.drawString(errTxt,10,20);
}
}
public void sleep (int period) {
try {Thread.sleep(period);}
catch(InterruptedException e) {}
}
}
The getParameter() method gets a parameter or an array of strings describing the applet. This information should be overridden in applets so that other applets can access the specific information. Listing 10.7 demonstrates the use of the getParameterInfo method from java.applet.Applet.
Listing 10.7. Using the getParameterInfo method from java.applet.Applet.
/*
This example can make use of several http parameters. getParameterInfo
is defined so that if an application queries this applet, it can
find out what the parameters are. The parameters that this applet
accepts are window size (height and width) and a URL of an audioclip
to play.
Note:
getParameterInfo is similar to getAppletInfo in that
it is a method you should override in your class to return the
appropriate information to others that wish to query your applet.
*/
import java.applet.*;
import java.awt.*;
import java.net.*;
public class AnApplet extends Applet implements Runnable {
Thread myThread;
int height, width;
String param, strURL;
URL myURL;
public void init() {
height = 200;
width = 400;
strURL = "http://www.tvp.com/test/test.au";
}
public void start() {
if (myThread == null) {
myThread = new Thread(this);
myThread.start();
}
}
public void stop() {
if (myThread != null) {
myThread.stop();
myThread = null;
}
}
public void run() {
param = getParameter("width");
if (param != null) {
width = Integer.parseInt(param);
}
param = getParameter("height");
if (param != null) {
height = Integer.parseInt(param);
}
param = getParameter("URL");
if (param != null) {
strURL = param;
}
resize(width,height);
try {myURL = new URL(strURL);}
catch(MalformedURLException e){}
play(myURL);
repaint();
}
public String[][] getParameterInfo() {
String paramInfo[][] = {
{ "height", "int", "resize to height pixels" },
{ "width", "int", "resize to width pixels" },
{ "URL", "URL", "play audoclip located at URL" }
};
return(paramInfo);
}
public void paint (Graphics g) {
g.drawString("now playing: "+strURL,10,20);
}
}
After you compile the applet source code, you will need to create an HTML document to view the applet, such as the following sample document:
<HTML>
<HEAD>
<TITLE> The Audio Player Applet </TITLE>
</HEAD>
<BODY>
<APPLET CODE="AnApplet" width=300 height=300>
<PARAM NAME="width" VALUE="200">
<PARAM NAME="height" VALUE="200">
<PARAM NAME="URL" VALUE="http://tvp.com/hello.au">
</APPLET>
</BODY>
</HTML>
Note |
To hear an actual sound file play on your system, you must specify a valid value for the URL parameter. Passing parameters to applets is explored in Chapter 15, "Creating Java-Powered Web Presentations with Applets." |
The init() method initializes the applet. This method is described in detail in Chapter 7, "Building Objects." Most of the examples in this chapter demonstrate its use as well. This method normally should be overridden in code, which allows you to specify precisely how the applet will be ini- tialized.
The play() method plays an audio clip retrieved by getAudioClip. See Listing 10.3 for an example of the use of play.
The resize() method resizes an applet. The dimensions are in pixels. Listing 10.8 is an example of resize.
Listing 10.8. Using the resize method.
/*
This applet uses the Applet.resize method to resize the applet
window to different sizes. The first time it uses int,int as
parameters, the second time it uses a dimension object as a parameter.
*/
import java.applet.*;
import java.awt.*;
public class AnApplet extends Applet implements Runnable {
int x,y;
Dimension d;
Thread myThread;
public void start() {
if (myThread == null) {
myThread = new Thread(this);
myThread.start();
}
}
public void stop() {
if (myThread != null) {
myThread.stop();
myThread = null;
}
}
public void run() {
x = 10;
y = 20;
repaint();
sleep(2000);
this.resize(300,300); // resize(int,int)
x = 10;
y = 40;
repaint();
sleep(2000);
d = new Dimension();
d.width = 200;
d.height = 800;
this.resize(d); // resize(Dimension)
x = 10;
y = 60;
repaint();
}
public void paint(Graphics g) {
g.drawString("Hello World! - " + x + "," + y, x,y);
}
public void sleep (int period) {
try {Thread.sleep(period);}
catch(InterruptedException e) {}
}
}
The setStub() method sets the applet stub. Generally, this function is performed automatically by the system and you will not need to perform this function in your code.
The showStatus() method shows a status message in the applet's context. For example, in Netscape the status message shows up in the status area at the bottom of the browser window. See Listing 10.3 for an example of showStatus.
The start() method starts the applet and the stop() method stops the applet execution. (These methods are discussed in Chapter 7.) The online documentation on start, as well as that on stop and destroy, is misleading. It states that it is not necessary to call these methods explicitly. I have had more predictable results when these methods are called explicitly. See the listings throughout this chapter for examples of the use of the start and stop methods.
isActive() returns true if the applet is active. The status of the method is true immediately before start is executed. See Listing 10.9 for a demonstration of the use of isActive().
Listing 10.9. isActive() displays the boolean value of whether the applet is active.
import java.applet.*;
import java.awt.*;
public class AnApplet extends Applet {
public void paint(Graphics g) {
g.drawString("thisApplet is active = " + this.isActive(), 10,20);
}
}
The java.lang package is so important that it would be just about impossible to do anything in Java without it. This is why it is imported automatically into all applets and applications at compile time. You never need to explicitly import java.lang. The following sections include information about all the first-level classes and a brief description of each. More detailed information about each class is available in the online documentation.
Java's utility classes work with objects only when those objects are used as arguments. However, in Java, booleans are not objects. The Boolean class provides a format to "wrap around" boolean data values to make them acceptable to Java utility classes. This process is referred to as an object wrapper.
Here is an example of a method to convert strings to booleans:
Boolean myBool = Boolean.valueOf("True"); //convert string to Boolean
This declares a new Boolean variable and sets it to the boolean value represented by the string "True". Note two things about this line: First, the variable myBool is declared to be of type Boolean as opposed to type boolean; second, the Boolean class is called directly on the right-hand side of the assignment operator. This can be done when a method is needed without having or needing a corresponding object declared in the program code.
Here is another method that does the opposite: It converts a Boolean variable to a string:
System.out.println("myBool = " + myBool.toString(); //convert Boolean to string
Boolean is a simple class with a limited set of methods. These are probably the two most likely to be used by most programmers.
The Character class works as an object wrapper for characters in the same way that the Boolean class wraps booleans. There are more methods available for this class than for Boolean.
Here is an example of the method used to convert characters to integers of any specified radix:
myInt = Character.digit('b',16); //convert Character to int in specified radix
Because b is the hexadecimal value for 11, the previous example assigns myInt the value 11.
Here are examples of other methods in class Character:
myString = myChar.toString(); //convert myChar to String
if (Character.isLowerCase(myChar)) //test if char is lowercase
myChar = Character.toUpperCase(myChar); //convert to uppercase
if (Character.isUpperCase(myChar)) //test if char is uppercase
myChar = Character.toLowerCase(myChar); //convert to lowercase
if (Character.isSpace(myCharArray[i])) //test if char is white space
I++; &nb sp; //go on to next character
The Class class contains subclasses that return runtime information about classes. Each class instance automatically has Class descriptor objects associated with it.
Here are examples of methods for determining class names and functions:
System.out.println("Class name = " + myClass.getName()); //return class name
//return class name with "class" or "interface" prependedSystem.out.println("Class type/name = " + myClass.toString());
//get superclass of this class
mySuperClass = myClass.getSuperclass();
//test if class is an interface or not
if (myClass.isInterface() == "true")
System.out.println("This object is an interface");
else
System.out.println("This object is a class");
//return all interfaces associated with this class
myClassArray = myClass.getInterfaces();
The ClassLoader class overrides the default structure of Java when loading in classes. The default is defined by the CLASSPATH environment variable and is platform dependent. ClassLoader requests that files and classes be loaded from remote areas such as across the network. It also contains methods for interpreting foreign classes created by defineClass() to be loaded as regular Java classes. ClassLoader is an abstract method and is not called if the default mechanisms are to be followed. This class is used mainly by Java interpreters and debuggers.
Java uses the Compiler class at program compile time. This class includes the following methods:
command(Object)
compileClass(Class)
compileClasses(String)
disable()
enable()
The Java compiler invokes these methods when you compile a Java program.
Number is an abstract superclass for all number classes. It includes the Integer, Long, Float, and Double number classes. Number contains the basic template methods for converting an arbitrary number into an instance of Integer, Long, Float, or Double. The primitive number classes are all based on this class.
Float, Integer, Double, and Long are all object wrappers used to make their respective data types acceptable to operations that require objects. All these data types contain basic methods for converting the corresponding primitive types to and from these classes. They also contain methods for converting between numeric data types as well as for converting to and from String types. The String type is useful for accepting text input of numbers and being able to easily convert the string to a number for processing.
Here are several examples of the various operations available for these data types:
public class MyMain {
public static void main (String args[]) {
Integer myInteger; //declare variables
Double myDouble;
Float myFloat;
Long myLong;
Number myNumber;
String myString;
//Integer constructor
myInteger = new Integer(37);
//Double constructor; conversion Integer to int
myDouble = new Double((double)myInteger.intValue());
//convert Double to string
myString = myDouble.toString();
myLong = Long.valueOf(myString);
System.out.println(myLong);
}
}
Many of the methods associated with these data types may seem extraneous. After all, why provide a method to convert an integer to a string when this is done automatically when using the + operator in conjunction with strings? The reason is that it may be necessary to treat an integer as an object and use an associated method. If a generic class for printing values of objects to a stream is needed, it may be easier to simply pass an object to all subclasses of that class, do the conversion to string, and then print to the stream. By converting a primitive type to an object, you can treat it just like any other possible object rather than make it a special case.
The utility class Math contains the standard Java math library, including such math functions as absolute value, exponents, roots, and trigonometric functions. All methods in this class are static, which means they cannot be subclassed or instantiated. Some aspects of this class, such as out-of-range or immeasurable results, are platform dependent.
Here is an example of using the pow and sqrt functions to create a method that calculates the distance between two points:
static double calcDist(double x1,double y1,double x2,double y2) {
double length;
length = Math.sqrt(Math.pow((x1-x2),2) + Math.pow((y1-y2),2));
return(length);
}
In addition to the standard math functions, there are routines for selecting a value on the basis of a numerical limit. This is done with the min/max and floor/ceil routines. The min and max routines provide a terse method to select the smaller or larger of two numbers, respectively, which can make for more compact code. The following two code fragments accomplish the same thing-setting x equal to the greater of a or b-but the second is obviously much more compact.
if (a > b) { //determine if a > b
x = a; //a is greater, set x equal to a
}
else {
x = b; //b is greater, set x equal to b
}
x = Math.max(a,b); //set x equal to greater of a and b
The floor and ceil routines offer similar compactness. These routines return the next higher or lower whole number for a given value. They are useful in working with graphic coordinates, such as screen displays, that typically require whole numbers.
Using floor and ceil routines allows for more specific control over how fractional numbers are handled. For example, if a calculation is done to draw a polygon, it is important that the lines making up the polygon actually have endpoints that are the same as the next connecting line. If some other method, such as rounding or casting to int, is used, the line coordinates may be off by a single pixel, resulting in an image that does not look quite right-or possibly downright sloppy.
Here is an example of how the floor method could be used:
void clipToRectangle(float x1,y1,int basex) {
z1 = x1/y1
//return the largest whole number less than or equal to z1
z2 = Math.floor(z1);
//insert body of message to make use of z2 value then return to caller
}
One last function worth mentioning in the java.lang.Math
library is random(). This
method generates random numbers, which are used in a variety of
applications from quantum mechanics to shoot-em-up games. The
random() function in Java
returns a double-precision floating-point number
between 0 and 1. By using this value as a multiplier, a random
number between any two limits can be produced. Here is an example
of a method that will produce an integer random number between
any two specified limits:
public static int genRandomInt(int lowerLimit, int upperLimit) {
double tmpNum; //declare temporary variable
tmpNum = upperLimit-lowerLimit; //calculate difference between high and low
tmpNum *= Math.random(); //multiply random value times difference
tmpNum = Math.round(tmpNum); //round to nearest whole number
tmpNum += lowerLimit; //add new value to lower limit
return((int)tmpNum); //cast resulting number to int and return value
}
This code fragment could have been rewritten in a single return but was broken out into several lines to show more clearly how the number was generated.
With random-number library functions, one question that should always be asked is, "How truly random are the numbers produced?" Many random-number generators do not produce very random numbers. So how accurate is the random-number generator in Java's math library? Not very, as it turns out.
Following is a small program to test the random() function. It tests a random number generator by calling it repeatedly to generate numbers between 0 and 99 using the method specified previously. It then stores in an array the number of times each number between 0 and 99 is generated. At the end, it prints out how many of each were actually generated. If random() generates truly random numbers, each number between 0 and 99 should be generated an equal number of times if random is called often enough. This program allows the number of iterations to be specified on the command line:
import java.util.Random;
public class MyMain {
public static void main (String arg[]) {
Random rnd = new Random();
Integer cnt;
int i,j;
int arrIndex = 0;
cnt = Integer.valueOf(arg[0]);
int intArr[] = new int[cnt.intValue()];
for (i=0; i<cnt.intValue(); i++) {
for (j=0; j<100; j++) {
arrIndex = Math.abs(rnd.nextInt() % cnt.intValue());
intArr[arrIndex]++;
}
}
for (i=0; i<cnt.intValue(); i++) {
System.out.println("intArr[" + i + "] = " + intArr[i]);
}
}
}
Testing Java's random-number generator using this program shows that random() is not really very random. Running this with a command-line value of 10,000,000 did not yield very high consistency. This means that the random() function, while quite usable for applications such as games, should not be relied upon for any application in which security might be a concern, such as encryption of critical information.
Object is the class from which all other objects in Java are derived. This class supports a basic set of methods that all subclasses should customize for their own needs. These methods are implemented in the Java class as actual routines, not simply as abstract methods. This is so all subclasses will inherit these routines, ensuring that the methods can be called without causing runtime exceptions. Again, most methods should be overridden in any objects the programmer declares. The methods themselves include methods for comparing, duplicating, and garbage collecting.
To clarify how these work, following is an example based on this simple class:
public class MyObject {
int x,y;
}
This class simply holds two integer variables, x and y. Because all classes are automatically subclasses of the Object class, the base Object methods are inherited by default. Because the methods for comparing objects do not work as you might expect them to, these methods should be overridden, as is shown in the next example.
The first method to look at is the method for comparing two objects, called equals. It is used to determine if all values instantiated in each instance of an object are equal. The method included in the Object class simply checks to see if the two objects are actually the same instance. Any implementation of a class should include a method that compares two different instances to see if they are equal. The following example implements an equals method for class MyObject:
public boolean equals(Object obj) {
return((obj != null) && //does obj point to an object?
(obj instanceof MyObject) && //is obj an instance of MyObject?
(((MyObject)obj).x == x) &&
(((MyObject)obj).y == y)); //do values for x & y match?
}
This method simply returns the results of a series of statements that check various parts of the objects to determine whether they are equal. The first simply checks to ensure that the passed-in object is not null; the second checks that the passed-in object is of type MyObject; and the last tests check whether all variables held in MyObject are of equal value. If all of the checks are validated, the two objects are considered equal and true is returned. If any of these checks fails, false is returned.
The next base method is called clone. Its purpose is to allow the creation of a new instance of an object that is an exact duplicate of the original instance. The default method implemented in the Object class does absolutely nothing. The following example implements a clone method for the MyObject class:
public synchronized Object clone {
MyObject m = new MyObject(); //create new instance of MyObject
m.x = x;
m.y = y; //set x & y values to the same values
return(m); //return clone of object
}
This method creates a new instance of MyObject and then sets the values x and y in the new instance equal to the original values of x and y. Note that because an existing method is being overridden, the declaration must match the original; therefore, the clone method actually returns type Object instead of type MyObject. This method must be synchronized so that the values of x or y do not change in the middle of a call to this method.
The next method is called toString. This method provides a way to represent an object as a string. It is automatically called when an object is included in a print string with the + operator. How this is actually implemented is entirely up to the programmer. For simple objects, this can be as simple as returning a string representation of a few variables. More complex objects may need to print out something far more complex or may simply print out some subset of the data available. Like clone, the default method implemented in the Object class does nothing and should be overridden. The following example shows the implementation for MyObject:
public final synchronized String toString() { //implement toString method
return "[" + x + "," + y + "]"; //print out values of object instance
}
This method simply returns a string containing the values of x and y in square brackets.
The last method to be discussed is called finalize. It is called by the garbage-collection mechanism in Java just before the object is freed. This method should contain any final cleanup, such as closing files and signaling other processes, that an object should do at that time. Not all objects require this final cleanup and so do not necessarily have to implement this method.
The default finalize method implemented in the Object class does nothing, so it will work quite well if nothing special is needed. The class used as an example up to this point does not require a finalize method, but here is an example:
public void finalize() {
x = -1;
y = -1; //set x & y to -1
}
This method simply sets the values of x and y to -1.
The Process class contains methods that control and manipulate subprocesses. It is an abstract class that can be used to get the stand input or stand output of a subprocess. The Process class can also be used to kill a subprocess, wait for a subclass to terminate, and retrieve the final exit value of the process.
Runtime is used by the Java interpreter at application runtime. The Runtime class contains classes and methods to get information about systems at runtime. One method is totalMemory, which returns the number of bytes in system memory. Runtime also has methods that apply to the application currently running. It has a method called gc that runs the garbage collector, but it is best to have the garbage collector run by default unless there are special circumstances.
System classes act as a platform-independent means to do system-level input and output as well as handle errors. The standard input streams are used to read character data. Standard output streams are used to print to the screen. The ubiquitous example of the use of System follows:
System.out.println("Hello World!");
System variables are static.
The following example contains a method named print that prints out the properties of the system it is running on, as well as the total and free available memory:
import java.util.*;
class MyEnv {
public void print() {
//declare properties object
Properties p;
//declare runtime object
Runtime r;
//get properties of system
p = System.getProperties();
//get runtime information
r = Runtime.getRuntime();
//list all properties available
p.list(System.out);
//print os version
System.out.println(System.getProperty("os.version","unkn"));
//print total memory
System.out.println("Total memory = " + r.totalMemory());
//print free memory
System.out.println("Free memory = " + r.freeMemory());
} }
The example class that follows contains a method called runCmd that will run a command passed in as a parameter. The runCmd method will then wait for the command to complete before continuing. If an error occurs during execution of either the exec or waitFor command, System.exit will be used to force the entire application to abort with the indicated exit codes:
import java.io.*;
class MyExec {
public void runCmd(String cmd[]) {
Process p; //declare process object
Runtime r; //declare runtime object
r = Runtime.getRuntime(); //get runtime information
try {
p = r.exec(cmd) ; //execute command
try {
p.waitFor(); //wait for command to complete
}
catch(InterruptedException e) { //handle waitFor failure
System.out.println("ERROR: waitFor failure");
System.exit(10); //exit application with exit code 10
}
}
catch(IOException e) { //handle exec failure
System.out.println("ERROR: exec failure");
System.exit(11); //exit application with exit code 11
}
}
}
This application uses the classes described in this section to actually print information about the system to the screen and to run a command using the exec method. The command can be specified on the command line:
import java.util.*;
import java.io.*;
public class MyMain {
public static void main (String arg[]) {
MyEnv myEnv; //declare MyEnv object
MyExec myExec; //declare MyExec object
myEnv = new MyEnv(); //create MyEnv object
myEnv.print(); //print system information to the screen
myExec = new MyExec(); //create MyExec object
myExec.runCmd(arg); //call runCmd method using command line arguements
}
}
The SecurityManager class is an abstract class. You can create subclasses of it to implement a security policy, such as the one used to manage the security of applets. The applet viewer's security manager is used to restrict the functions of applets and guard against malicious coding.
The key thing to know about security managers is that client applications can have only one security manager. Generally, clients cannot reference or create their own security manager. The security manager is executed when the program starts and cannot be replaced, overridden, extended, or overloaded.
The String class provides methods for representing and manipulating character strings. String values cannot be changed after creation. Each character in a string can be accessed as an array. The following two statements are equivalent:
String string1 = "Ben";
char string2[] = {'B', 'e', 'n'};
The second letter in the string can be extracted by the statement
String e = string1.substring(1, 2);
There are other methods for string manipulation in this class, such as the following:
class StringFun {
public static void main (String args[]) {
String str = "Manipulating strings in Java is easier than you think.";
System.out.println("The value of the string is: " + str);
System.out.println("Length of the string is: " +str.length());
System.out.println("The index of the character J: " +str.indexOf('J'));
System.out.println("The index of the beginning of the substring \"easier\" is:
Â" + str.indexOf("easier"));
System.out.println("The character at position 10: " + str.charAt(10));
System.out.println("The substring from positions 14 to 20: " +
Âstr.substring(14,20));
System.out.println("The string in upper case: " + str.toUpperCase());
}
}
StringBuffer allows strings to be changed and created. Remember, strings normally cannot be changed. There are many methods and constructors used here to manipulate strings. One example follows:
benName = new StringBuffer().append("B").append("e").append("n").toString();
This is similar to using + for string concatenation.
Thread contains methods
for creating, manipulating, and destroying threads. (See Chapter 8,
"Tying It All Together: Threads, Exceptions, and More,"
for more detailed information on threads.)
ThreadGroup contains methods that create, manipulate, and destroy groups of threads.
Throwable methods are used in conjunction with exceptions. This class provides information to trace back through the stack in case of exceptions. It also prints out exception messages.
Remember that java.lang, with all its classes and subclasses, is imported into every program by default. One reason that exceptions are part of the java.lang library is that it is important to be able to test for exceptions in every program.
Exceptions are discussed in Chapter 8.
The full list of exception classes is shown in Table 10.1. They
are listed in hierarchical order, starting at the top of the pyramid.
ClassNotFoundException | Exception | Thrown when a requested class could not be found. |
CloneNotSupportedException | Exception | Thrown when there has been an attempt to clone an unclonable object. |
IllegalAccessException | Exception | Thrown when a requested method could not be accessed. |
InstantiationException | Exception | Thrown when there has been an attempt to instantiate an abstract class or an interface. Interfaces are templates of methods and can never be instantiated. Abstract classes are also intended to be templates. They show the return value and argument types but must be overridden. |
InterruptedException | Exception | Thrown when another thread has interrupted the currently running thread. |
NoSuchMethodException | Exception | Indicates that a requested method could not be found. |
RuntimeException | Exception | Traps for exceptions that occur during the execution of bytecode by the Java Virtual Machine. |
ArrayStoreException | RuntimeException | Thrown during runtime when the user is trying to store the wrong type of object in an array. |
ClassCastException | RuntimeException | Thrown when an invalid cast has occurred. |
IllegalArgumentException | RuntimeException | Indicates that an illegal argument exception has occurred. |
IllegalThreadStateException | IllegalArgumentException | Indicates that a thread is not in the proper state for a requested operation. For example, the thread may not be running when a request is made to it. |
NumberFormatException | IllegalArgumentException | Thrown when an invalid number format has occurred, such as when the user attempts to use a decimal point with a number typed as an integer. |
ArithmeticException | RuntimeException | Thrown when an exceptional arithmetic condition has occurred. This class would be invoked when dividing by zero. |
IllegalMonitorStateException | RuntimeException | Thrown when a monitor operation has been attempted and the monitor is in an invalid state. This could indicate permission problems. |
IndexOutOfBoundsException | RuntimeException | Indicates that an index is out of bounds. This exception is fairly generic in nature. It has two subclasses that are more specific; see next two entries. |
ArrayIndexOutOfBounds Exception | IndexOutOfBoundsException | Indicates that an invalid array index has been used. |
StringIndexOutOfBounds Exception | IndexOutOfBoundsException | Indicates that a String index is out of range. |
NegativeArraySizeException | RuntimeException | Thrown when there has been an attempt to create an array that is negative in size. In other words, the argument to size the array is not a positive integer. |
NullPointerException | RuntimeException | Indicates that there has been an attempt to use a pointer with a null value. It is a good idea to do bounds checking on pointer values before use. |
SecurityException | RuntimeException | Indicates that a security exception has occurred. This is usually an attempt to access classes, methods, or variables that are not public. |
Listing 10.10 is an example of a Java applet that uses the ArrayIndexOutOfBoundsException exception. It shows how the exception is generated, caught, and replaced with a new ArrayIndexOutOfBoundsException, which generates a custom error message.
import java.applet.*;
import java.awt.*;
import java.net.*;
public class AnApplet extends Applet implements Runnable {
Thread myThread;
public void start() { //start running the applet
if (myThread == null) { //create a thread if doesn't exit
myThread = new Thread(this);
myThread.start();
}
}
public void stop() { //stop the applet from running
if (myThread != null) { //if the thread is running, stop it
myThread.stop();
myThread = null;
}
}
public void run() {
int[] arr = new int[10]; //create an array with 11 elements
try {arr[11] = 1;} //access the 12th element in the array
catch(ArrayIndexOutOfBoundsException e) { //in case of this exception
e = new ArrayIndexOutOfBoundsException("Idiot, didn't you do
Âbounds checking on your array accesses?"); //override exception
throw(e); //throw exception message and exit method
}
}
}
This chapter has explored the java.applet.Applet and java.lang packages from the Java API. The java.lang package contains classes associated with basic data structures in Java as well as Java-wide exceptions. Structures such as Boolean and Integer are included as classes in java.lang.
The java.applet package is used to create an applet instance and to perform applet-specific functions. Applets require the presence of a browser or applet viewer, and the Applet methods rely on this environment.