W3docs

Java Packages

Group related Java classes into packages, follow naming conventions, and structure projects for maintainability.

Java doesn't have one giant pool of class names. Every class lives inside a package — a named space that acts as both a unit of organization and a Java-level namespace. Two classes called Logger can coexist without collision as long as they sit in different packages, and the package name carries through everywhere: in import statements, in fully-qualified names, in the file system, even in JAR manifests. A working knowledge of packages is what lets you read someone else's project structure at a glance.

What a package actually is

A package serves three purposes at once:

  • A namespace. java.util.Date and java.sql.Date are different classes; the package name keeps them apart.
  • An access boundary. Without a modifier, members are visible only within the same package — the "package-private" access level. It's a real, structural form of encapsulation; see Access modifiers.
  • A directory. The package name maps one-to-one to a folder path. com.example.app.util lives at com/example/app/util/.

The same name is used in three places — declaration, file path, and import — and they all have to agree.

Naming conventions

Java's convention is reverse-DNS naming based on a domain you control:

  • All lowercase: com.example, not Com.Example.
  • Reverse domain order: a project at w3docs.com uses com.w3docs as its root.
  • Project, module, and feature segments follow: com.w3docs.learnjava.parser.
  • Avoid Java reserved words as segments (int, class, new). If your domain happens to include one, mangle it: com.example.int_ or split differently.

These conventions matter beyond aesthetics. The reverse-DNS rule is what makes JARs from different organizations safe to drop into the same classpath without name clashes.

The default package

A .java file with no package declaration belongs to the default (unnamed) package. Two things happen as a result:

  • You can't import from the default package into a named one. Anything in it is effectively walled off from real code.
  • Build tools, IDEs, and module systems all treat the default package as a degenerate case — many flat-out refuse to compile against it.

Use it for one-off Hello.java files. Don't ship anything from it.

How packages map to directories

If you declare package com.w3docs.learnjava.parser; at the top of Tokenizer.java, the file has to sit at:

com/w3docs/learnjava/parser/Tokenizer.java

relative to the source root. The compiler doesn't infer the package from the path — it reads the declaration, then trusts you. But the runtime (and most tooling) won't be happy if the two don't match.

That source root is where the rabbit-hole of classpath starts: the JVM has to know where the package tree begins, or it can't find anything.

A worked example: two Loggers

The clearest argument for packages is the collision they prevent. The following program uses two classes called Logger in spirit — the JDK's java.util.logging.Logger by its fully-qualified name — and shows how a class's package becomes part of its runtime identity.

java— editable, runs on the server

Two takeaways from running it: classes know their own package at runtime (via Class.getName() and Class.getPackage()), and the fully-qualified name is what unambiguously identifies a type — Logger alone is ambiguous; java.util.logging.Logger is not.

What's next

Naming a package is one thing; pulling its types into your own code is another. The next chapter covers the import statement — single-type imports, wildcard imports, static imports, and when each is the right call.

Practice

Practice

Why does Java's standard convention for package names use reverse domain order, like `com.example.app`?