Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Java  Module 5 – Classes, objects, records and enums

Packages, imports and the class path

Put Java classes in packages that match their folders, use single-type, on-demand, static and module imports, and run programs with javac -d and java -cp.

  • Beginner
  • 15 minutes
  • Examples run with Java 25.0.4 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 15 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Organise classes into packages whose folders match their names, and run a class by its full name
  • Use single-type, on-demand, static and module imports
  • Resolve a simple name that two imports offer
  • Predict where java looks for a class on a class path of folders and JAR files
  • Diagnose a NoClassDefFoundError caused by a class path that differs between compiling and running

Before you start

What you’ll learn · Before you start

What you will learn

  • Organise classes into packages whose folders match their names, and run a class by its full name
  • Use single-type, on-demand, static and module imports
  • Resolve a simple name that two imports offer
  • Predict where java looks for a class on a class path of folders and JAR files
  • Diagnose a NoClassDefFoundError caused by a class path that differs between compiling and running

Before you start

On this page

javac -d out wrote Main.class into out/com/example/library/app/, and java -cp out Main still fails: a class in a package is found only by its full name, one folder for each part of it. A package: A named group of classes, such as com.example.shop, declared on the first line of a source file. javac -d stores its class files in folders that follow the name, and java runs such a class by its full name. More in “Classic main, javac and .class files” is a named group of classes, declared with a first line such as package com.example.library.model;, and it maps onto those folders. An import lets code use a class from another package by its simple name, Book instead of com.example.library.model.Book.

The class path: The folders and JAR files in which the JVM looks for classes, given with -cp or --class-path. Without it, and without a CLASSPATH environment variable, it is the current folder. More in “Classic main, javac and .class files” is the list of folders and JAR files where java looks for compiled classes. This lesson builds a small two-package program, compiles and runs it the right way and two wrong ways, settles which Date a file gets when two imports offer one, and packs one package into a JAR to show what the class path does at run time. The commands below ran on the JDK of Eclipse Temurin 25.0.4.1, a Java 25 release.

A package name is a path of folders

The program has two packages. com.example.library.model holds the data, Book and Catalogue, and com.example.library.app holds the program, Main. The names follow the convention of JLS 6.1: start from a domain name you control, reversed, here example.com, a domain reserved for examples (RFC 2606), so that two organisations never choose the same package name.

library/src/com/example/library/app/Main

library/src/com/example/library/app/Main.java

package com.example.library.app;

import com.example.library.model.Book;
import com.example.library.model.Catalogue;

public class Main {
    public static void main(String[] args) {
        Catalogue catalogue = new Catalogue();
        catalogue.add(new Book("Gitanjali", "Rabindranath Tagore", 3));
        catalogue.add(new Book("Godaan", "Premchand", 2));
        IO.println(catalogue.size() + " titles, " + catalogue.copiesOf("Godaan") + " copies of Godaan");
        IO.println("this class is " + Main.class.getName());
    }
}

library/src/com/example/library/model/Book.java

package com.example.library.model;

/** A title in the catalogue and how many copies the library owns. */
public record Book(String title, String author, int copies) {}

library/src/com/example/library/model/Catalogue.java

package com.example.library.model;

import java.util.ArrayList;
import java.util.List;

/** The library's books. Code in other packages sees only the public methods. */
public class Catalogue {
    private final List<Book> books = new ArrayList<>();

    public void add(Book book) {
        books.add(book);
    }

    public int copiesOf(String title) {
        int copies = 0;
        for (Book book : books) {
            if (book.title().equals(title)) {
                copies += book.copies();
            }
        }
        return copies;
    }

    public int size() {
        return books.size();
    }
}
Compile into out, run by the full name, and two wrong runs Python · packages_session.py
from session import run

# Compile the three files into out, then run the class by its full name; then two ways to get it wrong,
# and the source launcher, which works out the source root from the package.
run(
    """
find library/src -name "*.java" | sort
javac -d out $(find library/src -name "*.java")
find out -name "*.class" | sort
java -cp out com.example.library.app.Main
java -cp out Main
java com.example.library.app.Main
java library/src/com/example/library/app/Main.java
""",
    fails=("java -cp out Main", "java com.example.library.app.Main"),
)

Output

# openjdk version "25.0.4.1" LTS
$ find library/src -name "*.java" | sort
library/src/com/example/library/app/Main.java
library/src/com/example/library/model/Book.java
library/src/com/example/library/model/Catalogue.java
$ javac -d out $(find library/src -name "*.java")
$ find out -name "*.class" | sort
out/com/example/library/app/Main.class
out/com/example/library/model/Book.class
out/com/example/library/model/Catalogue.class
$ java -cp out com.example.library.app.Main
2 titles, 2 copies of Godaan
this class is com.example.library.app.Main
$ java -cp out Main
Error: Could not find or load main class Main
Caused by: java.lang.ClassNotFoundException: Main
[exit status 1]
$ java com.example.library.app.Main
Error: Could not find or load main class com.example.library.app.Main
Caused by: java.lang.ClassNotFoundException: com.example.library.app.Main
[exit status 1]
$ java library/src/com/example/library/app/Main.java
2 titles, 2 copies of Godaan
this class is com.example.library.app.Main

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 packages_session.py

