Classpath in Java

Naveen AnamaneniUpdated · 5 min read

When your program says new TransferService(), the JVM has to find TransferService.class somewhere on disk. It doesn't search your whole computer. It looks only in the folders and JAR files listed on the classpath, in order, and stops at the first match. Most "Could not find or load main class" errors are classpath mistakes, so it pays to understand exactly how the search works.

Setting the Classpath

The classpath is given with -cp (or the longer -classpath or --class-path) on both javac and java:

Terminal
javac -d out $(find src -name "*.java")
java -cp out com.poolstring.bank.app.BankApp

For the class com.poolstring.bank.app.BankApp, the JVM takes each classpath entry and appends the package path: out/ + com/poolstring/bank/app/BankApp.class.

Entry typeExampleWhat the JVM does
A folderoutLooks for out/com/poolstring/.../X.class
A JAR filelib/bank.jarLooks inside the zip for com/poolstring/.../X.class
All JARs in a folderlib/*Every .jar file in lib (not sub-folders)

Separate several entries with : on macOS and Linux, and ; on Windows: java -cp out:lib/* com.poolstring.bank.app.BankApp.

The Search Order: First Match Wins

Entries are searched left to right; the first match is used

Two folders, v1 and v2, each contain a different Greeting class:

Terminal
java -cp v1:v2 Greeting
java -cp v2:v1 Greeting
Terminal output
Hello from v1
Hello from v2

The JVM searches the entries left to right and uses the first match. That's useful (you can put a patched class first) and dangerous (two versions of the same library on the classpath give unpredictable behavior, often called "JAR hell"). To see where each class really came from, add -verbose:class:

Terminal
java -verbose:class -cp v2:v1 Greeting | grep "Greeting "
Terminal output (path shortened)
[0.011s][info][class,load] Greeting source: file:/.../cp/v2/

JAR Files

A JAR (Java ARchive) is a zip file of compiled classes, which is how libraries are shipped:

Terminal
jar --create --file bank.jar -C out .
java -cp bank.jar com.poolstring.bank.app.BankApp

The first command packs everything under out into bank.jar; the second runs from the JAR. A later lesson on build tools shows how they download library JARs and build the classpath automatically.

Default Classpath and CLASSPATH

How the classpath is setResult
-cp on the command lineUsed, and anything else is ignored
No -cp, but the CLASSPATH environment variable is setCLASSPATH is used
NeitherThe current folder (.)

CLASSPATH is a global setting that affects every Java program in that shell, which causes confusing bugs. Prefer -cp per command, or let a build tool handle it.

When a Class Isn't Found

ErrorMeaningUsual fix
Error: Could not find or load main class X with ClassNotFoundException: XThe class you asked to run isn't on the classpathCheck -cp and use the full name with the package
java.lang.NoClassDefFoundErrorThe class was there at compile time but is missing at runtimeAdd the missing folder or JAR to -cp
error: package x.y does not exist (from javac)The compiler can't find a dependencyAdd it to javac -cp
Terminal output
Error: Could not find or load main class BankApp
Caused by: java.lang.ClassNotFoundException: BankApp

That's java -cp out BankApp: the class is really named com.poolstring.bank.app.BankApp.

Common Mistakes

Pointing -cp at the package folder. -cp out/com/poolstring/bank/app is wrong; point at the root (out) and use the full class name.

Using : on Windows or ; on macOS and Linux. Each OS has its own separator.

Setting a global CLASSPATH and forgetting it. Later programs mysteriously fail or load the wrong classes.

Interview Corner

What is the classpath?

The classpath is the ordered list of folders and JAR files where the JVM and javac look for user classes and libraries. It's set with -cp, or the CLASSPATH environment variable, and defaults to the current directory. For a class a.b.C, each entry is searched for a/b/C.class, left to right, and the first match is loaded.

What is the difference between ClassNotFoundException and NoClassDefFoundError?

ClassNotFoundException is a checked exception thrown when code asks to load a class by name, for example Class.forName or the launcher's main class, and it isn't on the classpath. NoClassDefFoundError is an error thrown when a class that was present at compile time can't be found or initialized at runtime, typically because a JAR is missing from the runtime classpath.

Practice

  1. Easy: Compile the bank project into out, then run it once with -cp out and once with no -cp from inside out. Why do both work?
  2. Harder: Create v1 and v2 folders with different Greeting classes, as above. Predict and check the output for -cp v1:v2, -cp v2:v1 and -cp v2.

Quick check: Classpath

4 questions
1What does the classpath list?
2A class is on the classpath in two places. Which is loaded?
3What is the default classpath with no -cp and no CLASSPATH?
4What separates classpath entries on macOS and Linux?

Key Takeaways

Was this tutorial helpful?

Lesson 149 of 482