Chapter 10

java : The Java Interpreter


CONTENTS


The Java runtime interpreter (java) is the component of the Java Developer's Kit used to run executable Java bytecode classes. The Java interpreter provides a means to run Java programs outside of a conventional Web browser. In this chapter, you learn about the Java interpreter, including how to use it and what options it provides for executing Java classes.

Overview

The Java runtime interpreter is a stand-alone version of the Java interpreter built into Java-compatible Web browsers, such as Netscape Navigator. The runtime interpreter provides the support to run Java executable programs in the compiled bytecode class format. Because the interpreter doesn't directly provide any means to view graphical output, you are limited to using it to execute purely textual Java programs and applications that manage their own graphics. If you want to run graphical Java applets, you need to use either the Java applet viewer or a Java-compatible Web browser. The Java applet viewer is covered in the next chapter, "Using the Applet Viewer."

You can think of the runtime interpreter as exposing the bare essentials of the Java runtime system. Even though I use the term "bare essentials," the interpreter actually lets you do quite a lot. Essentially, you can run any Java programs that don't rely on the Applet class. In fact, the statement earlier about not being able to run graphical programs isn't entirely true; you can run graphical Java applications-you just can't run Java applets. The difference between a Java application and a Java applet is that an application is responsible for creating and maintaining its own window if it requires the need for graphical output, whereas an applet relies on a Web browser to provide a window on which to display graphics. So, the Java interpreter is capable of executing both textual Java programs and graphical Java applications.

Usage

The runtime interpreter is a command-line tool for running Java programs and applications; Java applets require the graphics and display support of a Web browser. The syntax for using the Java runtime interpreter follows:

java Options Classname Arguments

The Classname argument specifies the name of the class you want to execute. If the class resides in a package, you must fully qualify the name. For example, if you want to run a class called SolveIt that is located in a package called Equations, you would execute it in the interpreter like this:

java Equations.SolveIt

When the Java interpreter executes a class, what it is really doing is executing the main method of the class. The interpreter exits when the main method and any threads created by it are finished executing. The main method accepts a list of arguments that can be used to control the program. Following is the definition of the main method as specified by the Java language:

class DoIt {
  public static void main(String argv[]) {
    // do something
  }
}

Notice that main has a single parameter, argv, which is an array of String objects. This brings us to the Arguments argument for the runtime interpreter, which specifies the arguments passed into the main method. Any arguments passed to the runtime interpreter by Arguments are accessible from the argv parameter in main. The following interpreter call passes two numeric arguments to the main method in the DoIt class:

java DoIt 8 24

Options

The Options argument specifies options related to how the runtime interpreter executes the Java program. Following is a list of the most important runtime interpreter options:

-debug
-checksource or -cs
-classpath Path
-mx x
-ms x
-noasyncgc
-noverify
-ss x
-oss x
-t
-verbose or -v
-verbosegc
-verify
-verifyremote
-DPropertyName=NewValue

The -debug option starts the interpreter in debugging mode, which enables you to use the Java debugger (jdb) in conjunction with the interpreter. To learn more about using the Java debugger, check out Chapter 15, "jdb: The Java Debugger."

The -checksource option causes the interpreter to compare the modification dates of the source code files and executable class files. If the source file is more recent, the class is automatically recompiled and the new bytecode executable is loaded.

The Java interpreter uses an environment variable, CLASSPATH, to determine where to look for user-defined classes. The CLASSPATH variable contains a semicolon-delimited list of system paths to user-defined Java classes. Actually, most of the Java tools use the CLASSPATH variable to know where to find user-defined classes. The -classpath option informs the runtime interpreter to override CLASSPATH with the path specified by Path.

The -mx option enables you to modify the maximum size of the memory allocation pool, or garbage collection heap, used by the interpreter. By default, the pool has a maximum size of 16 megabytes (-mx 16m). x specifies the new maximum size of the pool, and it is measured in bytes by default. You also can specify x in either kilobytes or megabytes by appending the letter k or m respectively onto the value. Also, x must be greater than 1,000 bytes, meaning that the pool must have a maximum size of at least 1,000 bytes.

