Java Classpath and Packages Explained with Examples

A Java package gives a class a qualified name, while the classpath tells the compiler or runtime where to find class roots and libraries.

Lesson 98 of 127Intermediate14 min read

A Java package gives a class a qualified name, while the classpath tells the compiler or runtime where to find class roots and libraries. They are related but not interchangeable. A source declaring package museum.labels has the binary name museum.labels.Ticket, and its compiled file belongs beneath museum/labels under a classpath root. Most class-not-found mistakes come from selecting the package folder instead of its parent root or launching only the simple class name.

Declare a logical namespace

A package declaration appears before imports and type declarations. It places your class in a namespace, reducing name collisions and grouping related code. Package names are conventionally lowercase and often begin with a reversed organization domain for published libraries. Directory organization should mirror the package structure for clarity and tool support. A package is not created by import statements: imports only let source code refer to existing types with shorter names.

Understand the binary class name

The compiler and launcher identify a packaged top-level class by its fully qualified name, such as museum.labels.Ticket. The runtime maps that name to a path beneath each classpath entry. If out contains museum/labels/Ticket.class, out is the root. Selecting out/museum/labels as the classpath would make the runtime search for another museum/labels hierarchy below it. This extra nesting explains a common failed launch even though the file visibly exists.

Compile source into a known output root

javac -d out writes compiled classes into a directory structure matching their packages. That avoids placing class files beside source merely because of your current working directory. Compile mutually dependent files together or give javac an appropriate classpath for already compiled dependencies. The compiler's search path and the runtime's search path are separate configurations; a library available during compilation must also be available during execution when its classes are needed.

Import names without copying code

An import such as import java.util.List permits the simple name List in source. It does not download a library, copy a class into your file, or select a runtime classpath. Wildcard imports cover types directly in one package, not all nested subpackages. Fully qualified names remain usable without imports. If two imported types share a simple name, qualify one explicitly so the source clearly identifies which type you intend.

Add libraries using the correct separator

Classpath entries can be directories or JAR files. Windows separates entries with a semicolon, while Unix-style environments commonly use a colon. Quote a classpath expression when the shell would otherwise split it or treat its separator specially. The java -cp option specifies the application classpath for that command and overrides the usual CLASSPATH environment setting. Build tools normally manage these entries, but understanding them helps diagnose missing dependencies.

Separate classpath from module path

The Java module system adds named modules and a module path, but ordinary classpath applications remain supported. A JAR on the classpath participates in the unnamed module rather than becoming an explicitly named module solely because it is a JAR. Module declarations introduce additional readability and exported-package rules. Start with a clear classpath layout, then learn modules as an extra dependency boundary instead of treating module path as a synonym for classpath.

Practice tasks and checks

Create src/museum/labels/Ticket.java with package museum.labels and a main method printing a ticket message. Compile it into out and inspect the generated directories before running the qualified class name. Then deliberately launch Ticket without its package and explain the lookup failure. Restore the qualified name and deliberately change the classpath to out/museum/labels; identify the duplicated package path the runtime would search beneath that root. Finally, create a second class in the same package and compile both source files together. Use an import only when you move the second class into another package. This exercise should connect declarations, filenames, output layout, and launch naming instead of treating each error as a missing Java installation.

Java Summary

  • A classpath entry is the root above its package directories.
  • Launch packaged classes with their fully qualified names.
  • Imports do not download dependencies or configure runtime lookup.
  • Continue with module boundaries when these examples are clear.

Java Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Keep an unpackaged reference example

Save this program as ClasspathCheck.java. Compile it with javac ClasspathCheck.java and run it with java ClasspathCheck.

Expected output:

This class has no package declaration, so its binary name is the simple name. If javac -d out creates out/ClasspathCheck.class, java -cp out ClasspathCheck can locate it. Printing Class.getName makes the naming rule visible. This is a starting comparison, not a recommendation to keep all application classes in the unnamed package as projects grow.

Java
public class ClasspathCheck {
    public static void main(String[] args) {
        System.out.println(ClasspathCheck.class.getName());
    }
}
Output
ClasspathCheck
Example 2

Provide the packaged source

Save the packaged source at the path explained below and use the accompanying compile and launch commands.

Expected output after the accompanying package launch commands:

Save this complete source as src/museum/labels/Ticket.java. The package declaration gives Ticket its qualified name museum.labels.Ticket. The next compilation command places its bytecode under out with the matching package directories, and the launch command uses that qualified name. Its fixed message lets you verify that the intended application ran. This packaged file and the earlier unnamed ClasspathCheck intentionally demonstrate different naming rules.

Java
package museum.labels;
public class Ticket {
    public static void main(String[] args) {
        System.out.println("Museum ticket ready");
    }
}
Output
Museum ticket ready
Example 3

Compile and launch a packaged application

Use the following shell commands or configuration.

What to expect: Museum ticket ready

Ticket.java must declare package museum.labels and contain an appropriate main method. The compiler writes out/museum/labels/Ticket.class. The runtime starts its search at out and uses the fully qualified class name to locate that file. These commands intentionally do not put the final package directory on the classpath. The source path and output path serve different roles even though both mirror package naming.

SHELL
javac --release 17 -d out src/museum/labels/Ticket.java
java -cp out museum.labels.Ticket
Example 4

Add a JAR on Windows

Use the following shell commands or configuration.

What to expect: Museum ticket ready, provided helper.jar exists and the class is compiled as shown.

The quoted expression contains two classpath entries separated by the Windows semicolon. A corresponding Unix-style command uses out:lib/helper.jar. The JAR must really exist and provide the needed classes; writing its name in the command does not fetch it. If Ticket uses a helper class, leaving the JAR off the runtime classpath can produce NoClassDefFoundError even if compilation previously succeeded with the library present.

SHELL
java -cp "out;lib/helper.jar" museum.labels.Ticket

Java FAQ

Does import install a dependency?

No. It changes how a source file names a type. A third-party dependency must separately be available to compilation and execution, usually through a build tool or explicit classpath.

Why is my class file present but not found?

Check the full binary name and the classpath root above the package directories. Also check capitalization and whether the command runs from the directory you expect. A visible file in the wrong relative layout is not sufficient.

What is a JAR file?

A JAR is a zip archive of compiled classes and resources, with a manifest file describing it. Libraries are distributed as JARs and added to the classpath. An application JAR whose manifest names a Main-Class can be run with java -jar app.jar.

What is the default classpath?

If you don't set one, the classpath is the current directory. As soon as you pass -cp or set the CLASSPATH variable, that value replaces the default, so include . or your out folder explicitly if your own classes live there.

Should I set the CLASSPATH environment variable?

Generally not. A global CLASSPATH affects every Java command you run and causes confusing errors when projects need different libraries. Pass -cp on the command line for small experiments, and let Maven or Gradle build the classpath for real projects.

Java Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choiceeasy

Where is the classpath root for out/museum/labels/Ticket.class?

Multiple choicemedium

Which launch name matches package museum.labels?

Java Quiz

2 questions to check what you learned.

  1. What does an import change?

    • Source name resolution
    • The downloaded libraries
    • The current runtime directory
  2. Which separator joins Windows classpath entries?

    • Semicolon
    • Comma
    • A package dot