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.Dateandjava.sql.Dateare 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.utillives atcom/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, notCom.Example. - Reverse domain order: a project at
w3docs.comusescom.w3docsas 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
importfrom 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.javarelative 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.
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
Why does Java's standard convention for package names use reverse domain order, like `com.example.app`?