Classpath in Java
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:
javac -d out $(find src -name "*.java")
java -cp out com.poolstring.bank.app.BankAppFor 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 type | Example | What the JVM does |
|---|---|---|
| A folder | out | Looks for out/com/poolstring/.../X.class |
| A JAR file | lib/bank.jar | Looks inside the zip for com/poolstring/.../X.class |
| All JARs in a folder | lib/* | 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
Two folders, v1 and v2, each contain a different Greeting class:
java -cp v1:v2 Greeting
java -cp v2:v1 GreetingHello from v1
Hello from v2The 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:
java -verbose:class -cp v2:v1 Greeting | grep "Greeting "[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:
jar --create --file bank.jar -C out .
java -cp bank.jar com.poolstring.bank.app.BankAppThe 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 set | Result |
|---|---|
-cp on the command line | Used, and anything else is ignored |
No -cp, but the CLASSPATH environment variable is set | CLASSPATH is used |
| Neither | The 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
| Error | Meaning | Usual fix |
|---|---|---|
Error: Could not find or load main class X with ClassNotFoundException: X | The class you asked to run isn't on the classpath | Check -cp and use the full name with the package |
java.lang.NoClassDefFoundError | The class was there at compile time but is missing at runtime | Add the missing folder or JAR to -cp |
error: package x.y does not exist (from javac) | The compiler can't find a dependency | Add it to javac -cp |
Error: Could not find or load main class BankApp
Caused by: java.lang.ClassNotFoundException: BankAppThat'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
- Easy: Compile the bank project into
out, then run it once with-cp outand once with no-cpfrom insideout. Why do both work? - Harder: Create
v1andv2folders with differentGreetingclasses, as above. Predict and check the output for-cp v1:v2,-cp v2:v1and-cp v2.
Key Takeaways
Was this tutorial helpful?