JAVA • GETTING STARTED AND TOOLING

Classpath & Directory Structure — Understand classpath and package directory structure (conceptual)

Learn how Java finds your code through packages and the classpath so your programs compile and run correctly.

Historical Context & Motivation

Before Java came along in the mid-1990s, most programming languages left it up to the programmer to figure out where compiled code lived on disk. C and C++ used header files and linker flags, which could become tangled messes on large projects. James Gosling and the team at Sun Microsystems designed Java with a clear goal: write once, run anywhere. To make that slogan a reality, Java needed a predictable way to organize and locate code on every operating system—Windows, Mac, or Linux.

The solution was twofold. First, Java introduced packages—a naming convention that maps directly to folders on disk. Second, it introduced the classpath—a list of locations where the Java Virtual Machine (JVM) should look for compiled class files. Together, these two ideas keep projects organized and allow the JVM to find exactly the right code at compile time and at runtime.

1991
Project Green at Sun Microsystems
James Gosling begins developing what will become Java. Early design decisions emphasize portability and clean code organization.
1995
Java 1.0 Released
The first public release ships with the package system and classpath mechanism already built in. The java.lang and java.util packages establish the convention.
2000
JAR Files Become Standard
Java ARchive (JAR) files bundle entire package trees into a single compressed file. The classpath can now point to JAR files as well as directories.
2017
Java 9 Introduces the Module System
The Java Platform Module System (JPMS) adds a layer above packages, but packages and the classpath remain fundamental for the vast majority of projects.

Understanding classpath and directory structure answers a question every new Java programmer eventually asks: "Why can't Java find my class?" Almost every "class not found" error traces back to a mismatch between the package declaration in your source code and the actual folder layout on disk, or a classpath that doesn't point to the right location.

Core Principles & Definitions

Before diving into diagrams and examples, you need a solid grip on the key vocabulary. Every concept below builds on the one before it, so take them in order.

1

Package

A namespace that groups related classes. Declared at the top of a .java file (e.g., package com.school.math;). Each dot in the package name corresponds to a nested folder on disk.
2

Directory (Folder) Structure

The hierarchy of folders that mirrors the package name. The class com.school.math.Calculator must live at com/school/math/Calculator.java relative to the source root.
3

Classpath

A list of directories and JAR files that tells the JVM where to search for compiled .class files. You set it with the -cp or -classpath flag.
4

Fully Qualified Name (FQN)

The complete name of a class including its package, such as com.school.math.Calculator. The JVM translates dots to directory separators when searching the classpath.
5

JAR File

A Java ARchive that bundles a directory tree of .class files into a single compressed file. You add JARs to the classpath so the JVM can find the classes inside them.
✦ KEY TAKEAWAY
Think of the classpath like the search path on your phone's GPS. The package name is the street address (e.g., 123 Main St, Apt 4B), and the classpath tells the GPS which neighborhoods to look in. If the address is right but the GPS is searching the wrong area, you'll never find the house. Likewise, if your package declaration doesn't match your folder layout—or the classpath points somewhere else—Java will report "class not found."

Visual Explanation — Package-to-Folder Mapping

The diagram below shows how a Java project's source code is organized on disk. Notice how every dot in a package name translates into a nested folder. The source root (often called src) is the top-level directory from which the package folder tree begins.

Each dot in the package declaration com.school.math becomes a nested folder: com → school → math. The Java file sits at the deepest level. The source root src/ is where the folder tree begins.

In the diagram above, Calculator.java declares package com.school.math; at the top of its file. Because of that declaration, it must physically live inside src/com/school/math/. If you moved the file to src/math/ instead, the compiler would complain that the package declaration doesn't match the file's location. This one-to-one mapping between dots and folders is the single most important rule of Java directory structure.

How the Classpath Works

When you compile or run a Java program, you can specify a classpath using the -cp flag. The classpath is simply a list of root directories (and JAR files) separated by a colon on Mac/Linux or a semicolon on Windows. When the JVM needs a class, it converts the fully qualified name into a file path by replacing dots with the system's file separator, then searches each classpath entry in order.

