Packages in Java: Class Path

What is the relationship between packages and the class path?

Overview

As you may already know, Windows and all Unix-based operating systems (the latter group includes macOS, Linux, etc.—sometimes referred to collectively as *nix.) make extensive use of an environment variable called PATH, which is simply a list of directory paths, separated from each other by a semicolon (in Windows) or a colon (in *nix). When you issue a command (e.g. by typing it into the search field of the Start menu or in a command prompt in Windows, or in a Terminal window in macOS), the operating system searches through the directories listed in the PATH environment variable, looking for an executable program with the specified name; if one is found, it is executed.

Java uses a class path to perform a similar operation: When the compiler or the class loader encounters a reference to a class or interface that is not part of the standard library, it searches the class path for the specified class or interface. The details of this operation are closely related to Java packages: though it may sound paradoxical, we need a reasonably good understanding of both to have a solid understanding of either one.

Specification

The class path may be specified in three ways:

When a class or interface that is not in the standard library is referenced at compile-time or runtime, the class path is searched, in order of specification. That is, if the class path contains multiple directory paths, each will be searched, in the order in which they are listed in the classpath, until a match is found; if no match is found, then the operation will fail.

Example

The following command may be used to start the Java application launcher in Windows, instructing it to load a class with the fully-qualified name edu.cnm.deepdive.FizzBuzz, and launch it as a Java application (i.e. invoke its main method). The -cp is used to specify where the application launcher should look for the bytecode of the edu.cnm.deepdive.FizzBuzz class.

java -cp c:\fb;c:\bootcamp;c:\projects edu.cnm.deepdive.FizzBuzz

On macOS, Linux Ubuntu, etc., we would write the (nearly) equivalent:

java -cp /fb:/bootcamp:/projects edu.cnm.deepdive.FizzBuzz

Note that in both cases, we’ve specified the fully-qualified name of the class to be launched. In fact, the import facilities discussed earlier are simply conveniences that enlist the compiler’s help to simplify our source code; the Java compiler and class loader always search for classes and interfaces using their fully-qualified names, no matter what import statements are (or were) in the source code. Starting with this fact clear in our minds is essential to understanding how the search proceeds.

In the Windows example above, the Java application launcher, using the class loader, will search for the following, in the order shown:

  1. c:\fb\edu\cnm\deepdive\FizzBuzz.class
  2. c:\bootcamp\edu\cnm\deepdive\FizzBuzz.class
  3. c:\projects\edu\cnm\deepdive\FizzBuzz.class

(Please note again the correspondence between packages and directories.)

If the FizzBuzz.class file is found in any of the locations listed, the search stops, the FizzBuzz class is loaded from the bytecode file into memory, and the application launcher attempts to invoke the class main method. (Note: Bytecode output from the compiler is written to files with a .class extension.)

If, during execution, the code of the edu.cnm.deepdive.FizzBuzz references any other class (or interface) that is not in the standard library, the same search process will be repeated, using the fully-qualified name of that class, together with each of the directory paths specified in the class path, to search for the bytecode of the referenced class. However, every time this search is performed, the relationship between packages and directories is enforced: If the bytecode is found in a directory corresponding to the fully-qualified name specified, but the fully-qualified name embedded in the bytecode does not agree with the fully-qualified name being searched for, the search fails.