You write a few Java classes and everything is fine. Then you write a few more. Then your project has 200 files and you cannot find anything. Two classes have the same name and the compiler starts yelling. This is exactly the problem packages solve.
A package in Java is a namespace. It groups related classes, interfaces, and enums into a folder-like structure. Every class in Java lives inside a package. Even your simple HelloWorld class has a package, even if you did not write one explicitly. It goes into the infamous “default package” which is fine for school projects and terrible for anything real.
The official Oracle tutorial explains: “A package is a grouping of related types providing access protection and name space management.” That is a textbook way of saying “packages keep your code from tripping over itself.”
Why Packages Exist
Three practical reasons.
First, name collisions. You write a User class. A library you imported also has a User class. Without packages, Java has no way to tell them apart. With packages, one is com.yourcompany.model.User and the other is org.somelibrary.model.User. They coexist peacefully.
Second, access control. Java has four levels of access: private, package-private (default), protected, and public. Package-private is the one beginners miss. It means “accessible to any class in the same package but not outside it.” This is not a bug. It is a design tool. You can hide implementation details from the outside world while keeping them visible to related classes inside your package.
Third, discoverability. When every billing-related class lives in com.yourcompany.billing, new developers know where to look. It is the same logic as organizing files in folders on your computer.
The Naming Convention
Java package names use a reverse domain name convention. If you own jamilur.dev, your packages start with dev.jamilur. If you work at a company with example.com, they start with com.example.
The official Java documentation recommends: “Package names are written in all lower case to avoid conflict with the names of classes or interfaces.”
Here is how real projects look.
-
java.lang— core Java language classes -
java.util— utility classes like collections -
org.springframework.boot— Spring Boot -
com.mysql.cj.jdbc— MySQL JDBC driver -
dev.jamilur.ecommerce.model— hypothetical ecommerce models
Each dot represents a directory. dev.jamilur.ecommerce.model maps to dev/jamilur/ecommerce/model/ on disk.
Declaring a Package
Put this at the very top of your Java file, before any imports.
package dev.jamilur.bkash.app;
Enter fullscreen mode Exit fullscreen mode
That is it. The file must be in a folder structure matching the package name: dev/jamilur/bkash/app/.
If you forget the package declaration, Java puts your class in the default package. Do not do this for real applications. The default package cannot be imported by classes that are in named packages, which means you lock yourself out of using your own code from other parts of the project. Baeldung has a good explanation of why the default package is dangerous in production.
A Real Example
Let us build a small project structure for a Bangladeshi ecommerce app.
src/
dev/
jamilur/
ecommerce/
model/
Product.java
Customer.java
Order.java
service/
PaymentService.java
ShippingService.java
controller/
OrderController.java
Enter fullscreen mode Exit fullscreen mode
The Product.java file starts with:
package dev.jamilur.ecommerce.model;
public class Product {
private String name;
private double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
}
Enter fullscreen mode Exit fullscreen mode
And the PaymentService.java file starts with:
package dev.jamilur.ecommerce.service;
import dev.jamilur.ecommerce.model.Order;
public class PaymentService {
public boolean processPayment(Order order) {
// payment logic here
return true;
}
}
Enter fullscreen mode Exit fullscreen mode
Notice the import statement. When you want to use a class from another package, you import it. The Order class lives in the model package. The PaymentService class lives in the service package. The import bridges the gap.
Imports and Wildcards
You have three ways to import.
Explicit import (use this most of the time).
import dev.jamilur.ecommerce.model.Order;
import dev.jamilur.ecommerce.model.Customer;
Enter fullscreen mode Exit fullscreen mode
Wildcard import (convenient but controversial).
import dev.jamilur.ecommerce.model.*;
Enter fullscreen mode Exit fullscreen mode
This imports every class in the model package. It saves typing. The downside is you lose clarity. A reader looking at your file has no idea which specific classes you are using. Many style guides including Google’s Java Style Guide recommend against wildcard imports. Your IDE will likely auto-expand them.
Static import (rare, use with care).
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
Enter fullscreen mode Exit fullscreen mode
Now you can write PI instead of Math.PI and sqrt(16) instead of Math.sqrt(16). This is nice for constants and utility methods but can make code harder to read if overused.
Package-Private Access
Here is the access modifier that most tutorials skip over.
When you declare a class, method, or field without any access modifier (no public, no private, no protected), it gets package-private access. Anything in the same package can see it. Nothing outside the package can.
package dev.jamilur.ecommerce.service;
class PaymentGatewayHelper {
// no 'public' keyword
// only classes in the same package can use this
String encryptData(String raw) {
return "encrypted_" + raw;
}
}
Enter fullscreen mode Exit fullscreen mode
This is useful for internal helper classes that should not be part of the public API. Spring uses this pattern heavily. You can annotate a service method with @Transactional and leave it package-private, and Spring’s proxy can still intercept it because it lives in the same package. But external code cannot call it directly.
Packages vs Modules
Java 9 introduced modules, which are like packages on steroids. A module bundles multiple packages and declares which ones it exports and which other modules it requires.
You do not need modules for everyday projects. Packages are enough for most applications. Modules add complexity that only pays off in large systems. The Java Platform Module System (JPMS) is covered in the official JMod documentation if you want to explore that later.
Common Beginner Confusion
Do package names affect performance? No. Packages are purely organizational. They have zero runtime cost.
Can two files in different packages have the same class name? Yes. That is one of the main reasons packages exist. com.example.User and com.other.User are two completely different classes.
Do I have to match package and folder structure? Yes, for standard Java compilation. The compiler expects it. Modern build tools like Maven and Gradle enforce it.
Can I change a package name later? You can, but it breaks every import and every reference. Your IDE can refactor it automatically. But on a shared team, changing package names creates merge conflicts and confusion. Choose your package structure early.
Quick Summary
- A package is a namespace that groups related Java types.
- Package names follow reverse domain conventions:
com.example.project.module. - The package declaration is the first line in a Java file.
- You import classes from other packages using the
importkeyword. - Prefer explicit imports over wildcard imports for clarity.
- Package-private access (no modifier) allows access only within the same package.
- Packages map to directories on the filesystem.
- Modules (Java 9+) are an extra layer on top of packages for large systems.
Packages are not exciting. But they are the difference between a project that scales and a pile of files that nobody can navigate. Getting your package structure right early saves you headaches later.
Based on dev.java/learn: Packages
답글 남기기