Concepts / Packages and Classes in Java

Packages and Classes in Java

A Java module is a collection of packages, adding one more level of containment above packages, classes, and members.

  • Programming

A Small Tool and a Large Runtime

Imagine a small command-line tool that only reads text files. It uses a handful of standard classes, yet the runtime it runs on carries the entire standard library along with it. Most of that library is never touched by the tool. This mismatch between what a program uses and what it ships with is the problem that Java modules were introduced to address. Java 9 brought modules in to handle the way large Java programs and the platform itself are organized at the largest scale.

What do you think happens?

The tool uses only a handful of standard classes. How much of the standard library does its runtime carry?

  • Only the handful of classes the tool uses

  • The entire standard library

Reveal answer
Answer:

The entire standard library

The runtime carries the whole library even though the tool touches only a small part of it. Modules make it possible to build a smaller runtime, which is covered later in this article.

The central question for this article is this: if code is already grouped into classes and packages, what extra grouping did Java need, and what does that grouping let a developer control? The answer starts with where a module sits in the structure of Java code.

Reading the Containment Chain

A Java module is a collection of packages. It adds one more layer of containment on top of the layers that already existed. Read from the outside inward, the nesting goes: a module holds packages, a package holds classes, and a class holds variables and methods. Each layer contains the one beneath it.

Modulecollection of packagesPackagecollection of classesClassholds variables and methodsVariables and methodsmembers of the classholdsholdsholds
What contains what, and where does a module sit above packages, classes, and members?

The chain above describes how code is nested, but it does not require every package to be placed in a module. The source is explicit that a package does not have to belong to a module to be used. The standard classes, however, have been divided into a set of modules, so the platform's own code follows the same structure that application developers can now use.

Rethinking What Public Means

Before modules, marking a class public was a broad promise. Any class in any package could use that class, along with its public variables and methods. Modules change the meaning of public for code placed inside a module. Inside the module where a class is defined, a public class is public. Outside that module, it is not automatically visible.

Tracing an Export

The control point is the export. A module can explicitly export a package, and doing so makes the public classes in that package accessible from anywhere. That includes other modules and code that belongs to no module at all. Trace the effect on a module with two packages, one exported and one not. Both contain a public class, but only one of those classes is reachable from outside.

Code in anothermoduleExported packageexportedPublic class ServiceNon-exported packagenot exportedPublic class Helpercontainscontainscan usecannot use
Which public classes can code in another module access once a package is exported, and which remain hidden even though they are public?
Worked example

Reaching a public class across a module boundary

A module contains an exported package named api and a non-exported package named internal. Each package has one public class. Can code in another module use each class?

  1. 1
    Check the class's package

    Service is in api, and Helper is in internal.

  2. 2
    Check whether that package is exported

    The api package is exported, so its public classes are accessible from anywhere. The internal package is not exported.

  3. 3
    Apply the export rule to each class

    Service is public and its package is exported, so other code can use it. Helper is public, but its package is not exported, so it stays hidden from outside code.

  4. 4
    Notice the role of the keyword

    Both classes are declared public, yet only one is reachable. The export decides outside access, not the public keyword alone.

Result

Other modules can use Service but cannot use Helper, even though both are public.

Packages That Stay Effectively Private

Because a package can be left unexported, it can be effectively private. It can serve other packages inside its module while staying invisible to the outside world. In that sense a module hides its internal packages the way a well-designed class hides its implementation details. The module's internal structure becomes a detail that outside code does not need to know about.

Building a Custom Runtime with jlink

The second motivation for modules concerns the size of the standard JRE, which contains all of the standard classes. An application typically uses only a small part of that runtime. Modules make it possible to assemble a smaller custom JRE that includes only the modules the application requires. The JDK provides a jlink command for this purpose.

Required modulesonly what the app needsjlinkbuilds the runtimeCustom runtimesmaller than the full JREStandaloneapplicationruns without a JDKinstalledinputproducesships with
How does the module graph flow through jlink to produce a smaller runtime image, and what does the developer become responsible for?

Once built, the custom runtime can be shipped as a standalone application. People who have not installed a JDK on their machine can still run it. Building it, however, creates responsibilities for the developer. The source is careful to note that the runtime is not portable in the way a single program file might be. Separate runtimes are needed for Windows, macOS, and Linux, just as the JDK itself has platform-specific builds.

Module, Package, and Class Compared

The three layers differ in scope and in what they group together. A module groups packages and sits at the outermost layer. A package groups classes. A class groups variables and methods. The table below summarizes these differences, along with the access role each one plays.

LayerWhat it groupsWhere it sitsAccess role
ModulePackagesOutermost layer, added by Java modulesExports decide which packages outside code can reach
PackageClassesInside a module, or outside any modulePublic classes can be reached only if their package is exported
ClassVariables and methodsInside a packagePublic means public within the module it belongs to

Scope and grouping of modules, packages, and classes

Mistakes Beginners Make with Modules

  • Common mistake

    Assuming public means accessible from anywhere

    What it looks like

    A class is declared public inside a module, and the developer expects code in another module to use it without any further setup.

    Why it fails

    Inside a module, public is only automatically public within that module. Outside access depends on whether the package is exported.

    Do this instead

    Check that the package containing the class is exported, either to everyone or to the named modules that need it.

  • Common mistake

    Believing a package must belong to a module to be used

    Why it fails

    The source states that a package does not have to belong to a module to be used, although the standard classes have been divided into modules.

  • Common mistake

    Expecting a jlink runtime to run on every operating system

    What it looks like

    A developer builds one custom runtime on Linux and plans to ship that same runtime to Windows and macOS users.

    Why it fails

    The source notes that separate runtimes are needed for Windows, macOS, and Linux.

    Do this instead

    Build a separate runtime for each target platform.

  • Common mistake

    Thinking a module is the same as a package

    Why it fails

    A module is a collection of packages and sits one layer above them in the containment chain.

    Do this instead

    Treat a module as the outer container and packages as the units it holds.

Checking Your Reading of Exports

MEDIUM

A module contains a package named api, which is exported to everyone, and a package named internal, which is not exported. The internal package has a public class named Helper, which the api package's classes use. Can code in another module use Helper directly? Explain your answer using the idea of exporting.

Hints
  • Ask first which package Helper belongs to.
  • Ask whether that package is exported, and to whom.
  • Remember that public inside a module does not automatically mean visible outside it.

Key Takeaways

  • A Java module is a collection of packages. It adds one more layer of containment above packages, classes, and members, and a package does not have to belong to a module to be used.
  • Inside a module, public only means public within that module. Outside access is controlled by exporting a package, either to everyone or to specific named modules.
  • An unexported package can serve other packages inside its module while remaining invisible outside it, much like a class hides its implementation details.
  • The jlink command builds a smaller custom runtime containing only the modules an application needs, which can be shipped and run without a JDK installed.
  • A custom runtime is platform-specific, so developers must build separate runtimes for Windows, macOS, and Linux.