Step through the session: the folders the files live in are on the left, and each command on the right either finds its class by the folders or does not:

Interactive · step by step From package names to folders, and back to a running class Step through the session. The left column is the folders the files live in; the right column is the command that runs.
From package names to folders, and back to a running class, step 6 of 6. Showing src/…/library/app, src/…/library/model, out/…/library/app (Main.class), out/…/library/model (Book.class, Catalogue.class), javac -d out, java -cp out (full name) (runs: 2 titles), java -cp out Main (ClassNotFoundException), java (full name), no -cp (ClassNotFoundException), java …/app/Main.java (runs: the same two lines). In focus: java …/app/Main.java, src/…/library/app, src/…/library/model.src/…/library/appMain.javasrc/…/library/modelBook.java, Catalogue.javaout/…/library/appMain.classout/…/library/modelBook.class, Catalogue.classjavac -d outevery source filejava -cp out (full name)runs: 2 titlesjava -cp out MainClassNotFoundExceptionjava (full name), no -cpClassNotFoundExceptionjava …/app/Main.javaruns: the same two lines

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. One folder per part. Each part of the package name is one folder below the source root library/src: com/example/library/app holds Main.java, and com/example/library/model holds Book.java and Catalogue.java.
  2. javac -d out. javac -d out writes each class file into the same folders below out, creating them as needed: out/com/example/library/app/Main.class and the two model classes.
  3. Run by the full name. java -cp out com.example.library.app.Main turns the full name into the path com/example/library/app/Main.class below out, finds it and runs: 2 titles, 2 copies of Godaan.
  4. The simple name fails. java -cp out Main looks for out/Main.class. No class is called just Main, so the run stops: Could not find or load main class Main.
  5. No class path given. java com.example.library.app.Main, with no -cp and no CLASSPATH variable, searches only the current folder, which has no com folder, so it fails the same way.
  6. The source launcher. java library/src/com/example/library/app/Main.java reads the file's package, works out that library/src is the source root, and compiles the model classes from there. It prints the same two lines.

  • The source folders follow the packages. Each part of the package name is one folder, below a source root, here library/src. JLS 7.2 describes this layout for packages kept in a file system, and javac’s source path, the launcher and build tools such as Maven expect it.
  • javac -d out writes the same folders. The class files land in out/com/example/library/..., one folder per part of the package name, created as needed. The $(find ...) part is the shell’s way of passing every source file to javac.
  • Run the class by its full name, with the output folder on the class path. java -cp out Main fails, because no class is called just Main. The fully qualified name: A class's name with its package in front, such as com.example.library.model.Book. The JVM turns it into the path com/example/library/model/Book.class, and java runs a class in a package only by this name., com.example.library.app.Main, is what the JVM turns into a path. With no -cp and no CLASSPATH variable, the class path is only the current folder, so java com.example.library.app.Main looks for ./com/example/library/app/Main.class and finds nothing.
  • The source launcher works too. java library/src/com/example/library/app/Main.java read the file’s package, worked out that library/src is the root of the source tree, and compiled the model classes from there (JEP 458).

Two more facts about packages matter in practice. Main used Book because Book is public; a class without a modifier would be invisible outside its package, as the encapsulation lesson showed. And packages whose names share a prefix are not related: code in com.example.library.app has no special access to com.example.library.model (JLS 7.1), and an import of one does not import the other.

When the folder and the package disagree

Nothing forces a file’s package declaration to match the folder it is saved in. Helper.java sits in com/example/tools/ but declares package com.example.util;:

wrong/com/example/tools/Helper.java Java
package com.example.util;

/** Declared in com.example.util, but saved in the folder com/example/tools. */
public class Helper {
    public static void main(String[] args) {
        IO.println("Helper runs");
    }
}
javac follows the declaration, the launcher follows the folders Python · mismatch_session.py
from session import run

# javac files the class under its declared package; the source launcher insists that the folders match it.
run(
    """
javac -d out wrong/com/example/tools/Helper.java
find out -name "*.class"
java wrong/com/example/tools/Helper.java
""",
    fails=("java wrong/com/example/tools/Helper.java",),
)

Output

