thecodex.expert · The Codex Family of Knowledge
Java

Packages and Modules

Before Java 9, marking a class public meant it was accessible from literally anywhere on the classpath — modules finally let a library genuinely hide its internal packages.

Java 21 LTS JPMS since Java 9 Last verified:
Canonical Definition

A package (declared with package com.example.myapp; at the top of a file) groups related classes and enforces the public/package-private visibility rules, but offers no way to hide a public class from outside code entirely — anything public on the classpath was accessible from anywhere. The Java Platform Module System (JPMS), introduced in Java 9, adds a module-info.java descriptor declaring which packages a module exports; packages not explicitly exported are genuinely inaccessible to other modules, even if their classes are public.

Packages: namespace and basic visibility

A class with no access modifier at all (no public, private, or protected) has package-private visibility — accessible only within its own package, one of Java's four real access levels alongside public, protected, and private.

Javacom/example/myapp/Calculator.java
package com.example.myapp;

public class Calculator {          // public: visible anywhere on the classpath
    int internalState;              // package-private: visible only within com.example.myapp
}

module-info.java: declaring exports

Only com.example.myapp.api is exported; com.example.myapp.internal, even with fully public classes inside it, is invisible to any other module — real, enforced encapsulation that plain packages could never provide.

Javamodule-info.java
module com.example.myapp {
    requires java.sql;                        // this module depends on java.sql
    exports com.example.myapp.api;             // this package IS visible to other modules
    // com.example.myapp.internal is NOT exported — genuinely inaccessible outside this module
}

Why JPMS matters: real encapsulation

Before modules, a library's "internal" packages were a purely social convention — nothing stopped external code from importing and using them, and libraries broke constantly when users depended on classes never meant to be public API. JPMS gives the compiler and runtime a way to enforce that boundary genuinely, which is also what made it possible to modularize the JDK itself starting in Java 9, letting applications ship smaller custom runtime images containing only the modules they actually need.

Sources

1
Oracle. Java Language Specification, "The Java Platform Module System," docs.oracle.com/en/java/javase/25/language, and JEP 261.