Packages in Java – Organising Classes and Controlling Access
A package is a namespace that groups related classes and interfaces, much like a folder groups related files. Packages prevent name clashes (two Date classes can live in java.util and java.sql), organise large codebases, and work with access modifiers to control which classes and members other code can see.
This tutorial covers built-in and user-defined packages, naming conventions, the import and import static statements, the required folder structure, compiling and running packaged code, and package-level access.
1. Built-in and User-Defined Packages
The JDK ships with thousands of classes organised into packages:
| Package | Contents |
|---|---|
java.lang | Core classes: String, Math, Object, wrappers, Thread. Imported automatically. |
java.util | Collections, Scanner, Optional, Random |
java.io / java.nio.file | Input/output and file handling |
java.time | Dates and times: LocalDate, Duration |
java.net / java.net.http | Networking and the HTTP client |
java.util.concurrent | Executors, locks, concurrent collections |
java.sql | JDBC database access |
User-defined packages are the ones you create for your own code.
2. Creating a Package
Put a package declaration as the first statement in the source file. Here is a small shop application split into three packages:
package com.shop.model;
public class Product {
private final String name;
private final double price;
int stock = 10; // package-private: visible only inside com.shop.model
public Product(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public double getPrice() { return price; }
}
package com.shop.util;
import java.text.NumberFormat;
import java.util.Locale;
public class PriceFormatter {
private static final NumberFormat INR = NumberFormat.getCurrencyInstance(Locale.forLanguageTag("en-IN"));
public static String format(double amount) {
return INR.format(amount);
}
}
package com.shop.app;
import com.shop.model.Product; // single-type import
import static com.shop.util.PriceFormatter.format; // static import
import java.util.*; // on-demand (wildcard) import
public class ShopApp {
public static void main(String[] args) {
List<Product> cart = List.of(new Product("Keyboard", 2499), new Product("Mouse", 799));
for (Product p : cart) System.out.println(p.getName() + " : " + format(p.getPrice()));
// Fully qualified name instead of an import
java.time.LocalDate today = java.time.LocalDate.of(2026, 10, 11);
System.out.println("Order date: " + today);
// p.stock is not accessible here: package-private in com.shop.model
System.out.println("Class name: " + Product.class.getName());
System.out.println("Package: " + ShopApp.class.getPackageName());
}
}
Keyboard : ₹2,499.00 Mouse : ₹799.00 Order date: 2026-10-11 Class name: com.shop.model.Product Package: com.shop.app
A class without a package statement belongs to the unnamed default package, which is fine for experiments but cannot be imported from named packages. Real projects always use named packages.
3. Folder Structure, Compiling and Running
The directory structure must mirror the package name: com.shop.model.Product lives in com/shop/model/Product.java.
# Project layout: the folder structure mirrors the package names
src/
└── com/shop/
├── model/Product.java (package com.shop.model;)
├── util/PriceFormatter.java (package com.shop.util;)
└── app/ShopApp.java (package com.shop.app;)
# Compile everything into the out/ directory (javac creates the package folders)
javac -d out $(find src -name "*.java")
# Run using the fully qualified class name
java -cp out com.shop.app.ShopApp
# Package it as a runnable JAR
jar --create --file shop.jar --main-class com.shop.app.ShopApp -C out .
java -jar shop.jar
Build tools such as Maven and Gradle follow the same convention under src/main/java and handle compilation and classpaths for you.
4. Naming Conventions
- All lowercase:
com.example.billing, notcom.Example.Billing. - Start with your organisation's reversed internet domain (
com.javabytechie,org.apache) to make names globally unique. - Then add the project and module:
com.javabytechie.shop.payment. - Replace invalid characters: hyphens become underscores, and a segment starting with a digit gets an underscore prefix.
- Never use the
javaorjavaxprefixes for your own code.
5. Ways to Use Classes from Other Packages
| Form | Example | Notes |
|---|---|---|
| Single-type import | import com.shop.model.Product; | Preferred: explicit and clear |
| On-demand import | import java.util.*; | Imports all public types of one package (not sub-packages) |
| Fully qualified name | java.time.LocalDate.now() | Useful to resolve name clashes |
| Static import | import static java.lang.Math.max; | Imports static members; see Static Import |
| Module import (Java 25) | import module java.base; | Imports all packages exported by a module |
Imports are purely a compile-time convenience: they do not load classes or affect performance. Wildcards do not include sub-packages: import java.util.*; does not import java.util.concurrent.
6. Packages and Access Control
Packages are an encapsulation boundary. A member with no access modifier is package-private: visible to every class in the same package and to nothing outside. In the example, Product.stock cannot be used from com.shop.app.
| Modifier | Same class | Same package | Subclass (other package) | Everywhere |
|---|---|---|---|---|
public | Yes | Yes | Yes | Yes |
protected | Yes | Yes | Yes | No |
| (package-private) | Yes | Yes | No | No |
private | Yes | No | No | No |
Since Java 9, modules add a stronger layer: a module exports only selected packages, hiding the rest even if their classes are public. See Access Modifiers.
7. Advantages of Packages
- Name-clash prevention through unique fully qualified names.
- Organisation: related types live together and are easy to find.
- Access control: package-private types and members hide implementation details.
- Reusability and distribution: packages are packaged into JARs and shared as libraries.
Two common organisation styles: package by layer (controller, service, repository) and package by feature (order, payment, customer). Package by feature usually keeps related code together and makes better use of package-private access.
8. Summary
- A package is a namespace grouping related types; declare it with
packageas the first statement. - Folder structure must mirror the package name; compile with
javac -dand run with the fully qualified class name. - Use single-type imports, wildcard imports, static imports or fully qualified names to use other packages.
java.langis imported automatically.- Package-private access and modules make packages an encapsulation boundary.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is a package in Java?
A namespace that groups related classes and interfaces, preventing name clashes and controlling access.
Q2. What are the types of packages?
Built-in packages provided by the JDK, such as java.util, and user-defined packages that you create.
Q3. Which package is imported by default?
java.lang. Classes in the same package are also available without imports.
Q4. Where must the package statement appear?
As the first statement in the source file, before any imports. Only comments may precede it.
Q5. Can a file have more than one package statement?
No. Each source file belongs to exactly one package.
Q6. Does import java.util.* import sub-packages?
No. Sub-packages such as java.util.concurrent are separate packages and need their own imports.
Q7. Do wildcard imports slow down a program?
No. Imports only affect compilation. Explicit imports are preferred for readability and to avoid ambiguity.
Q8. What happens if two imported packages contain classes with the same name?
Using the simple name is ambiguous and fails to compile. Import one explicitly or use fully qualified names, as with java.util.Date and java.sql.Date.
Q9. What is the default package?
The unnamed package for classes without a package statement. Its classes cannot be imported by classes in named packages.
Q10. How do I run a class that is in a package?
From the directory containing the package root, run java -cp out com.shop.app.ShopApp using the fully qualified name.
Q11. What is package-private access?
The default access when no modifier is given: visible only to classes in the same package.
Q12. Why do package names use reversed domain names?
Domains are globally unique, so reversing them (com.example) produces package names that do not clash with other organisations' code.
Q13. What is a sub-package?
A package whose name extends another, such as com.shop.model under com.shop. Java treats it as a completely separate package with no special access.
Q14. What does javac -d do?
It sets the output directory and creates folders matching each class's package.
Q15. What is the classpath?
The list of directories and JAR files where the JVM and compiler look for classes, set with -cp or the CLASSPATH variable.
Q16. What is the difference between a package and a module?
A package groups types. A module (Java 9+) groups packages, declares dependencies, and exports only chosen packages to other modules.
Q17. Can a class be in two packages?
No. A class belongs to exactly one package; its fully qualified name includes that package.
Q18. Should package names contain uppercase letters?
No. By convention package names are all lowercase to avoid conflicts with class names.
Q19. What is package-info.java?
A special file for package-level documentation (Javadoc) and package annotations.
Q20. What is package by feature?
Organising code by business feature (order, payment) rather than by technical layer, keeping related classes together and enabling package-private encapsulation.