By far, the most common questions in Freenode ##java center around the concept of classpath. It’s funny, too, because the questions are often asked by people who – upon questioning – insist that they understand classpath, they really do… and then, upon having it explained to them in excruciating detail, manage to solve their problem.
By using the classpath properly.
To me, this sounds like the classpath documentation hosted by The Company Formerly Known As Sun is being unread, and when it is being read, it’s not being understood.
Time to fix this.
You may think you know all this.
The classpath is a list of resources in which other resources are located. It’s a set of starting points.
It’s a list of resources. Because it’s a list of resources, the list has an OS-specific aspect to it.
In UNIX, that means the list uses “:” as a separator; in Windows, it uses “;” as a separator. I’m going to use UNIX semantics here, because I prefer UNIX to Windows, despite using Windows. If you see “foo:bar,” then, and you’re on Windows, you’ll need to use “foo;bar” instead.
The elements in the classpath can be one of two types: archives or directories.
An archive for Java is normally a .jar file, although it can be a .zip file as well (a .jar file uses the .zip format, so this makes sense.)
A directory is a filesystem directory, and can contain other directories or files, of course. (This isn’t rocket surgery.)
Resources in Java have paths; for classes, the path is composed of the package name plus the class name (and the .class extension.) Therefore, a class that looks like this:
package foo.bar; public class Baz { public static void main(String args) { System.out.println("hello, world"); } }
… will have a resource path of “/foo/bar/Baz.class”.
So let’s start applying this knowledge.
How the classpath works.
When you (or Java, or whatever) ask for a resource – let’s say a class, for example – it will look at the list of resources in the classpath, according to the classloader in use. (Pretend I didn’t include that last phrase about classloaders; it’s really important, but until you understand the classpath, classloaders are mad wizardry that you don’t need to acknowledge. Look at them after you understand the classpath.)
So let’s say we have two elements in the classpath: “foo.jar:bar”. This means that “foo.jar” in the current working directory is in the classpath, as is the “bar” directory in the current working directory.
Further, let’s say we are requesting the resource “foo.bar.Baz,” our class from earlier in this post. We might be requesting it with the following command line:
java -cp foo.jar:bar foo.bar.Baz
Java will then look inside foo.jar, looking for a file entry of “/foo/bar/Baz.class” – remember, this is our full resource path generated the compiler from that source file.
It uses foo.jar first because it’s first in the classpath.
If foo.jar contains “/foo/bar/Baz.class”, Java uses it and stops looking further in the classpath.
If foo.jar does not contain “/foo/bar/Baz.class”, then Java will look in the “bar” directory for “./foo/bar/Baz.class” — i.e., if the current working directory is “/home/username/app”, it will look in “/home/username/app/bar/” for “foo/bar/Baz.class” — with a full path being looked for of “/home/username/app/bar/foo/bar/Baz.class”.
If that file exists, Java will use it, and search no more.
If it doesn’t exist, it keeps searching until the entire classpath has been scanned; if the resource doesn’t exist, you’ll get a NoClassDefFoundError from java (or a null input stream, depending on what you’re doing.)
If this is unclear to you, please let me know – I’ll try to figure out how to make it more clear. (Part of the problem is that people who understand the classpath don’t understand what those who don’t understand the classpath are misunderstanding.)
Author’s Note: Another repost.