The -ms option is similar to the -mx option, except that it enables you to modify the initial size of the memory allocation pool rather than the maximum size. By default, the size of the pool is initially set to 1 megabyte (-ms 1m). x specifies the new initial pool size and is measured in bytes by default. As with the -mx option, you also can specify x in either kilobytes or megabytes by appending the letter k or m respectively onto the value. Additionally, x must be greater than 1,000 bytes.

The Java runtime system typically performs garbage collection automatically to make sure unneeded memory stays freed up. This takes place in an asynchronous thread that runs alongside other threads in the runtime system. The -noasyncgc option alters this behavior by turning off asynchronous garbage collection. The result is that no garbage collection takes place unless it is explicitly called upon or the Java program runs out of memory. Incidentally, an explicit garbage collection can be forced by calling the gc method in the System class.

The -noverify option turns all code verification off, meaning that no bytecodes are processed by the bytecode verifier. Typically, the verifier verifies code loaded into the system using a class loader.

Every thread in the Java runtime system is given two stacks, one for Java code and one for C/C++ code. The presence of two stacks reflects the native code support in Java. The -ss option enables you to alter the maximum stack size used by C code in a thread. The default C stack size is 128 kilobytes (-ss 128k). The x parameter specifies the new maximum size in bytes of the C stack, which must be greater than 1,000 bytes. You also can specify x in either kilobytes or megabytes by appending the letter k or m onto the value, respectively. Keep in mind that this option applies to all threads created during program execution.

Similar to the -ss option, the -oss option enables you to set the maximum stack size that can be used by the Java code in a thread. The default Java code stack size is 400 kilobytes (-oss 400k). The x parameter specifies the new maximum size in bytes of the Java stack, which must be greater than 1,000 bytes.

The -t option prints a trace of the bytecode instructions executed. This option works only with the non-optimized version of the Java interpreter, java_g. You learn about the non-optimized interpreter in a moment. The -t option generates a great deal of information that can give you a lot of insight into what is happening within a program. Of course, it would help if you had some understanding of Java bytecodes.

The -verbose option causes the interpreter to print a message to standard output each time a Java class is loaded. Similarly, the -verbosegc option causes the interpreter to print a message each time a garbage collection is performed. A garbage collection is performed by the runtime system to clean up unneeded objects and to free memory.

The opposite of the -noverify option, the -verify option causes the interpreter to run the bytecode verifier on all code loaded into the runtime environment. The default function of the verifier is to only verify code loaded into the system using a class loader. This default behavior also can be explicitly specified using the -verifyremote option.

The -D option enables you to redefine property values. PropertyName specifies the name of the property you want to change, and NewValue specifies the new value you want to assign to it.

The Non-Optimized Interpreter

Some distributions of the Java Developer's Kit include an alternate Java interpreter called java_g. This is a non-optimized version of the Java interpreter that executes Java bytecodes in a manner more suitable for debugging. If this interpreter is in your JDK distribution, be sure to use it when you are executing code within the Java debugger.

Bugs

The latest release of the Java Developer's Kit, which as of this writing is 1.02, contains some known bugs. More specifically, the following Java runtime interpreter bugs, which apply only to the Windows 95/NT platform, have been documented and acknowledged by the JavaSoft development team:

The first bug is a pretty big problem and occurs whenever a program starts or creates multiple threads; any program that starts multiple threads will not exit. Fortunately, there is a workaround for this bug: either call System.exit when the last running thread is finished, or monitor the threads by calling Thread.join and force an exit yourself. Keep in mind that this problem, along with all the interpreter bugs, is apparent only on the Windows 95/NT platform.

The NaN constant defined in the Float and Double classes represents a result that isn't a number. Because NaN isn't a number, any numeric comparisons made with it should always return false. However, the second bug causes the runtime interpreter to evaluate NaN as less than NEGATIVE_INFINITY, which allows for comparisons with it to return true.

The last two bugs listed deal with converting doubles to integer numbers. More specifically, Double.MAX_VALUE doesn't result in Integer.MAX_VALUE or Long.MAX_VALUE when converted to an integer or long, respectively.

Summary

In this chapter, you found out what the Java runtime interpreter is used for, along with what kind of Java programs can be executed with it. You learned about the main function, which is where execution begins in a Java program. You then learned how to use the interpreter and how to specify different options to custom-tailor the execution of Java programs to fit your needs. The chapter finished up by taking a look at some of the bugs present in the current release of the Java interpreter, and how you can get around them.