Module Path vs Classpath
In Java's module system, the module path is used to locate named modules and lets the JPMS resolve module dependencies and enforce stronger encapsulation. The classpath follows the traditional class-loading model and does not provide JPMS module-resolution semantics.
The classpath is the traditional way to tell the JVM and Java tools where to find classes and JAR files. Classes found there are treated as part of the unnamed module when running with JPMS, so traditional applications can continue to work without declaring `module-info.java`.
The module path is used for named modules, typically JARs containing `module-info.class`. JPMS reads each module's declared `requires`, `exports`, and related directives, then builds a module graph starting from the requested root modules.
A key difference is encapsulation. A named module exposes only packages listed in `exports`; merely having a public class does not make it accessible to arbitrary code in another module. The classpath does not provide this same package-level module boundary.
For command-line compilation and execution, `--module-path` specifies module locations, while `--class-path` specifies traditional classpath locations. A dependency should normally be placed on the path corresponding to how it is intended to participate in the application: as a named module on the module path or as a classpath dependency in the traditional model.
Key points
- `--module-path` supplies locations from which named modules can be resolved.
- `--class-path` supplies traditional classes and JARs without named-module resolution.
- Named modules declare dependencies with `requires`; their accessible API is constrained by `exports`.
- Classpath code belongs to the unnamed module when used in a JPMS application.
- A modular JAR can generally be identified by its `module-info.class` descriptor.
Interview questions
What is the difference between the module path and the classpath?
The classpath is the traditional mechanism for locating Java classes and JARs. The module path is used by JPMS to locate and resolve named modules. Named modules can declare dependencies and explicitly export packages. Classpath code is associated with the unnamed module, so it does not get the same JPMS encapsulation.
What happens if a dependency is on the classpath instead of the module path?
It can be treated as part of the unnamed module rather than as a named module in the resolved module graph. This means a `requires` relationship cannot be satisfied from that dependency in the same way as a named module. The dependency may still be usable through traditional classpath mechanisms, depending on the application structure. The important distinction is that its JPMS metadata and strong module boundary are not being used as a normal named-module dependency.
How does the module path improve encapsulation compared with the classpath?
A named module explicitly controls which of its packages are exported. Code in another named module cannot normally access non-exported packages through ordinary module-aware access rules, even when classes inside them are public. This creates a boundary around implementation packages. The classpath has no equivalent module-level export mechanism.
How does Java determine module dependencies on the module path?
JPMS reads module descriptors and uses directives such as `requires` to construct a resolved module graph. The runtime starts from specified root modules and resolves their required modules from the available module path. Resolution also detects problems such as missing required modules and conflicting graph constraints. This graph is then used to define the modules available to the application.