16 Mar 1996


Java doesn't have a preprocessor or header (*.h) files. Previously compiled class files become input when subsequent classes are compiled. To gain access to the classes, fields, and methods of an existing class in the library, a new Java source file uses the import statement.

As with the more widely used %include statements of C, Java import statements are normally grouped together at the beginning of any Java source file:

import java.io.StreamTokenizer

Compiled class files are normally stored in a hierarchical file system. The periods used to qualify the class name are replaced by "/" or "\" so that each component except the last is treated as a directory. The final name becomes the dataset name. Thus the previous import statement searches for "java/io/StreamTokenizer.class" from within the class library directories configured to the Interpreter.

The effect of the import statement is to define the referenced class name to the current program, as if the class definition itself had appeared. After this statement, StreamTokenizer is a defined name associated with a class. The leading "java.io." is used to find the class, but it doesn't become part of the symbol structure. This means that class names in Java should be unique, since two classes with the same file name can exist in different directories, but they cannot both be used in any one program.

A class file named in an import statement is processed twice. It is read during the compilation of the client program to obtain information about field names, variable types, and method parameters. It is loaded again each time the program executes.

Currently, neither Java nor any of the program development environments will detect the problem if a class file is changed between the time that a client program is compiled and executes. If none of the existing public fields are changed, then the program will execute normally. During execution, if the class loader discovers that the number or type of arguments to a method call no longer match any of the methods in the class, then a run time error is generated and the program cannot run.

Networking complicates things, because the maintenance level of the class library on the client machine may be different from the one used to compile an applet. There is no general solution to this problem.

Historical Background

Early programming languages (FORTRAN, COBOL) provided no mechanism to ensure that the number and type of arguments used in a call matched the definition of an externally compiled subroutine. C programming used the preprocessor and header files (*.h) to provide common declarations of function arguments that could be included in the compilation of both the client and the library function.

A preprocessor only works if both programs use the same version of the header file. While there is some support for automatic recompilation of effected files through the "make" utility, it depends on the programmer providing a proper declaration of interdependencies in the external utility files unrelated to the language itself.

Ada provided a good example of the most popular rigourous solution. A programmer building an Ada "package" (the closest concept corresponding to a class) would provide two files. The first file is called the "specification" and defines all the public variables and the number and type of arguments to all public functions. The specification was compiled and stored in the library. Client programs could include the compiled version of the specification to generate proper function calls.

The developer of the package coded a separate "implementation" file that contained the body of all the functions. It too referenced the compiled specification to ensure that the functions of the package were actually coded to accept the documented arguments.

The implementation could be changed at any time, without effecting client programs. Only if the specification were changed and recompiled would it be necessary to recompile the implementation and all the client programs.

A compiled Java class does double duty as its own Specification and Implementation. When the class is processed during the compilation of a client program, only the external public information in the class (the Specification) is scanned. When the class is subsequently loaded during execution, the body of the methods (the Implementation) becomes important. Because Java classes are dynamically loaded from the library in order to start the program, there is no problem with old modules holding obsolete versions of function packages. However, correct operation of a program requires that it be executed with the same version of the class that it was compiled with (or at least a version of the class in which no public elements of the interface have changed).

Continue Back PCLT

Copyright 1996 PC Lube and Tune -- Java H. Gilbert

This document generated by SpHyDir, another fine product of PC Lube and Tune.