The one Java tool that you have to use constantly is the compiler, javac. This is because your Java source-code files are meaningful only to human readers. Your computer cannot understand them at all. The compiler's job is to take your program and convert it from human-readable form to machine-readable form. You've been using the Java compiler all throughout this book, but in this chapter, you'll learn some new tricks and tips that'll help you get the best results from the compiler.
In languages such a C, a compiler converts source code (the stuff you write) to machine language, which your computer can execute directly. Because every type of computer uses a different form of machine code, programs that must run on different types of machines must be compiled specifically for each machine. For example, a C program compiled on a Windows machine cannot be run on a Macintosh, and vice versa. To run that Windows program on the Macintosh, the program would first have to be compiled by a Macintosh compiler (assuming that the source code was portable, meaning that the code contained no machine -specific instructions).
With Java, however, the compiler converts your source code into byte-code files, which are the same format on every machine. This means that a Java program compiled on a Windows machine will run equally as well on a Solaris or Macintosh machine. This feat of digital magic is possible because the Java byte-code files are not read directly by the machine. Instead, Java's interpreter reads the byte-code files and translates them into machine code for the specific machine on which the Java program is running.
The interpreter does this translation as the applet or application is running, meaning that the whole process is transparent to the user. The interpreter, of course, must be specially written and compiled for each type of machine that wants to run Java programs. Figure 34.1 illustrates this concept. From the user's point of view, though, this simply means that he must have Java installed on his system. The user doesn't need to know anything about the interpreter; it works automatically when the user views an applet in his Web browser.
Figure 34.1 : Because Java programs are interpreted, they can be run on any machine that has a Java interpreter.
As you already know, you can run the Java compiler with a command line that consists of the compiler's name followed by the name of the file to compile, like this:
There are a couple of important things to remember about this command. First, the Java compiler is case-sensitive when it comes to comparing source-code file names with the names of the class contained in the file. For example, if your source-code file is named shapeapplet.java and the class it defines is ShapeApplet, the Java compiler will complain and not compile the file (Figure 34.2).
Figure 34.2 : The source-code file name must match the name of the public class defined in the file.
Second, the compiler requires that you include the source-code file's extension, which should always be .java. Notice that the extension is all lowercase. If you fail to include the extension when running the compiler, or if you fail to save your source-code file with the proper extension, you will get an "invalid argument" error (Figure 34.3). I'm not sure why Java's creators insist upon the file extension being present when you type the javac command line. Most compilers assume the proper file extension when the file name is typed without the extension. Not so with Java. Strange.
Figure 34.3 : A source code name without the proper .java extension is an invalid argument.
Like many of the tools included with java, the compiler recognizes
some command options that you can add to the command line. Table
34.1 lists these command options and their meanings.
|-classpath path||Determines the path in which the compiler looks for classes.|
|-d directory||Determines the directory in which javac stores the output files.|
|-g||Tells javac to create debugging information, which is used by debugging tools.|
|-nowarn||Tells javac not to display warnings as it compiles a file.|
|-O||Tells java to optimize the compiled program.|
|-verbose||Tells javac to display status information as it works.|
To use any of these options, place the options between the javac command and the source file name, like this:
javac options filename.java
In the following sections, you'll look at each of the compiler options in detail. In some cases, you'll even get some hands-on experience.
In order to compile an applet, the compiler usually needs to draw upon other already compiled files. These files might be files that you've created for custom classes or they may be the class files that make up the class hierarchy of the class you're compiling. For example, when you derive your applet from Java's Applet class, the compiler needs to know about the Applet class in order to fully compile your applet. Moreover, because Java's Applet class itself is a subclass of yet other Java classes, the compiler needs to bring in many different class files. Obviously, before the compiler can access these class files, it has to know where they are.
Normally, when you compile a program, the compiler finds classes using the current setting of your system's CLASSPATH variable, whose default value is the folder that contains Java's classes. Java will also look in the active folder (the one you're in when you type the javac command line). However, you can change the setting of CLASSPATH temporarily for the current compilation by using the -classpath option, like this:
javac -classpath path FileName.java
In the above line, path is the path you want to include, each separated by a semicolon. For example, assuming that you installed Java in a folder called C:\JAVA and that your own classes are in the C:\CLASSES folder, the following line compiles your program using the same settings the compiler would use by default:
javac -classpath c:\java\lib\classes.zip;c:\classes FileName.java
Notice that Java's classes are in a file called CLASSES.ZIP. You must include this file name in the path in order for the compiler to find the classes it needs to successfully compile your applet.
When you run javac by typing the javac Applet.java command line, the compiler reads the source-code file (or files), converts it to byte-code form, and stores the resultant .CLASS file in the directory from which the compiler was run. You can control this target directory by specifying the -d command option, like this:
In this command, directory is the directory in which you want the output files (.CLASS files) stored.
Suppose you have your Java source code files (the ones with the .java extension) in a folder called C:\CLASSES, as you have for the applets you've created in this book. Now you want to have the .CLASS files that are created by the Java compiler placed in a subdirectory of CLASSES called COMPILED. You'd first create the subdirectory with the command md compiled. Then you'd issue the following command:
javac -d c:\classes\compiled applet.java
Following the javac command are the -d option, the name of the directory in which to store the output files, and the Java source-code file to compile.
The directory name is either a full path or a path relative to your current directory. For example, if you're current directory is c:\CLASSES, when you type the above command, you can shorten the directory name, like this:
javac -d compiled applet.java
To get the most out of a debugger, your programs need to be compiled in a special way, so that debugging information is included in the compiled byte-code files. The compiler switch that turns this option on is -g, and you use it like this:
javac -g applet.java
As you can see, the only thing extra here is the -g option itself, which requires no additional arguments.
You may decide that it would be cool to use the -g option all the time, so that your programs are always loaded with debugging information. Don't do it. This wouldn't be a good idea because programs with debugging information are not only a bit larger than programs without the debugging information, but also tend to run slower. The larger the program is, the more debugging information the -g option adds to the file.
To test the -g option, copy the ShapeApplet.java file from the CHAP34 folder on this book's CD-ROM to your CLASSES directory. Then, compile the file with the following command:
Now, check the size of the ShapeApplet.class file. It should be 1,334 bytes.
Next, compile the applet again, this time using the -g option, like this:
javac -g ShapeApplet.java
When you check the file size this time, you'll find it's 1,612 bytes, over 20% larger. The extra size is caused by the additional debugging information the compiler has stored in the .CLASS file.
Sometimes, when the Java compiler finds something questionable in your code, it issues a warning. Warnings represent the kind of errors that don't prevent a program from compiling properly, but that may generate a runtime error or just be bad programming practice. Because warnings are not critical to the compilation process, Java enables you to turn them off. You might do this, for example, when you already know about the problems that are creating the warnings. To turn off the warnings, you use the -nowarn option, like this:
javac -nowarn applet.java
Like the -g option, -nowarn requires no additional arguments.
You can use more than one command-line option at a time. For example, you can both turn on debugging information and set the target directory with a command like this: javac -g -d c:\classes applet.java.
When a compiler runs, it reads in source code and converts that source code to some other format, in Java's case, a byte-code file. As a programmer, though, you know that there are many ways to accomplish the same task in a program. A compiler doesn't normally take this sort of thing under consideration when it's working, though. It generates its output the same way for every source-code file.
However, the javac compiler knows how to perform certain types of optimization on your programs, but it only does so when asked. (And don't forget to say pretty please). To tell the Java compiler to optimize your program, you use the -O option, like this:
javac -O applet.java
The -O option requires no arguments.
Notice that the letter after the hyphen is an uppercase O. A lowercase o will not work. Also, be aware that compiling with the optimizing option may make the resulting .CLASS file incompatible with some other Java tools. For this reason, optimizing should be done only when compiling the program for the final time.
When you run the Java compiler with no command-line option, the compiler runs and performs its task without displaying any sort of information on the screen (unless the program contains errors). With a large program that takes a while to compile, you may want to know what's going on behind your back, if for no other reason than to reassure yourself that everything is going okay. You can make the compiler report to you as it works by using the -verbose option, like this:
javac -verbose applet.java
When you add this command-line option, the compiler will tell you which files it's loading and compiling. It'll even tell you how long each step took to complete (Figure 34.4).
Figure 34.4 : When you use the -verbose option, the compiler reports to you every step of the way.
The compiler is one of the most important of the Java tools, because without it you'd be unable to convert your source-code files into byte-code files, which are the only kind of files that Java's interpreter understands. Ordinarily, you can run the compiler simply by typing the command javac followed by the name of the file you want to compile. However, javac also recognizes a number of options that you can add to the command line. These include options to set directories, to optimize the program, to add debugging information, and to display status information as the compiler works. In the next chapter, you learn about the compiler's counter-part, the interpreter, which reads the files created by the compiler in order to run the program.