# openjdk version "25.0.4.1" LTS
$ javac -d out wrong/com/example/tools/Helper.java
$ find out -name "*.class"
out/com/example/util/Helper.class
$ java wrong/com/example/tools/Helper.java
error: end of path to source file does not match its package name com.example.util: wrong/com/example/tools/Helper.java
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 mismatch_session.py

Given the file by name, javac compiled it without a word and filed the class under its declared package, out/com/example/util/. The source launcher refused it, and so would any tool that looks for com.example.util.Helper in com/example/util/Helper.java, such as javac with --source-path. Keep every file in the folder its package names, and the question never comes up.

Checkpoint

Check: Packages as folders

  1. Question 1 of 2 Book.java starts with package com.example.shop; and is compiled with javac -d out. Where does Book.class go?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: out/com/example/shop/Book.class

    With -d, javac writes each class into folders that follow its package name, one folder per part, creating them as needed. The session listed out/com/example/library/app/Main.class the same way.

  2. Question 2 of 2 Main is declared in package com.example.library.app and compiled into out. Why does java -cp out Main fail?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: A class in a package must be named in full: java -cp out com.example.library.app.Main

    The JVM turns the name into a path below each class path entry. Main alone becomes out/Main.class, which does not exist; the full name becomes out/com/example/library/app/Main.class, which does.

An import changes only which simple names a file can use

An import loads nothing and copies nothing: the class file stores full names either way. It only changes which simple names the compiler understands. Kinds.java uses one import of each kind:

imports/Kinds.java Java
import java.util.List;            // a single-type import: one class
import java.time.*;               // an on-demand import: every public class of java.time
import static java.lang.Math.max; // a static import: one static member of a class
import module java.net.http;      // a module import: every package that java.net.http exports

class Kinds {
    static void main() {
        List<String> shifts = List.of("morning", "evening");
        DayOfWeek reopens = DayOfWeek.FRIDAY.plus(3);
        int larger = max(3, 9);
        HttpClient.Version version = HttpClient.Version.HTTP_2;
        IO.println(shifts + " " + reopens + " " + larger + " " + version);
    }
}
Four imports, then what two modules export Python · kinds_session.py
from session import run

# The four kinds of import in one file, then what two modules export (sorted: the JDK lists a module's
# requirements in no fixed order).
run(
    """
java imports/Kinds.java
java --describe-module java.base | grep -c "^exports "
java --describe-module java.base | grep "^exports java.lang.classfile"
java --describe-module java.sql | sort
"""
)

Output

# openjdk version "25.0.4.1" LTS
$ java imports/Kinds.java
[morning, evening] MONDAY 9 HTTP_2
$ java --describe-module java.base | grep -c "^exports "
58
$ java --describe-module java.base | grep "^exports java.lang.classfile"
exports java.lang.classfile
exports java.lang.classfile.attribute
exports java.lang.classfile.constantpool
exports java.lang.classfile.instruction
$ java --describe-module java.sql | sort
exports java.sql
exports javax.sql
java.sql@25.0.4.1
requires java.base mandated
requires java.logging transitive
requires java.transaction.xa transitive
requires java.xml transitive
uses java.sql.Driver

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 kinds_session.py

Import What it makes usable by simple name
import java.util.List; (single-type import: An import of one class or interface by its full name, such as import java.util.List;. It shadows a class of the same simple name that an on-demand or module import would bring.) One class or interface
import java.time.*; (on-demand import: An import that ends in .*, such as import java.time.*;. It makes every public class and interface of one package usable by its simple name, but not those of its subpackages.) Every public class and interface of one package, not of its subpackages
import static java.lang.Math.max; (static import: An import static declaration, such as import static java.lang.Math.max;. It makes a static member of a class, or with .* all of them, usable without the class name in front.) A static member of a class; import static java.lang.Math.*; brings all of them
import module java.net.http; (module import: An import module declaration, such as import module java.base; (JEP 511). It makes every public class and interface of every package the module exports usable by its simple name. Compact source files import java.base this way., JEP 511) Every public class of every package the module exports

java --describe-module shows what a module offers. On this JDK, java.base exports 58 packages, which is what every compact source file imports implicitly. JEP 511 gives 54; the difference is the four java.lang.classfile packages of the Class-File API, a standard API since Java 24 (JEP 484). java.sql exports two packages, java.sql and javax.sql, and its requires ... transitive lines matter too: import module java.sql; also imports what java.logging, java.transaction.xa and java.xml export, because code that uses java.sql needs their types.

Expecting java.util.* to cover java.util.function

An on-demand import covers one package. import java.util.*; gives List and Map but not Function, which lives in java.util.function: import java.util.function.Function too, or use import module java.base;.

Checkpoint