The Class-Loading Algorithm

Suppose your classpath is set to -cp out:lib/helpers.jar and your code references com.school.math.Calculator. The JVM follows these steps:

  1. Convert the FQN to a path: com.school.math.Calculator becomes com/school/math/Calculator.class
  2. Search the first classpath entry: Look for out/com/school/math/Calculator.class. If found, load it and stop.
  3. Search the next classpath entry: Open lib/helpers.jar and look for com/school/math/Calculator.class inside the archive.
  4. If still not found: Throw a ClassNotFoundException or NoClassDefFoundError.
FQN TO FILE PATH CONVERSION
FQN.replace('.', '/') + ".class"
FQN = fully qualified name (e.g., com.school.math.Calculator). Replace every dot with a forward slash, then append .class. The JVM prepends each classpath root to this relative path during its search.
💡 Default Classpath
If you don't specify a -cp flag, the JVM uses the current working directory (.) as the only classpath entry. That's why simple programs work when you compile and run from the project root, but break when you cd somewhere else.

Detailed Breakdown — From Source to Execution

Let's trace the full lifecycle of a Java class from source code to running program. The diagram below shows the two phases—compilation and execution—and highlights where the classpath is consulted in each phase.

Left side: the compiler (javac) turns .java files into .class bytecode. Right side: the JVM (java) loads and runs those .class files. Both phases use the classpath (-cp) to locate code.
Compile vs. Run phase comparison
PhaseToolInputOutput / Action
Compilejavac.java source files.class bytecode files in matching directories
RunjavaFully qualified class name (e.g., com.school.math.Calculator)JVM loads class from classpath and executes main()

Worked Example — Building & Running a Multi-Package Project

Let's walk through creating, compiling, and running a small project that has two packages. You'll see exactly how the directory structure and classpath fit together.

Create and Run a Two-Package Project
1
Step 1 — Plan the PackagesWe want two classes. Greeter lives in package com.demo.greet and Main lives in package com.demo.app. Main will import and use Greeter.
Two packages: com.demo.greet and com.demo.app
2
Step 2 — Create the Directory StructureFrom a project root folder, create the source directories to mirror the packages. We use src as the source root and out as the output root. Run: mkdir -p src/com/demo/greet src/com/demo/app out. This creates the necessary nested folders.
Folders created: src/com/demo/greet/ and src/com/demo/app/
3
Step 3 — Write the Source FilesIn src/com/demo/greet/Greeter.java, write: package com.demo.greet; public class Greeter { public static String hello(String name) { return "Hello, " + name + "!"; } }. In src/com/demo/app/Main.java, write: package com.demo.app; import com.demo.greet.Greeter; public class Main { public static void main(String[] args) { System.out.println(Greeter.hello("World")); } }. Notice that each file's package declaration matches its folder location.
Two .java files saved in the correct directories
4
Step 4 — Compile with the ClasspathFrom the project root, run: javac -cp src -d out src/com/demo/greet/Greeter.java src/com/demo/app/Main.java. The -cp src tells the compiler to look in the src directory for source dependencies. The -d out flag puts the compiled .class files into the out directory, automatically creating matching subfolders.
Compiled files appear at out/com/demo/greet/Greeter.class and out/com/demo/app/Main.class
5
Step 5 — Run with the ClasspathExecute: java -cp out com.demo.app.Main. The -cp out tells the JVM to search the out directory. The JVM converts com.demo.app.Main to com/demo/app/Main.class, finds the file inside out, loads it, and calls main().
Output: Hello, World!

Common Mistakes & How to Fix Them

Even experienced developers occasionally get tripped up by classpath or directory issues. The table below catalogs the most common mistakes and their fixes. Bookmark this section—you'll come back to it.

