Packages & Imports
Packages & Imports
As your Java program grows beyond a handful of classes, you need a way to organize them — just as you organize files into folders on your computer. Java solves this with packages. A package is a named group of related classes and interfaces. Packages serve two purposes: they keep code organized, and they prevent name clashes between classes that happen to share the same name.
The package statement
Every Java source file may begin with a package statement that declares which package the class belongs to. The statement must be the very first non-comment line in the file.
The package name uses reverse domain notation by convention. If your domain is mybank.com, your top-level package is com.mybank. Sub-packages separate concerns further: com.mybank.accounts, com.mybank.loans, com.mybank.util.
package com.mybank.accounts must live in the directory com/mybank/accounts/ relative to your source root. Modern build tools (Maven, Gradle) and IDEs enforce this automatically.
The default package
If you omit the package statement, the class belongs to the default package — an unnamed package. This is fine for tiny one-file experiments, but you should never use it in real projects because classes in the default package cannot be imported by classes in named packages.
Importing classes with import
When you want to use a class from a different package, you have two options. The first is a single-type import: you name the exact class you need.
The second option is a wildcard import that brings in every public type from a package:
Fully-qualified class names
You can always refer to a class by its fully-qualified name — the complete package.ClassName path — without any import statement at all:
Fully-qualified names are verbose, so they are mainly used when two packages contain classes with the same name and you need both in the same file:
The java.lang package is always imported
You have been using String, System, Math, and Integer all along without importing them. That is because every Java file automatically imports all classes from java.lang. You never need to write import java.lang.String.
Static imports
A static import lets you use static members (fields and methods) of another class without qualifying them with the class name. The most common use-case is Math constants and methods:
sqrt or PI came from. Reserve static imports for well-known constants and utility methods (like Math or JUnit assertion methods).
A realistic package structure
Here is how a small banking application might be organised into packages:
Each package has a clear responsibility. accounts holds account-related classes, loans holds loan-related classes, and util holds shared helpers. This mirrors how you already learnt to separate fields, methods, and constructors inside a class — now you are doing the same at a higher level.
Access modifiers and packages revisited
You learnt about public, private, and protected in lesson 4. There is a fourth level you may not have noticed: package-private (no keyword). A class or member with no access modifier is visible only within its own package. This is useful for implementation helpers you want to share within a package but hide from the rest of the application.
AccountValidator is visible to every class inside com.mybank.accounts but invisible to classes in other packages — a clean way to hide internal details.
Summary
Packages are Java's mechanism for organising classes and controlling visibility. Declare a package with the package statement at the top of every source file, use import to bring in classes from other packages, and rely on fully-qualified names when two packages share a class name. The java.lang package is always available without an import, and static imports let you use static members unqualified — use them sparingly. Together, these tools let you build large applications that stay readable and maintainable.