Check: The four kinds of import

  1. Question 1 of 2 What does import static java.lang.Math.max; let Kinds.java write?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: max(3, 9), without Math. in front

    Single-type and on-demand imports bring classes; static imports bring static members of a class, one by name or all of them with Math.*. Kinds.java printed 9 for max(3, 9).

  2. Question 2 of 2 A named class in its own file, not a compact source file, has import java.util.*; and uses Function, which is in java.util.function. Does it compile?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: No: an on-demand import covers one package, not its subpackages

    Packages whose names share a prefix are unrelated as far as the language is concerned, and a named class gets no implicit import of java.base. On JDK 25 such a class stops with cannot find symbol for Function. Import java.util.function.Function, or java.util.function.*, or import module java.base;.

When two imports offer one name, the more specific kind wins

java.base exports java.util, which has a Date class, and java.sql has a Date of its own. Three files ask for Date:

imports/Ambiguous

imports/Ambiguous.java

import module java.sql;

void main() {
    Date due = new Date(0);
    IO.println(due.getClass().getName());
}

imports/Resolved.java

import module java.sql;
import java.sql.Date;

void main() {
    Date due = new Date(0);
    IO.println(due.getClass().getName());
}

imports/Silent.java

import java.sql.*;

void main() {
    Date due = new Date(0);
    IO.println(due.getClass().getName());
}
An ambiguous name, a fixed one, and a silent winner Python · ambiguity_session.py
from session import run

# Date is in java.util (exported by java.base) and in java.sql: which one does each file get?
run(
    """
java imports/Ambiguous.java
java imports/Resolved.java
java imports/Silent.java
""",
    fails=("java imports/Ambiguous.java",),
)

Output

# openjdk version "25.0.4.1" LTS
$ java imports/Ambiguous.java
imports/Ambiguous.java:4: error: reference to Date is ambiguous
    Date due = new Date(0);
    ^
  both class java.sql.Date in java.sql and class java.util.Date in java.util match
imports/Ambiguous.java:4: error: reference to Date is ambiguous
    Date due = new Date(0);
                   ^
  both class java.sql.Date in java.sql and class java.util.Date in java.util match
2 errors
error: compilation failed
[exit status 1]
$ java imports/Resolved.java
java.sql.Date
$ java imports/Silent.java
java.sql.Date

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 ambiguity_session.py

All three are compact source files, so each starts with an implicit import module java.base;. Step through how javac settles Date in each of them:

Interactive · stage by stage Which Date does each file get? Step through the three files. javac looks for Date in the import kinds from the top; the arrows on the side are where it stops.
Which Date does each file get?, step 7 of 7. Showing Single-type imports (none in Silent.java), On-demand imports (java.util.*, java.sql.*), Module imports (shadowed), The name Date (ambiguous). In focus: On-demand imports, The name Date.found: it winsfound: it winsSingle-type importsnone in Silent.javaOn-demand importsjava.util.*, java.sql.*Module importsshadowedThe name Dateambiguous

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. Ambiguous.java: no single-type. Ambiguous.java has no single-type import of Date, so javac looks further down.
  2. No on-demand import. It has no on-demand import either, only import module java.sql; and the implicit import module java.base;.
  3. Two modules, two Dates. java.sql exports java.sql, which has a Date, and java.base exports java.util, which has another. Two imports of the same kind offer the name.
  4. Ambiguous. javac stops with reference to Date is ambiguous, twice: once for the type of due and once for new Date(0).
  5. Resolved.java. Resolved.java adds import java.sql.Date;. A single-type import shadows on-demand and module imports, so the search stops at the top and the run prints java.sql.Date.
  6. Silent.java. Silent.java has only import java.sql.*;. An on-demand import shadows module imports, the implicit java.base included, so Date is java.sql.Date with no error and no warning.
  7. Two on-demand imports. In an ordinary class, import java.util.; with import java.sql.; is ambiguous instead: both imports are on demand, equally specific, and each offers a Date.

  • In Ambiguous.java, two module imports offer a Date each, so the name is ambiguous and the file does not compile.
  • In Resolved.java, import java.sql.Date; settles it. A single-type import shadows the classes of the same name from on-demand and module imports (JLS 6.4.1).
  • Silent.java is the trap. An on-demand import, import java.sql.*;, also shadows module imports, so Date became java.sql.Date with no error and no warning. In an ordinary class, import java.util.*; with import java.sql.*; is ambiguous instead, because two on-demand imports are equally specific.

The order of the import lines never matters; only their kinds do. When two packages share a name, import the one you mean by its full name, so the file says which class it uses.

Key idea

A single-type import beats an on-demand import, which beats a module import; two imports of the same kind that offer one name make it ambiguous, and the order of the lines never decides anything.

Checkpoint

