Building Large Java Applications

Real Java applications are made up of hundreds, or thousands, of classes. To make things manageable, the classes are grouped into packages. But when an application is being compiled and run, how does the system find all the classes? It uses classloaders to find and load the classes (and other resources like images, movies, properties files) that the program requires.

Basics of Class Loading

The Java runtime starts with one classloader (the bootstrap classloader) that finds classes on the local filesystem. You can create your own classloaders to find classes from other places (such as over a network connection), to compose binary classfiles on the fly, or do things while loading classes (like decrypting them, verifying digital signatures, etc.). Classloaders are chained together so that each classloader except the bootstrap loader has a parent; if a classloader can't find a class it asks its parent to find it.

Every Class object contains a reference to the ClassLoader that defined it; you'll sometimes see code that says

    x.getClass().getClassLoader()

The Bootstrap Classloader

Unless you are doing fairly fancy stuff, you never have to tell a classloader to load a class; just mentioning a class is good enough. For example, the class A below refers to:

// File: ~/src/edu/lmu/cs/rtoal/scratch/A.java
package edu.lmu.cs.rtoal.scratch;
public class A {
    org.bouncycastle.crypto.BlockCipher cipher =
        new com.citysearch.util.crypto.HagenRedmannTwofishEngine();

    void m(int x) {
        java.util.List y = new java.util.ArrayList();
        cipher.reset();
        B b = new B();
        edu.lmu.cs.rtoal.math.Complex c;
        java.lang.System.out.println("okay");
    }
}
// File: ~/src/edu/lmu/cs/rtoal/scratch/B.java
package edu.lmu.cs.rtoal.scratch;
public class B {}
// File: ~/src/edu/lmu/cs/rtoal/math/Complex.java
package edu.lmu.cs.rtoal.math;
public class Complex {
    // Not done yet
}

So I've written classes A, B, and Complex myself, but these other classes (BlockCipher, HagenRedmannTwofishEngine, List, ArrayList, and System) already exist. But it doesn't really matter who wrote them; what matters is the full class names. A classloader needs to find:

    edu.lmu.cs.rtoal.scratch.A
    edu.lmu.cs.rtoal.scratch.B
    edu.lmu.cs.rtoal.math.Complex
    org.bouncycastle.crypto.BlockCipher
    com.citysearch.util.crypto.HagenRedmannTwofishEngine
    java.util.List
    java.util.ArrayList
    java.lang.System
But how does the bootstrap class loader find all the classes? First, it turns the full class name into a filename — so the first class in the list above would correspond, on a Windows system, to

    edu\lmu\cs\rtoal\scratch\A.class

(If you're compiling, and the compiler can't find that class, it will look for

    edu\lmu\cs\rtoal\scratch\A.java

and compile that for you!!! How sweet.)

On almost every other system, the file names would be:

    edu/lmu/cs/rtoal/scratch/A.class
    (or edu/lmu/cs/rtoal/scratch/A.java)

Note: that filename is a relative path name! Relative to what? The bootstrap loader looks for it in this order:

  1. The jar files in your JRE's lib directory (rt.jar, jsse.jar, jce.jar, charsets.jar)
  2. The jar files in your extensions directory — by default this is the JRE's lib/ext directory. You can dump your own jars in this directory, or tell your tool to use a different directory.
  3. Each entry in the current classpath, in order.

Classpath? What's that?

Classpaths

A classpath is simply a list of directories and jar files. The bootstrap class loader searches a classpath when it looks for the classes (or source files) it needs, after searching the platform and extension locations.

On Windows the classpath entries are separated with semicolons; on every other platform (I think) colons are used.

Example

    c:\homework\stuff.jar;c:\other\crap;c:\mylibs\junit.jar

If you requested the class a.b.C from the bootstrap classloader, and that class was not found in rt.jar or in the extensions, it would look for, in this order:

  1. a\b\C.class in c:\homework\stuff.jar
  2. c:\other\crap\a\b\C.class
  3. a\b\C.class in c:\mylibs\junit.jar

Specify the classpath when invoking a tool, for example

    javac -classpath c:\homework\stuff.jar;c:\other\crap;c:\mylibs\junit.jar *.java

or, less flexibly, set the CLASSPATH environment variable (which may seem like a timesaver but can cause headaches). It's suggested you leave this environment variable unset and use a specific classpath when you invoke a tool. If you really must know about this variable, consult Sun's online docs.

More on Classloaders, Classpaths, and Related Topics

See Sun's documentation on How Classes are Found.

Building Your Application

Developers should be familiar with all three main approaches to building applications

Distributing Your Application

There are three main ways to distribute a Java application:

Fun With Multiple Class Loaders

Once you start writing your own classloaders or you start deploying applications with multiple classloaders, you'll probably run into the case where a single class file is loaded by each classloader. Your application will think there are two distinct classes, and, well, some confusing things may start to happen. Just be aware.