Top 5 classpath and directory mistakes
MistakeSymptomFix
Package declaration doesn't match folderCompiler error: "class X is public, should be declared in a file named X.java" or similarMove the file so the folder path matches the package declaration, or update the package line.
Classpath points to wrong directoryClassNotFoundException at runtimeSet -cp to the root directory that contains the top-level package folder (e.g., out), not the package folder itself.
Using file path instead of FQN to runError: "Could not find or load main class"Run with java -cp out com.demo.app.Main, not java out/com/demo/app/Main.class
Missing a JAR from the classpathNoClassDefFoundError at runtimeAdd the JAR to the -cp list. Example: -cp out:lib/gson.jar
Wrong separator characterOnly the first classpath entry worksUse : on Mac/Linux and ; on Windows to separate entries.
✦ KEY TAKEAWAY
The classpath should point to the root of the package tree, not to the package folders themselves. Think of it like telling someone to start searching for a book at the front door of the library, not inside a specific aisle. The FQN is the call number that guides you from the front door to the exact shelf.

Connection to Build Tools & the Module System

As projects grow larger, managing the classpath by hand becomes tedious. Modern Java development relies on build tools like Maven and Gradle to download library JARs automatically and set the classpath for you. These tools enforce a standard directory layout so every developer on a team knows exactly where to put source files and where compiled output will appear.

Classpath management approaches compared
FeatureManual ClasspathBuild Tool (Maven/Gradle)Module System (Java 9+)
How you set it-cp flag on command lineDeclared in pom.xml or build.gradlemodule-info.java defines exports and requirements
DependenciesDownload JARs yourself and list themAuto-downloaded from repositoriesExplicit requires directives
Directory conventionYour choice (e.g., src and out)src/main/java and src/test/javaSame as build tools, plus module-info.java at module root
Best forLearning, small scriptsReal-world projects of any sizeLarge-scale, modular applications

Even though build tools and modules abstract away much of the manual work, they all still rely on the same underlying concepts you learned in this lesson. Understanding how packages map to folders and how the classpath guides the JVM will make you a better debugger and a more confident developer when things go wrong.

🚀 Looking Ahead
When you start learning Maven or Gradle, you'll notice that they enforce the directory src/main/java as the source root. Everything you know about packages and the classpath still applies—only the exact root folder name changes.

Practice Problems

PROBLEM 1 — CONCEPTUAL
A Java file begins with package org.robotics.sensors;. The file is named Lidar.java. What is the correct path for this file relative to the source root?
PROBLEM 2 — BASIC CALCULATION
You compile your project with javac -d build src/org/robotics/sensors/Lidar.java. Where will the compiled .class file end up? Write the full relative path.
PROBLEM 3 — INTERMEDIATE
Your project has these classes: com.game.engine.Renderer and com.game.ui.Menu. The compiled .class files are in the out directory, and you also need a third-party library at lib/audio.jar. Write the complete java command to run Menu on a Mac/Linux system.
PROBLEM 4 — APPLIED
A teammate sends you a project and says, "Just run java Main from the project folder." You try it and get Error: Could not find or load main class Main. The Main.java file starts with package com.project; and the compiled file is at bin/com/project/Main.class. What went wrong, and what is the correct command?
PROBLEM 5 — CRITICAL THINKING
Suppose two different JAR files on your classpath each contain a class with the fully qualified name com.utils.StringHelper. Which version does the JVM load, and what problems could this cause? How does the Java Module System (introduced in Java 9) help prevent this?

Lesson Summary

Java's package system provides a naming convention that groups related classes and maps directly to nested directories on disk. Every dot in a fully qualified name (like com.school.math.Calculator) becomes a folder separator, so the source file must live at com/school/math/Calculator.java relative to the source root. When this one-to-one mapping is broken, the compiler or JVM cannot find your class.

The classpath is a list of root directories and JAR files where the JVM searches for compiled .class files. Set it with the -cp flag during both compilation (javac) and execution (java). Build tools like Maven and Gradle automate classpath management for larger projects, and the Module System adds an extra layer of organization for advanced applications. Mastering these fundamentals ensures you can diagnose and fix "class not found" errors quickly and confidently.

Varsity Tutors • Java • Classpath & Directory Structure