Check: Two imports, one name

  1. Question 1 of 2 What happens when this class is compiled?

    Read the code, then choose one answer.

    import java.util.*;
    import java.sql.*;
    
    class Due {
        Date date = new Date(0);
    }
    Show the answer: Question 1 of 2

    Answer: A compile error: the reference to Date is ambiguous

    Two on-demand imports that both provide a Date are equally specific, so the simple name is ambiguous. A single-type import such as import java.sql.Date; decides it, because single-type imports shadow on-demand ones.

  2. Question 2 of 2 A compact source file adds import java.sql.*; and then uses Date. Which Date is it?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: java.sql.Date, because an on-demand import shadows the implicit import module java.base;

    A compact file imports module java.base implicitly, and an on-demand import is more specific than a module import, so it wins without any warning. The lesson's run printed java.sql.Date for exactly this file.

The class path is searched in order, and the first match wins

The class path is a list of folders and JAR files, separated by : on Linux and macOS and by ; on Windows. A JAR file: A ZIP archive of class files kept in their package folders, with a manifest in META-INF/MANIFEST.MF. Put on the class path, it is searched for classes like a folder. is a ZIP archive of class files, laid out in the same package folders. To find a class, the JVM turns its name into a path, com/example/library/model/Book.class, and searches the entries in order, using the first one that has it:

The class name becomes a file path, which is looked up in each class path entry in turn; the first entry that has it wins.Class name:com.example.library.model.BookPath:com/example/library/model/Book.class1st entry, app-out:is the path there?2nd entry, the JAR:is the path in it?Loaded from thefirst entry with itIn no entry:the run failsyesnoyesno

How the class path finds a class

Text description of the diagram

The diagram shows how java -cp app-out:library-model.jar com.example.library.app.Main finds the class com.example.library.model.Book.

  1. The class name com.example.library.model.Book becomes the relative path com/example/library/model/Book.class: one folder per part of the package name.
  2. The first class path entry, the folder app-out, is searched for that path.
  3. If it is not there, the second entry, the JAR file library-model.jar, is searched for the same path inside the JAR.
  4. The class is loaded from the first entry that has it, so the order of the entries matters when two of them contain the same class.
  5. If no entry has it, loading fails: with ClassNotFoundException when the class was asked for by name, such as the main class, or with NoClassDefFoundError when compiled code needs a class that is missing at run time.

