Moving back to the world of Java, we see that it is a high-level programming language and that bytecode is the low-level machine language of the JVM. Java is an object-oriented language; that is, it deals primarily with objects and their interrelationships. Objects are best thought of in this context as a collection of data ( fields , in Java parlance) and the functions ( methods ) which operate on that data. Objects are created at run time based on templates ( classes ) defined by the programmer.
A Java source file may contain definitions for one or more classes. During compilation each of these classes results in the generation of a single class file. In some respects, the class file is the Java equivalent of an object module rather than an executable program file; that is, it contains compiled machine code, but may also contain references to methods and fields which exist in other classes and hence in other class files.
Class files are the last stage of the development process in Java. There is no separate link phase. Linking is performed at run time by the JVM. If a reference is found within one class file to another, then the JVM loads the referenced class file and resolves the references as needed.
The astute reader will deduce that this demand loading and linking requires the class file to contain information about other class files, methods and fields which it references, and in particular, the names of these files, fields and methods.
Even more astute readers may be pondering some of the following questions.
• Is it possible to compile Java source code to some machine language other than that of the JVM?
• Is it possible to compile some other high-level language to bytecode for the JVM?
• Is there such a thing as an assembler for Java?
• What is the relationship between the Java language and bytecode?
The simple answer to the first three questions is yes.
It is possible with the appropriate compiler (generally referred to as a native code compiler) to translate Java source code to any other low-level machine code, although this rather defeats the Write Once, Run Anywhere proposition for Java programs, since the resultant executable program will only run on the platform for which it has been compiled.
It is also possible to compile other high-level languages into Java bytecode, possibly via an interim step in which the source code is translated into Java source code which is in turn compiled. Bytecode compilers already exist for Ada, COBOL, BASIC and NetREXX (a dialect of the popular REXX programming language).
Finally, Jasmin is a freely available Java assembler which allows serious geeks to write Java code at a level one step removed from bytecode. Java Grinder 2 is a another freely available Java assembler and disassembler and is very simple to use. Let’s consider the following Java code:
Figure (Part 1 of 2). Count.java
Figure (Part 2 of 2). Count.java
We compile this code using the Java compiler: javac Count.java
This command produces the Count.class file. This is a simple Java program that counts the number of characters in a file. The file name is given as an argument on the command line. If the Count program is able to count the characters in the file, it prints the number of characters counted, and if not, it prints the exception. We run this program against this sample text file, called itso.txt:
Both the Count.class and itso.txt files are stored in the same directory, say D:\itso\ch05, and we launch the command:
java Count itso.txt This is the output we receive:
Hi! We counted 70 chars
On disassembling the class file with the freely available software Java Grinder, we get an output file, which is shown in the following figures:
Figure . Disassembled Count.class File
Figure. Disassembled Count.class File
On assembling it again, we get the same functioning as the original class file.
Notice that even if someone changes your code by simply changing the message:
Hi! We counted count chars
to something undesirable like:
Hi! Guess what else I did to this program
the result can be disturbing. It is possible to manipulate it even further and add statements that can vary from serious things like reading files from your system to merely annoying things like throwing up continuous messages. Class files are most vulnerable when they are in transit along the information superhighway. There are ways to help prevent or at least detect this tampering. The Java 2 SDK provides tools for sealing classes in JAR files.
The following figure gives a pictorial model of how different languages, such as COBOL, C++, NetREXX and Java, are compiled in different ways.
Figure . Compiler Models