The CLASSPATH is an environment
variable that tells the Java compiler javac.exe
where to look for class files to import or java.exe
where to find class files to interpret.
In contrast, the PATH is an environment variable that
tells the command processor the where to look for executable files, e.g. *.exe,
*.com and .bat
files. The Classpath is one of the most confusing things in Java. Unfortunately,
you must master it to even compile HelloWorld.
CLASSPATH And File Naming Recipes
Here are my simplified rules for using CLASSPATH and naming the files on the javac.exe
and java.exe command line:
-
Put every class in a package. Don't use the default
package.
-
Use the latest JDK. It will be the one everyone you ask
help from is familiar with. Two dangling prepositions in one sentence. Churchill
would be proud.
-
Configure your SET CLASSPATH= in the environment to
clear it out. Avoid JDK 1.0 if you can because its CLASSPATH is more complicated
since it has to help javac.exe or java.exe
find the standard classes.
-
You don't need to explicitly include J:\j2sdk1.4.2_04\jre\lib\rt.jar
unless you are using Jikes, where you need to add it to
the JIKESPATH, but not the CLASSPATH.
-
In all that follows, everything is strictly case sensitive.
-
To compile a HelloWorld.java app in the default
package in C:\MyDir, use
CD \MyDir
javac.exe -classpath . HelloWorld.java
-
To run a HelloWorld.class app, in the default package
in C:\MyDir, use
CD \MyDir
java.exe -classpath . HelloWorld
-
To compile a HelloWorld.java app in C:\com\mindprod\mypackage,
in package com.mindprod.mypackage, use
CD \
javac.exe -classpath . com\mindprod\mypackage\HelloWorld.java
-
To run a HelloWorld.class app in C:\com\mindprod\mypackage,
in package com.mindprod.mypackage, use
CD \
java.exe -classpath . com.mindprod.mypackage.HelloWorld
-
To compile a HelloWorld.class app in C:\com\mindprod\mypackage,
in into a jar called helloworld.jar in package com.mindprod.mypackage,
use
-
To run a HelloWorld.class app in C:\com\mindprod\mypackage,
in a jar called helloworld.jar in package com.mindprod.mypackage,
use
CD \AnyDir
java.exe -classpath helloworld.jar com.mindprod.mypackage.HelloWorld
java.exe -jar helloworld.jar
helloworld.jar
-
If for any reason the examples shown do not work with your version of java.exe,
try replacing the \ in com\mindprod\mypackage\HelloWorld
with / mypackage/HelloWorld.
If you stare long enough at those examples, you may understand the logic behind
them, and then you can create variants. If you can't, just slavishly copy the
closest matching example.
Rules About Classpaths
-
The elements of the classpath are platform specific OS directory names or jar
file names; the package/classnames on the command line are not. Don't try to
concoct a class name such as C:/com.mindprod.mypackage.MyClass
-
If you want a jar on the classpath, you must put the jar file name on the
classpath, not just the name of the directory where the jar lives. This
means you need whacking long classpaths, with every jar in a common directory
each added to the classpath individually. Perhaps one day Sun will implement a JARPATH.
In would not be hard to build a wrapper around Javac.exe
and Java.exe that faked in a JARPATH. Hint, hint.
-
Simply copying or moving your jar files to the ext
directory pointed to by the system property java.ext.dirs
= C:\Program Files\Java\j2re1.4.2_04\lib\ext
automatically puts them on the classpath without having to mention the
explicitly. This is a great way to prune back an overblown classpath. It is
safest to put your jars in all the ext directories:
where to look for ext directories :
You never know for sure where your Javac.exe
or java.exe is going to look. Grrr. You can
change the location of the ext directory on the
command line.
java.exe -Djava.ext.dirs=c:\mylibs mypackage.MyClass
-
Class names are always fully qualified with the complete package name.
There is no way to ever abbreviate the higher levels.
-
Each element of the CLASSPATH provides a starting point to look for a
fully qualified package and class name, identical to the way it appeared in the
package or import statement.
-
If the element of the CLASSPATH is the name of a directory, Java will look in
that tree for directory names matching the package name structure. It looks at
one place only. It does not search. The class file sought must be filed under
the one and only precise fully qualified pathname, or it won't be found. It
wants to find a *.class file (or *.java
file), at the precisely correct spot in the directory tree. You must get an
exact match on the fully qualified name. The name of the directory specified in
the CLASSPATH itself is totally immaterial in determining the package name.
-
If the element of the CLASSPATH is a jar, Java will look in the internal
directory structure of the jar for an exact match on the fully qualified name.
It looks; it does not search. The class file sought must be filed under the one
and only precise fully qualified pathname, or it won't be found. The location of
the jar is totally immaterial in determining the name of the package. If you
peek inside the jar with WinZip you should see pathnames on each class file
matching the package structure. Download and examine any of my jars and the
corresponding source to see how it works.
-
An alternative, ultimately more confusing way of looking at it, is that you
specify part of the operating system's name for a class file in the CLASSPATH
and part in the package name. Java source imports and package statements, javac.exe
and java.exe command lines specify only the fully
qualified package name, not the higher order part handled by the CLASSPATH. The
higher levels that are handled by the CLASSPATH (which could appear on the
command line via -classpath option), are effectively invisible to your Java
programs. However, you are not at liberty to shuffle levels of qualification
between your import and classpath unless you adjust all your package statements
and recompile as well.
Spaces and Quotes in Classpaths
Spaces in filenames are a royal PITA, however, Microsoft
forces them down your throat because most packages install in C:\Program Files.
There are several plausible ways you might deal with spaces in classpaths:
-
Avoid spaces altogether. Don't put packages in C:\Program Files
unless you have to.
-
do nothing special.
-
Put quotes around the entire classpath.
-
Put quotes around each element of the classpath.
javac.exe and java.exe
are fairly forgiving. Here is what works and what does not:
javac -classpath .;C:\;C:\Program Files\Java Web Start\javaws.jar;E:\jaf-1.0.1\activation.jar
*.java
javac -classpath ".;C:\;C:\Program Files\Java Web Start\javaws.jar;E:\jaf-1.0.1\activation.jar"
*.java
javac -classpath ".;C:\;C:\Program Files\Java Web Start\javaws.jar;E:\jaf-1.0.1\activation.jar"
*.java
set classpath=.;C:\;C:\Program Files\Java Web Start\javaws.jar;E:\jaf-1.0.1\activation.jara
javac *.java
set classpath=".;C:\;C:\Program Files\Java Web Start\javaws.jar;E:\jaf-1.0.1\activation.jar"
javac *.java
set classpath=".;C:\;"C:\Program Files\Java Web Start\javaws.jar";"E:\jaf-1.0.1\activation.jar"
javac *.java
There is some logic to it. The command line needs quotes around the
entire classpath to tell it apart from any other command line options. SET
CLASSPATH= needs no quotes because the end of line terminates the
classpath. The simplest rule is always put to always put quotes around the
entire classpath, even though they are not necessary for SET
CLASSPATH=.
CLASSPATH Tips
-
Beware of inserting extra semicolons in your CLASSPATH. Everything to the right
will be ignored!, leading you to pull out your remaining hair in frustration
wondering why java.exe can't find the classes. You must
have exactly one semicolon between elements, no lead/trail/extras.
-
Unlike C++, Java compilers use the CLASSPATH to find and examine compiled code
rather than source header files to learn how about how to invoke the various
methods. The compiler also uses the CLASSPATH to find and compile the
corresponding source if no class file is available. The runtime also uses the
CLASSPATH to find the class files to execute.
-
The Webgain (neé Symantec) compilers ignore the usual SET
CLASSPATH= and take one from the \VCP\BIN\SC.INI
file instead. Class files may be standalone, combined in zip files or combined
in jar files. Java looks for class files in any directories mentioned in the
CLASSPATH, but only searches jar and zip files if they are explicitly mentioned.
A typical CLASSPATH statement might look like this:
SET CLASSPATH=.;D:\VCP\BIN\COMPONENTS\SYMBEANS.JAR;D:\VCP\JAVA\LIB\CLASSES.ZIP;D:\VCP\JAVA\LIB;D:\MyStuff
all on one gigantic line without any spaces. Ouch!
-
SlickEdit creates a
classpath composed of the files included in the current project.
-
Internet Explorer hides its CLASSPATH in the registry under HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Java
VM.
-
Netscape uses the CLASSPATH in the standard SET environment.
-
Windows 95 controls the environment with SET CLASSPATH=
in autoexec.bat.
-
Linux controls the environment with export CLASSPATH=
in your .bashrc file.
-
For NT, since there is no autoexec.bat, you have to
preload the environment strings into the environment with Settings
| control panel | system | environment. You can use traditional BAT files
to create them, then echo, copy and paste them into the permanent environment.
Remember to click set before you click OK
or your new settings will be discarded. Also see the rules
above for dealing with directory of jar filenames containing blanks
Alternatively always install your apps in directories without embedded spaces.
Make sure you have no lead or trail spaces on the classpath as a whole. The
control panel uses a microscopic unreadable font. To proofread, copy/paste to an
editor. Beware of spurious spaces introduced by copy/pasting.
-
Beware. Putting D: on the classpath is not the same
thing as putting D:\. The first put the current
directory of D: on the classpath. The second puts the
root directory. They are often the same, but not always.
-
One would think a platform independent language would have a platform
independent way of controlling the CLASSPATH, but it doesn't. Webgain's SC.INI
is closest.
-
Note that CLASSPATH uses forward (or optionally backslashes under Windows and NT)
to separate levels, and semicolons to separate directories. In contrast, inside
Java programs in import statements, you use dots to
separate levels. Inside <lt;APPLET CODE statements
it is best if you use dots to represents levels inside jar files and slashes to
represent files. java.exe uses only dots, no slashes or
backslashes allowed.
-
In Linux and NT under bash, the elements of the CLASSPATH are separated by
colons. In Win95 and standard NT, they are separated by semicolons. Somebody
deserves a major raspberry.
-
Presuming you had a CLASSPATH like this:
SET CLASSPATH=.;D:\VCP\BIN\COMPONENTS\SYMBEANS.JAR;
You might think that you could have an import like this:
However, you cannot respecify any level already mentioned in the CLASSPATH. You
just give the low levels of qualification like this:
-
If you have a jar file in C:\MyStuff\ajar.jar, on the
classpath, then com.mindprod.somepackage is the
internal directory name stored inside the jar file. You might be tempted to
might try to get at the class in the jar with the following import:
That will not work. You may only specify the low order qualification that is
actually part of the package name like this:
-
Basically the rule is, your package name cannot provide redundant information
that the CLASSPATH has already provided. You always have to specify the fully
qualified package name. You can't abbreviate with a smart Alec CLASSPATH like
this:
SET CLASSPATH=.;C:\com\mindprod\mypackage;
Then expect to get away with specifying only MyClass
instead of com.mindprod.mypackage.MyClass. You always
have to use fully qualified class names.
-
You can check the CLASSPATH setting by typing:
echo %CLASSPATH%
under Win95 or
echo $CLASSPATH
under Unix.
If you want to be really sure, use the Wassup
utility which will also find and report on Webgain's SC.INI
CLASSPATH when it applies.
-
If you don't want to be bothered with manually composing a CLASSPATH, try SmartJ.
-
For applications, you can also specify the CLASSPATH on the command line with
the -classpath or -cp (for
short) option switch. e.g.
java.exe -cp C:\MyStuff;C:\MyStuff\mygoodies.jar HelloWorld
This is the safest place especially when every app needs a slightly different
CLASSPATH and/or a different JVM. The catch is the CLASSPATH can be very long
which makes the command line hard to type and read. Infuriatingly, the -cp
shortcut does not work with javac.exe as well.
-
Keep in mind that Java is extremely case sensitive, even if your operating
system is not. Be very careful to get case precisely right any time you specify
a filename, <APPLET CODE, or CLASSPATH.
Unfortunately Windows and Windows NT will often lie to you about the actual case
of a name. Tracking down case mismatches can drive you nuts. JP Soft's 4NT
DIR /F is useful at getting at the true case of a
filename. Packages should contain lower case only. Classes should start with an
upper case letter. Variables should start with a lower case letter. See coding
conventions.
-
Just to keep you on your toes, in JDK 1.0 putting the classes.zip
on the CLASSPATH is mandatory. in JDK 1.1, putting classes.zip
on the CLASSPATH is optional. In 1.2 and 1.3 putting rt.jar
on the classpath is an error. Starting with version 1.2 the class files live in:
and they
automatically go on the classpath.
-
See java.exe for a more discussion of how the java.exe
runtime uses package names, class names and the CLASSPATH to find the classes,
and javac.exe for how the javac.exe
compiler finds the dependent *.java files that also
need compilation.
-
You have little control over the CLASSPATH used by a browser for an Applet. You
can find out what it is using for a CLASSPATH by running this Applet.
You have to grant it security permission to look at your classpath. If that does
not work, try Wassup.
-
I lost pounds of hair fighting with classpath. I have found some magic patterns
that work, and now I just cut and paste existing java source, HTML and BAT files
for new projects. You might study my jar files and Applet HTML and emulate my
patterns. See the downloads page.
-
See javac.exe for tip on how to squeeze long
classpath onto the command line.
-
You can discover what the CLASSPATH is with the system property:
System.getProperty( "java.class.path" );
which you can view by running wassup as an
application. The CLASSPATH separator character is platform dependent. You can
discover it with:
System.getProperty( "path.separator" );
It will usually be ; or :. You
must put ., the current directory, explicitly on the
CLASSPATH.
-
If you use the -jar option, java.exe
ignores the classpath. It will only look in that jar.
CLASSPATH Complexities
I lied to you. Life is actually a little more complicated. If you feel ready for
the whole truth, and want to understand the logic behind those examples, here is
how CLASSPATH really works. Suddenly all of classpath's craziness made sense
once I figured out how it worked inside. You may be similarly lucky.
-
You must put the fully qualified name of the class on the java.exe
command line. If there is no package, the name is simply HelloWorld.
e.g.
CD \MyStuff
java.exe HelloWorld
However, had you used a package com.mindprod.business;
clause, then the full name of HelloWorld is com.mindprod.business.HelloWorld.
It must be spelled with perfect attention to upper/lower case.
-
You may not abbreviate the name in any way. It must be 100% fully qualified,
always.
-
That settled, where should the com.mindprod.business.HelloWorld.class
file live? It could live in a jar file on the CLASSPATH. Inside the jar it must
be stored with its fully qualified name.
CD \jardir
java.exe -cp mystuff.jar com.mindprod.business.HelloWorld
-
The class may also live as a free-standing class file. Let us assume that "."
(the current directory) is on the CLASSPATH, and that the fully qualified name
of the class is com.mindprod.business.MyClass. You cannot
put HelloWorld.class in the current directory. java.exe
won't find it. It will look for it three levels deeper in as com\mindprod\business\HelloWorld.class.
If it is not there, it won't find it. It will ignore copies in the current
directory and in .\com.mindprod. You must coax it into working like this:
CD \
set classpath=. java.exe com.mindprod.business.HelloWorld
or like this:
CD \com\mindprod\business
java.exe -cp ..\..\..\ com.mindprod.business.HelloWorld
or like this:
java.exe -cp C:\ com.mindprod.business.HelloWorld
-
However that last solution is dangerous and slow because you are exposing your
entire drive to be searched for classes. It is unwise to hang your class
directories directly off the root. Instead hang your directory tree under C:\cl.
Then you could write.
CD \cl
java.exe -cp . com.mindprod.business.HelloWorld
or this:
CD cl\com\mindprod\business
java.exe -cp ..\..\..\ com.mindprod.business.HelloWorld
This time only the cl directory is exposed to being
searched for class files.
-
com.mindprod.business.HelloWorld may also live as a
free-standing class file hanging off one of the directories mentioned in the
CLASSPATH. Let us assume that C:\MyStuff is on the
CLASSPATH. You cannot put HelloWorld.class
directly in the C:\MyStuff directory. java.exe
won't find it. It will look for it three levels deeper in as C:\MyStuff\com\mindprod\business\HelloWorld.class.
If it is not there, it won't find it. You can make it work like this:
java.exe -cp C:\MyStuff com.mindprod.business.HelloWorld
-
These same rules apply to finding all the classes, not just the one
mentioned on the command line. Your directory structure, names and class file
placement must perfectly reflect your package structure which must also
perfectly reflect your structure for storing the *.java source code files in
directories or inside jar files.
-
Inside a jar, class names are fully qualified with package and class name using
dots. To execute class com.mindprod.business.MyClass
inside jar myjar.jar:
java.exe -jar C:\someplace\myjar.jar com.mindprod.business.MyClass
-
It is still even more complicated than that. java.exe
looks for your classes on each element of the CLASSPATH. You might put C:\;C:\MyStuff;C:\Mystuff\Project99
all on the CLASSPATH. Then you would have several options to the way you specify
your classes, each one dovetailing with a different piece of the CLASSPATH.
The Key To Understanding
This all sounds hideously complicated. My explanations sound like drooling
nonsense. It did not come clear to me until I began to think about how java.exe
and javac.exe make use of the classpath. Then it
all made sense.
-
When java.exe (or <APPLET
CODE) wants to find a class, it has the fully qualified classname
composed of package.classname e.g. com.mindprod.business.HelloWorld.
-
It then looks at each element (a chunk between semicolons) of the CLASSPATH,
working left to right seeking a match.
-
If that CLASSPATH element is a jar, it looks for an entry inside the jar for a
folder called precisely com/mindprod/business and a
member called precisely HelloWorld.class. It is
irrelevant to the naming scheme where in the directory structure the jar file
itself is. All that matters is perfect-fully-qualified-pathnames-to-package
mapping inside the jar.
-
If the CLASSPATH element is a directory, it expects to find in that directory a
directory subtree called precisely com\mindprod\business
and in the business directory it expects to find a
file called precisely HelloWorld.class. It does not
matter where the CLASSPATH element itself is in the directory tree. That has no
effect on the package name.
-
The lookup is quite quick for each element of the classpath. It involves no
scanning, just a lookup, does this class file exist by precisely this name in
precisely this place? It does though have to repeat this for each element of the
classpath before it gives up.
-
When javac.exe wants to find a class, it may want
either the *.java source or the compiled *.class
or both. It uses the same mechanism to find them.
The Hashtable Explanation
If you understand Hashtables, this explanation may
let you suddenly grok
the classpath.
A ClassLoader with plenty of RAM could work this way.
It creates a giant Hashtable of all possible classes
out there on disk in all the directories and jars on the classpath and all the ext
directory jars, using fully qualified package and class names as the keys. It
would include classes it might never even possibly load. A real implementation
would use some tricks to conserve RAM such as making a Hashtable
of Hashtables, one for each layer of the package
name, or keys broken into interned segments, or might only build a Hashtable
for jarred classes, but for the purpose of understanding, imagine just a simple
single Hashtable with the keys to all the fully
qualified package and classnames on the classpath.
How does the ClassLoader build this Hashtable?
It looks at the first segment of the classpath and starts adding classnames
using the fully qualified class name as the key and where the class files are on
disk as the value. Then it moves onto the next segment of the classpath. It adds
all those classnames. If it discovers a duplicate, it ignores the new key, and
keeps the key it already has. This ensures the first occurrence of a class on
the classpath will be the one used.
Now when you first use a class, the ClassLoader
looks up the name in the Hashtable, and it if it is
present, it knows where on disk and in what jar to find it. There is no scanning
required, just a straight forward keyed Hashtable
lookup. If the class is not present in the Hashtable,
the ClassLoader knows the class is nowhere to be
found and it raises the dreaded NoClassDefFoundError
exception.
Classpath Example
If, for example, you had a class called com.mindprod.bulk.Resend
e.g. class Resend in package com.mindprod.bulk,
If you did cd \ and had classpath .
then java would expect to find the class file in: C:\com\mindprod\bulk\Resend.class.
If you did cd \com\mindprod\bulk and had classpath .
then java would expect to find the class file in: C:\com\mindprod\bulk\com\mindprod\bulk\Resend.class.
If you did cd \ and had classpath C:\
then it would expect to find the class file in: C:\com\mindprod\bulk\Resend.class.
If you did cd \com\mindprod\bulk and had classpath C:\
then it would expect to find the class file in: C:\com\mindprod\bulk\Resend.class.
To get the hang of this, experiment with simple classpaths with only one element
to them, then gradually build up more complex classpaths that search in many
places.
java.ext.dirs
Sometimes you will have so many jar files, you can't fit them all on the
classpath. What you can do then is look at the system property,
System.getProperty( "java.ext.dirs" );
which you can view by running wassup as an
application or Applet. Then put the jar in the corresponding directory. e.g.
java.ext.dirs = D:\program files\JavaSoft\JRE\1.3\lib\ext
The jars will automatically be found without putting them on the classpath.
-
Opera 7.35 will likely be in j2re1.4.2_04\lib\ext
-
Netscape 4.79 will likely be in Program Files\Netscape\Communicator\Program\Java\classes
-
IE 5.5 will likely be in WINNT\Java\Packages
-
Netscape 7.02 will likely be in j2re1.4.2_04\lib\ext
There are at least two ext directories:
where additional jars on the path are kept :
java.exe seems to use
the JRE version and where javac.exe seems to use the
JDK version.
Sooner or later some you will have to reinstall and you will lose your ext
directories. You can quickly rebuild them if you maintain a bat file like this.
Adjust the file to account for where your ext dirs are
and where the jars are you need.
C:
CD "J:\j2sdk1.4.2_04\jre\lib\ext"
copy "c:\jaf-1.0.1\activation.jar"
copy "c:\javamail-1.2\mail.jar"
copy "c:\Program Files\JMF2.1.1\lib\jmf.jar"
copy "c:\Program Files\JMF2.1.1\lib\sound.jar"
CD "C:\Program Files\Java\j2re1.4.2_04\lib\ext"
copy "c:\jaf-1.0.1\activation.jar"
copy "c:\javamail-1.2\mail.jar"
copy "c:\Program Files\JMF2.1.1\lib\jmf.jar"
copy "c:\Program Files\JMF2.1.1\lib\sound.jar"
Command Line Too long?
In Windows in particular, you will often find all the junk you need to put on a
command line is too long. Here are a few tricks to shorten it.
Global Classpath Is An Anachronism
The global classpath is an anachronism. It is impossible to have one classpath
that satisfies all possible compilations and all possible applications.
Installers will meddle with it. Programs will work, then mysteriously stop
working when you make some innocent change the classpath.
Instead, put it in your IDE projects, on your javac.exe -classpath
and java.exe -classpath commands and in your jar
manifests where the rest of the world cannot meddle with it.
Avoid using version numbers in your classpaths. They tend to go stale.
If you leave out your SET classpath, it defaults to simply .
the current directory.
Servlets
When you write servlets, JSP, Struts and the like, the classpath is extended
with the WEB-APP\classes directory for additional class
files for a particular application, and WEB-APP\lib for
jars for a particular application. Instead of adding jars and directories to the
general classpath, you make multiple copies off the classes and jars and put
them in the various WEB-APPs as needed. This helps
minimize unexpected interactions between applications, e.g. one app needs
version 1.1 of a jar and another version 2.0.
Learning More