-cp (also spelled --class-path or -classpath) sets the list for one command and overrides the CLASSPATH environment variable; with neither, the class path is just the current folder. A class path entry ending in *, such as lib/*, stands for every JAR file in that folder. Because the first entry that has a class wins, the order of the entries matters whenever two of them contain the same class.

Checkpoint

Check: How the class path is searched

  1. Question 1 of 2 The JVM needs com.example.library.model.Book. Which path does it look for in each class path entry?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: com/example/library/model/Book.class

    The JVM turns the class name into a relative path, com/example/library/model/Book.class, and looks for it in each entry in turn, folder or JAR, using the first entry that has it.

  2. Question 2 of 2 The class path is app-out:library-model.jar. Where does the JVM load com.example.library.app.Main from, and where Catalogue?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Main from app-out, Catalogue from the JAR

    The search runs per class, entry by entry, in order. The first run of the session found Main in app-out and the model classes in library-model.jar, and printed 2 titles, 2 copies of Godaan.

A class that was there at compile time can be missing at run time

Here the model package goes into a JAR, Main is compiled against it, and then run with and without it:

A JAR on the class path, then the same run without it Python · classpath_session.py
from session import run

# The model classes go into a JAR file; the app is compiled against it, run with it, and run without it.
run(
    """
javac -d model-out library/src/com/example/library/model/*.java
jar --create --file library-model.jar -C model-out .
jar --list --file library-model.jar
javac -d app-out -cp library-model.jar library/src/com/example/library/app/Main.java
java -cp app-out:library-model.jar com.example.library.app.Main
java -cp app-out com.example.library.app.Main
""",
    fails=("java -cp app-out com.example.library.app.Main",),
)

Output

# openjdk version "25.0.4.1" LTS
$ javac -d model-out library/src/com/example/library/model/*.java
$ jar --create --file library-model.jar -C model-out .
$ jar --list --file library-model.jar
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/library/
com/example/library/model/
com/example/library/model/Book.class
com/example/library/model/Catalogue.class
$ javac -d app-out -cp library-model.jar library/src/com/example/library/app/Main.java
$ java -cp app-out:library-model.jar com.example.library.app.Main
2 titles, 2 copies of Godaan
this class is com.example.library.app.Main
$ java -cp app-out com.example.library.app.Main
Exception in thread "main" java.lang.NoClassDefFoundError: com/example/library/model/Catalogue
	at com.example.library.app.Main.main(Main.java:8)
Caused by: java.lang.ClassNotFoundException: com.example.library.model.Catalogue
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:490)
	... 1 more
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 classpath_session.py

Step through the same commands and watch where each class Main needs is found:

Interactive · step by step The same program, with the JAR and without it Step through the session. The left column is the class path of each run; the right column is each class Main needs, and where it was found.
The same program, with the JAR and without it, step 6 of 6. Showing app-out, com…app.Main, com…model.Catalogue (in no entry: the run fails), com…model.Book (not looked up yet). In focus: com…model.Catalogue.found inapp-outa folder with Main.classcom…app.Mainthe class to runcom…model.Cataloguein no entry: the run failscom…model.Booknot looked up yetNoClassDefFoundError at Main.java:8

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Build the JAR. javac compiles the model package into model-out, and jar --create packs it into library-model.jar. jar --list shows that the JAR keeps the package folders, com/example/library/model/Book.class included.
  2. Compile against it. javac -cp library-model.jar compiles Main into app-out. Main.class records the names of Book and Catalogue, not where they were found.
  3. Run with both entries. java -cp app-out:library-model.jar searches app-out first and finds Main there. When line 8 needs Catalogue, app-out has no such path, and the JAR has it.
  4. It runs. Book comes from the JAR as well, and the run prints 2 titles, 2 copies of Godaan, then this class is com.example.library.app.Main.
  5. Run without the JAR. java -cp app-out leaves the JAR out. Main is still found in app-out, so the program starts.
  6. Line 8 fails. At line 8 the JVM needs Catalogue and finds it in no entry: NoClassDefFoundError, caused by ClassNotFoundException. The class existed when Main was compiled, and is missing now.

jar --list shows that the JAR keeps the package folders, so the same lookup works inside it. Without the JAR on the class path, Main still started, because its own class was found in app-out, and failed at line 8, the first line that needs Catalogue, with NoClassDefFoundError. That error means the class existed when the code was compiled but cannot be found now. For a missing JAR, the fix is on the command line or in the build’s dependencies, not in the code.

ZIP & RAR Extractor A JAR file is a ZIP archive: open one to see its package folders and class files.

Checkpoint

Check: A class missing at run time

  1. Question 1 of 2 Main was compiled with library-model.jar on the class path, and is then run with java -cp app-out com.example.library.app.Main, without the JAR. What happens?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Main starts, then fails with NoClassDefFoundError when it first uses a class from the JAR

    Class files record class names, not where to find them. The JVM looks for each class when it is first needed, so the run fails at the first line that needs Catalogue, line 8 in the lesson's run.

  2. Question 2 of 2 What does NoClassDefFoundError tell you?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: The class existed when the running code was compiled, but the JVM cannot find it now

    The searched-for class was available when the current code was compiled and cannot be found now. The fix is the class path of the run, or the dependencies of the build, not the code.

Practise: fix a broken two-package project

Here is a small shop program with mistakes of three kinds that this lesson covered, compiled as it is:

practice/src/com/example/shop/app/Checkout

practice/src/com/example/shop/app/Checkout.java

package com.example.shop;

import com.example.shop.cart.Item;

public class Checkout {
    public static void main(String[] args) {
        Cart cart = new Cart();
        cart.add(new Item("notebook", 4_500, 2));
        cart.add(new Item("pen", 1_000, 3));
        IO.println(cart.count() + " items, total " + cart.totalPaise() + " paise");
    }
}

practice/src/com/example/shop/cart/Cart.java

package com.example.shop.cart;

class Cart {
    private final List<Item> items = new ArrayList<>();

    public void add(Item item) {
        items.add(item);
    }

    public int count() {
        return items.size();
    }

    public long totalPaise() {
        long total = 0;
        for (Item item : items) {
            total += item.totalPaise();
        }
        return total;
    }
}

practice/src/com/example/shop/cart/Item.java

public record Item(String name, long pricePaise, int quantity) {
    public long totalPaise() {
        return pricePaise * quantity;
    }
}
The broken project, compiled as it is Python · practice_session.py
from session import run

# The broken project, compiled as it is.
run('javac -d out $(find practice/src -name "*.java" | sort)', fails=('javac -d out $(find practice/src -name "*.java" | sort)',))

Output

# openjdk version "25.0.4.1" LTS
$ javac -d out $(find practice/src -name "*.java" | sort)
practice/src/com/example/shop/app/Checkout.java:3: error: cannot find symbol
import com.example.shop.cart.Item;
                            ^
  symbol:   class Item
  location: package com.example.shop.cart
practice/src/com/example/shop/cart/Cart.java:4: error: cannot find symbol
    private final List<Item> items = new ArrayList<>();
                  ^
  symbol:   class List
  location: class Cart
practice/src/com/example/shop/cart/Cart.java:4: error: cannot find symbol
    private final List<Item> items = new ArrayList<>();
                       ^
  symbol:   class Item
  location: class Cart
practice/src/com/example/shop/cart/Cart.java:6: error: cannot find symbol
    public void add(Item item) {
                    ^
  symbol:   class Item
  location: class Cart
practice/src/com/example/shop/app/Checkout.java:7: error: cannot find symbol
        Cart cart = new Cart();
        ^
  symbol:   class Cart
  location: class Checkout
practice/src/com/example/shop/app/Checkout.java:7: error: cannot find symbol
        Cart cart = new Cart();
                        ^
  symbol:   class Cart
  location: class Checkout
practice/src/com/example/shop/app/Checkout.java:8: error: cannot find symbol
        cart.add(new Item("notebook", 4_500, 2));
                     ^
  symbol:   class Item
  location: class Checkout
practice/src/com/example/shop/app/Checkout.java:9: error: cannot find symbol
        cart.add(new Item("pen", 1_000, 3));
                     ^
  symbol:   class Item
  location: class Checkout
practice/src/com/example/shop/cart/Cart.java:4: error: cannot find symbol
    private final List<Item> items = new ArrayList<>();
                                         ^
  symbol:   class ArrayList
  location: class Cart
practice/src/com/example/shop/cart/Cart.java:16: error: cannot find symbol
        for (Item item : items) {
             ^
  symbol:   class Item
  location: class Cart
10 errors
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 practice_session.py

Fix the package declarations, the access levels and the imports, without moving any file, until these two commands work from the folder that holds practice:

  1. javac -d out $(find practice/src -name "*.java") prints nothing.
  2. java -cp out com.example.shop.app.Checkout prints 2 items, total 12000 paise.

Ten errors can come from very few mistakes, so read them in order and fix the first one first. A first hint: each error names a class it cannot find; ask which package that class is really in, and whether it may be used from there.

Then the questions on packages, imports and the class path. The part of this page your answers have missed most leads, and every choice comes with the reason it fits or fails:

Practice that adapts to you

Practise this lesson

15 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 15 A file declares package com.example.shop.cart;. In which folder below the source root should it be saved?

    Choose one answer.

    Show the answer: Question 1 of 15

    Answer: com/example/shop/cart

    Keep every source file in the folder its package names. Then javac with a source path, the launcher and build tools all find it, and no tool depends on being handed the file by name.

  2. Question 2 of 15 Helper.java declares package com.example.util; but is saved in com/example/tools/. What does java wrong/com/example/tools/Helper.java do?

    Choose one answer.

    Show the answer: Question 2 of 15

    Answer: It refuses: end of path to source file does not match its package name

    javac, handed the file by name, filed the class under its declared package, out/com/example/util/. The source launcher insisted that the folders match the package and refused the file, as the session shows.

  3. Question 3 of 15 TaxRule.java is saved in the folder com/example/billing/tax and declares package com.example.billing;. Other code runs it as com.example.billing.tax.TaxRule. Without moving the file, what is the fix?

    Choose one answer.

    Show the answer: Question 3 of 15

    Answer: Change its declaration to package com.example.billing.tax;

    A class's package is what its package line declares, and its full name follows from it. Keep the declaration and the folder in step, and every tool, the launcher and --source-path included, finds the class where it looks.

  4. Question 4 of 15 What does an import do when the program runs?

    Choose one answer.

    Show the answer: Question 4 of 15

    Answer: Nothing; it only changes which simple names the compiler accepts

    An import is a compile-time convenience: Book instead of com.example.library.model.Book. The compiled code is the same with or without it.

  5. Question 5 of 15 Which names does import module java.sql; make usable by their simple names?

    Choose one answer.

    Show the answer: Question 5 of 15

    Answer: The public classes of java.sql and javax.sql, plus those of the modules java.sql requires transitively

    A module import brings every package the module exports, and also the exports of the modules it requires transitively, because code that uses java.sql needs their types too.

  6. Question 6 of 15 A file has import static java.lang.Math.*;. Which call compiles without Math. in front?

    Choose one answer.

    Show the answer: Question 6 of 15

    Answer: abs(-4)

    import static java.lang.Math.*; makes every static member of Math usable by its simple name. The call must still fit a method that exists, with the right arguments.

  7. Question 7 of 15 Which kind of import wins when it offers a simple name that other kinds of import offer too?

    Choose one answer.

    Show the answer: Question 7 of 15

    Answer: A single-type import

    Single-type beats on-demand, which beats module. Two of the same kind that offer one name make it ambiguous.

  8. Question 8 of 15 Ambiguous.java does not compile. Would writing its imports in the other order fix it?

    Choose one answer.

    Show the answer: Question 8 of 15

    Answer: No; the order of import lines never matters, only their kinds

    The fix is a more specific import, import java.sql.Date; or import java.util.Date;, or the full name where the class is used. Reordering lines changes nothing.

  9. Question 9 of 15 A class uses java.util.Date in most places and java.sql.Date in one method. What is the clearest code?

    Choose one answer.

    Show the answer: Question 9 of 15

    Answer: import java.util.Date; and write java.sql.Date in full in the one method

    A simple name can mean only one class in a file. Import the one you use most, and write the other by its full name where you need it.

  10. Question 10 of 15 With no -cp option and no CLASSPATH variable, what is the class path?

    Choose one answer.

    Show the answer: Question 10 of 15

    Answer: The current folder

    -cp sets the class path for one command and overrides CLASSPATH; with neither, the class path is just the current folder.

  11. Question 11 of 15 What does the class path entry lib/* stand for?

    Choose one answer.

    Show the answer: Question 11 of 15

    Answer: Every JAR file in the folder lib

    lib/* is a convenience for libraries: every JAR file in lib becomes an entry of the class path.

  12. Question 12 of 15 The session ran java -cp app-out:library-model.jar … on macOS. How are the same two entries written on Windows?

    Choose one answer.

    Show the answer: Question 12 of 15

    Answer: app-out;library-model.jar

    The separator is : on Linux and macOS and ; on Windows. Everything else about the class path is the same.

  13. Question 13 of 15 Run without the JAR, at which point does Main fail?

    Choose one answer.

    Show the answer: Question 13 of 15

    Answer: At line 8, the first line that needs Catalogue

    The stack trace says at com.example.library.app.Main.main(Main.java:8): the first line that needs a class from the JAR is where the missing class is noticed.

  14. Question 14 of 15 Where is the fix for a NoClassDefFoundError caused by a missing JAR?

    Choose one answer.

    Show the answer: Question 14 of 15

    Answer: In the run command's class path, or in the build's dependencies

    NoClassDefFoundError for a missing library is a class path problem. Put the JAR on the class path of the run, or declare it as a dependency so that the build tool does.

  15. Question 15 of 15 A teammate "fixes" the JAR-less run by copying Catalogue.java into the app's source folder. Why is that the wrong fix?

    Choose one answer.

    Show the answer: Question 15 of 15

    Answer: The class already exists in the JAR; the run's class path lacks it, and a second copy can drift from the JAR's

    Fix the cause: add the JAR to the class path of the run, or declare the dependency in the build. Copying a library's class into the program leaves two versions of one class to keep in step.

Interview questions

Fresher · What is the class path, and what is it when you set nothing?

The class path is the list of folders and JAR files where java and javac look for compiled classes that are not part of the JDK, separated by : on Linux and macOS and by ; on Windows. You set it with -cp (or --class-path), which overrides the CLASSPATH environment variable, and with neither it is just the current folder. A class in a package is looked up by its path inside each entry, in order: com.example.app.Main is found as com/example/app/Main.class under a folder of the class path, or inside one of its JAR files.

Two longer questions of this module start from this lesson: a program that compiles and then stops with NoClassDefFoundError, and two JAR files on the class path that hold different versions of the same class.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to mid

    Your program compiles, but at run time it stops with NoClassDefFoundError for a class from a library. What is different between compile time and run time, and how do you find and fix the cause?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    Two JAR files on the class path both contain com.acme.util.Strings, in different versions. What does the JVM do, how would you notice, and how do you fix it?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • A package name maps to folders, one per part: keep each source file in the folder its package names, and run a class with java -cp out com.example.library.app.Main, by its full name.
  • An import changes only which simple names a file can use; an on-demand import covers one package, never its subpackages.
  • Single-type imports shadow on-demand and module imports, and on-demand imports shadow module imports; two imports of the same kind that offer one name make it ambiguous, whatever the order of the lines.
  • The class path is a list of folders and JAR files searched in order, and the first entry that has a class wins.
  • A class that was there at compile time and is missing at run time gives NoClassDefFoundError, at the first line that needs it; the fix is the class path, not the code.

Terms in this lesson

fully qualified name
A class's name with its package in front, such as com.example.library.model.Book. The JVM turns it into the path com/example/library/model/Book.class, and java runs a class in a package only by this name.
JAR file
A ZIP archive of class files kept in their package folders, with a manifest in META-INF/MANIFEST.MF. Put on the class path, it is searched for classes like a folder.
module import
An import module declaration, such as import module java.base; (JEP 511). It makes every public class and interface of every package the module exports usable by its simple name. Compact source files import java.base this way.
on-demand import
An import that ends in .*, such as import java.time.*;. It makes every public class and interface of one package usable by its simple name, but not those of its subpackages.
single-type import
An import of one class or interface by its full name, such as import java.util.List;. It shadows a class of the same simple name that an on-demand or module import would bring.
static import
An import static declaration, such as import static java.lang.Math.max;. It makes a static member of a class, or with .* all of them, usable without the class name in front.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.