Have you ever read a tutorial, or someone in a forum, or in Discord, say "make sure it's on the classpath" and don't have the foggiest idea what they are talking about? Well it's your lucky day because we are going to figure out what the mysterious Java classpath is.
There is a TLDR at the bottom, if you'd like the concise answer
How the terminal finds and runs programs
First of all, you are going to be running a lot of your Java programs from a terminal. You've probably already used a number of commands in the terminal already, one such example is -
D:\Coding\Dev\Classpath example demo>echo Hello, World
Hello, world
What is happening here? We're using a program called echo
to print the line of text "Hello, World". We are calling the program by typing its name then some text, but how does the computer know we have a program called "echo" and how does it find it? There is something called an environment variable which stores a semi-colon separated list of paths to programs, one is aptly called Path
.
Lets have a look at my Path
using echo
D:\Coding\Dev\Classpath example demo>echo %Path%
C:\Python38\Scripts\;C:\Python38\;C:\Program Files\Java\jdk-13.0.2\bin;
C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\ProgramData\Oracle\Java\javapath;
C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;
C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;
...
C:\Program Files\Java\jdk-13.0.2\bin;
...
Wrapping a string with
%
symbols identifies it as a variable
I've omitted quite a bit here, but you can see these are directory paths within your computer to the location of a program file. The command terminal will check your Path
variable's paths when you type a command and see if it can find a matching program with that name, then it will run the program with any options you added, like the text "Hello, world".
Making and running a simple .java
program
So now we know how the computer finds a program, and we can see from the list C:\Program Files\Java\jdk-13.0.2\bin
, this is the location of the java
program. This is how we run our Java code, lets make a simple program and run it. Let's stick to the old faithful, slightly modified, it will output "Hello, world, from Main class" to the terminal.
public class Main {
public static main(String[] args) {
System.out.println("Hello, world, from Main class");
}
}
Now we have a program, lets use java
to run it.
D:\Coding\Dev\Classpath example demo>java Main
Error: Could not find or load main class Main
Caused by: java.lang.ClassNotFoundException: Main
Huh, something went wrong. It seems java
couldn't find our class called "Main". Well, there's a hint in the error, java
is looking for a .class
file. A class file is a compiled version of our .java
file, which the computer can understand and execute. If we look at the documentation for java
(always a good idea to read the doc's!) we can see that the structure for a command is java [options] classname [args]
. So how do we get a .class
file? We can use another program called javac
.
javac
, short for Java Compiler, will compile your .java
into a .class
file. Lets give it a go.
D:\Coding\Dev\Classpath example demo>javac Main.java
D:\Coding\Dev\Classpath example demo>dir
Volume in drive D is Data
Volume Serial Number is 64F6-4376
Directory of D:\Coding\Dev\Classpath example demo
26/05/2021 15:42 <DIR> .
26/05/2021 15:42 <DIR> ..
26/05/2021 15:42 414 Main.class
26/05/2021 14:07 162 Main.java
2 File(s) 576 bytes
2 Dir(s) 320,053,022,720 bytes free
dir - lists out all the folders and files in the current directory
You can see here there is a new file created Main.class
. We can now run this file with java
.
D:\Coding\Dev\Classpath example demo>java Main
Hello, world, from Main class
Complicating matters
So this is great. What's the issue with "classpath" then? Lets move our Main.class
and try again to run the program.
D:\Coding\Dev\Classpath example demo>mkdir SubFolder
D:\Coding\Dev\Classpath example demo>move Main.class SubFolder
1 file(s) moved.
D:\Coding\Dev\Classpath example demo>tree /F
Folder PATH listing for volume Data
Volume serial number is 64F6-4376
D:.
│ Main.java
│
└───SubFolder
Main.class
tree /F
prints a folder and file hierarchy to the console
Here we have created a new sub-folder called "SubFolder" and placed Main.class
within. Running the program as before, this happens -
D:\Coding\Dev\Classpath example demo>java Main
Error: Could not find or load main class Main
Caused by: java.lang.ClassNotFoundException: Main
We've lost our Main.class
! So how do we tell java
where it is? We put it on the classpath! Lets do that -
D:\Coding\Dev\Classpath example demo>java -cp ./SubFolder Main
Hello, world, from Main class
.
before/SubFolder
means the path is relative to where we
are in the file system
What we just did is set the classpath with the -cp
option. This tells the JVM where to find the .class
file, and it now runs!
A more "real world" example
Ok, so everything is great, right? Well, right now. In real applications there is a lot of classes and a lot of dependencies. Dependencies are code files which your code depends on, and are usually kept in a library of related files you download and add to your project. These are normally kept outside of your project file structure, usually in a some type of container like a .jar
file. So, lets look at a practical example, when a class is out in another folder on it's on, simulating being a dependency.
First we will create our new java file and update Main.java
with some code that utilises the new class -
public class ExternalClazz {
public void printText() {
System.out.println("Hi from elsewhere");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("Hello, world, from Main class");
ExternalClazz externalClazz = new ExternalClazz();
externalClazz.printText();
}
}
and compile it, along with Main.java
to update that code -
javac ExternalClazz.java
javac Main.java
In fact we could have just used
javac Main.java
, and it would
have compiled both files, as it will parse throughMain.java
and discover it needs to compileExternalClazz.java
for
Main.java
to work correctly
This creates ExternalClazz.class
in our current directory. We can add it to a .jar
file and move it to "Dependency" folder -
D:\Coding\Dev\Classpath example demo>jar cvf MyJar.jar ExternalClazz.class
added manifest
adding: ExternalClazz.class(in = 417) (out= 292)(deflated 29%)
D:\Coding\Dev\Classpath example demo>move MyJar.jar Dependency
1 file(s) moved.
Now the file structure looks like this -
D:.
│ ExternalClazz.java
│ Main.java
│
├───Dependency
│ MyJar.jar
│
└───SubFolder
Main.class
So now we have our Main.class
in a sub-folder, and our main
method has some code which is dependent on a .class
which is in a .jar
file, also in another folder. How do we run this?
D:\Coding\Dev\Classpath example demo>java -cp ./Dependency/MyJar.jar;./SubFolder Main
Hello, world, from Main class
Hi from elsewhere
We have used the argument -cp
to define the classpath, but this time we've used multiple paths. One points to the .jar
file, and the other to where our Main.class
is. Does this remind you of anything? That's right, it's the same as the Path
environment variable, a list of ;
separated paths to target locations.
Developer tools
Now, generally we all use IDEs to make our projects, like InteliJ IDEA, VSCode or Eclipse. Normally these integrated development environments will handle setting the classpath and running the programming, but this is still good knowledge to have and understand.
Here in InteliJ IDEA is where the classpath is set for your project, in run/debug configurations, "Use classpath of module" -
and in VSCode, after installing the Java extension -
IDEs are very powerful tools and handle a lot of the under the bonnet configuration, but should we ever run into issues with these configs we'll already be prepared. There are other tools called "build" tools such as Maven and Gradle, which handle pointing JVM to the right places, which is totally out of the scope of this blog post, but they are incredibly useful and you should spend some time to learn them, too.
TLDR;
The Java classpath is a collection of folder or file paths that tell the Java Virtual Machine where the compiled code is which is to be executed in your program. When it can't find the .class
files your program cannot run, as the JVM can't find it's instructions. "Putting it on the classpath" means making sure compiled java files are in a folder the classpath knows. Otherwise, you will need to specify that folder when you run your java program. Classpath will check the current folder by default, if it can't find the .class
files you need to specify the path with the -cp
or -classpath
argument, more than one path can be separated with a ;
. You can point to .class
files or .jar
files.
I hope this is helpful, please let me know if I missed anything 😃
Header image photo by Alexander Schimmeck on Unsplash
Top comments (0)