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.

Java programming emblem with a coffee cup, code braces, and terminal
Inside this lesson 10 sections 5 questions 6 figures

SECTION 1

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.

SECTION 2

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."

SECTION 3

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.

Package → Directory Mappingsrc/com/school/math/util/Calculator.javaGraph.javaLogger.javaFull path: src/com/school/math/Calculator.javaPackage: package com.school.math;FQN: com.school.math.Calculator
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.

SECTION 4

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.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.

SECTION 5

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.

Compilation & Execution FlowCOMPILE TIME (javac)RUN TIME (java)Calculator.javajavac compiles-cp tells javac whereto find dependenciesCalculator.classOutput in matching folder:out/com/school/math/Calculator.classJVM class loader-cp tells JVM whereto find .class filesProgram runs ✓Or throws ClassNotFoundExceptionif classpath is wrong ✗
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.
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()

Compile vs. Run phase comparison

SECTION 6

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. 1

    Step 1 — Plan the Packages

    We 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. 2

    Step 2 — Create the Directory Structure

    From 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. 3

    Step 3 — Write the Source Files

    In 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. 4

    Step 4 — Compile with the Classpath

    From 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. 5

    Step 5 — Run with the Classpath

    Execute: 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!

SECTION 7

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.

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.

Top 5 classpath and directory mistakes

✦

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.

SECTION 8

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.

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

Classpath management approaches compared

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.

SECTION 9

Practice Problems

Question 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?
Show answer
The correct relative path is org/robotics/sensors/Lidar.java. Each dot in the package name org.robotics.sensors translates into a nested directory: org → robotics → sensors. The Java file must sit inside the deepest folder. If your source root is src/, the full path on disk would be src/org/robotics/sensors/Lidar.java.

Question 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.
Show answer
The compiled file will be at build/org/robotics/sensors/Lidar.class. The -d build flag tells javac to use build as the output root. The compiler automatically recreates the package folder structure under the output root, so the class file mirrors the package hierarchy inside the build directory.

Question 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.
Show answer
The command is: java -cp out:lib/audio.jar com.game.ui.Menu. On Mac/Linux, classpath entries are separated by a colon. The first entry out is where your compiled classes live, and lib/audio.jar is the third-party library. The JVM will search both locations. The last argument is the fully qualified name of the class with the main method—no .class extension, no slashes.

Question 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?
Show answer
Two things went wrong. First, because Main is in package com.project, you must use the fully qualified name: com.project.Main. Second, the default classpath is the current directory, but the class files are in bin/, not the project root. The correct command is: java -cp bin com.project.Main. This sets the classpath to bin so the JVM can find bin/com/project/Main.class.

Question 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?
Show answer
The JVM searches classpath entries in the order they appear. It loads the first com.utils.StringHelper it finds and ignores the second one entirely. This can cause subtle bugs: if your code depends on behavior in the second version of StringHelper, the program may compile fine but crash or behave unexpectedly at runtime. This issue is sometimes called "classpath hell" or "JAR hell." The Java Module System addresses this by requiring explicit requires and exports declarations in a module-info.java file. If two modules export the same package, the JVM detects the conflict at startup and reports an error instead of silently loading the wrong class.

SUMMARY

Lesson Summary

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