Java Packages
A package is a named group of related classes and interfaces. Packages organize code the way folders organize files, give every class a unique full name, and control which classes can be used from outside the group. Every non-trivial Java program, and the entire JDK, is organized into packages. This lesson introduces them; the Modules and Packages section later covers creating, importing, and access control in more depth.
Why Packages Exist
Organization. A project with hundreds of classes needs structure. Grouping by responsibility (model, service, repository, web) lets developers find code quickly.
Unique names. Two libraries can each have a class called User or Date. Packages make their full names different: java.util.Date and java.sql.Date are distinct classes that coexist without conflict.
Access control. Classes and members without an access modifier are visible only inside their own package. A package can expose a small public API while keeping its helper classes internal.
Built-in Packages
The JDK's classes are grouped into packages. Some you will use constantly:
| Package | Contents |
|---|---|
java.lang | Core classes: String, Math, Integer, System, Thread, Object |
java.util | Collections (List, Map, ArrayList, HashMap), Scanner, Optional, Random |
java.util.function | Functional interfaces: Function, Predicate, Supplier |
java.util.stream | The Stream API |
java.io | Classic stream-based input and output |
java.nio.file | Modern file APIs: Path, Files |
java.time | Dates and times: LocalDate, Instant, Duration |
java.math | BigDecimal, BigInteger |
java.net / java.net.http | Networking and the HTTP client |
java.sql | JDBC database access |
java.lang is special: its classes are available in every file without an import, which is why String and System never need one.
Fully Qualified Names
A class's fully qualified name is its package plus its simple name:
java.util.ArrayList
└─ package ─┘└ simple name ┘
You can always refer to a class by its full name, with no import:
java.util.List<String> names = new java.util.ArrayList<>();
java.time.LocalDate today = java.time.LocalDate.now();
This is legal but verbose. Imports exist to avoid it.
Importing Classes
An import declaration lets you write a class's simple name:
import java.util.ArrayList;
import java.util.List;
import java.time.LocalDate;
public class Planner {
public static void main(String[] args) {
List<String> tasks = new ArrayList<>();
tasks.add("Review pull requests");
System.out.println(LocalDate.now() + ": " + tasks);
}
}
Imports go after the package declaration and before the class. They are purely a compile-time naming convenience: they do not load code or make the program larger, and an unused import has no runtime effect.
Wildcard imports
import java.util.*;
This makes every class in java.util available by simple name. It does not include subpackages: java.util.* does not import java.util.function.Function. Packages are not nested in Java's type system, even though their names look hierarchical.
Wildcard imports are shorter, but explicit imports make a file's dependencies visible at a glance and avoid ambiguity. IDEs manage explicit imports automatically, so most projects use them.
Name conflicts
import java.util.Date;
import java.sql.Date; // compile error: a type with the same simple name is already imported
When two classes share a simple name, import one and write the other's full name:
import java.util.Date;
public class Report {
Date created; // java.util.Date
java.sql.Date databaseDate; // written in full
}
Static imports
A static import brings in static members (fields and methods) so they can be used without the class name:
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
double circumference = 2 * PI * r;
double hyp = sqrt(a * a + b * b);
Use them sparingly, for constants or utility methods used very frequently. Overuse hides where a name comes from.
Creating Your Own Package
Declare the package on the first line of the source file:
// src/com/gocourse/shop/model/Product.java
package com.gocourse.shop.model;
public class Product {
private final String name;
private final double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() { return name; }
public double getPrice() { return price; }
}
// src/com/gocourse/shop/App.java
package com.gocourse.shop;
import com.gocourse.shop.model.Product;
public class App {
public static void main(String[] args) {
Product p = new Product("Mechanical Keyboard", 4999);
System.out.println(p.getName() + " costs " + p.getPrice());
}
}
The two classes are in different packages, so App imports Product. Product and its constructor and methods are public, so code in another package can use them.
Directory structure must match
Each segment of the package name corresponds to a directory:
src/
└── com/
└── gocourse/
└── shop/
├── App.java
└── model/
└── Product.java
Compile from the directory containing src and run by fully qualified name:
javac -d out src/com/gocourse/shop/App.java src/com/gocourse/shop/model/Product.java
java -cp out com.gocourse.shop.App
Mechanical Keyboard costs 4999.0
javac -d out creates out/com/gocourse/shop/App.class and out/com/gocourse/shop/model/Product.class. The JVM finds com.gocourse.shop.App by translating the dots to directory separators under each classpath entry.
Naming Conventions
- All lowercase:
com.example.billing, nevercom.Example.Billing. - Start with your organization's internet domain reversed: a company owning
gocourse.inusesin.gocourse...; an open-source project on GitHub might useio.github.username.... This makes collisions between independently written libraries practically impossible. - Use short, meaningful segments:
com.gocourse.lms.course,com.gocourse.lms.enrollment. - If a domain contains a hyphen or a segment starts with a digit or is a keyword, replace or prefix it with an underscore (
com.example.my_app,com.example._2fa). - Never use
javaorjavaxas the first segment; those are reserved for the platform.
Package Access
When a class, field, method, or constructor has no access modifier, it is package-private: visible to every class in the same package and to nothing outside it.
package com.gocourse.shop.model;
public class Product {
String sku; // package-private: visible within com.gocourse.shop.model only
public String getName() { ... }
}
class PriceCalculator { // package-private class: invisible outside this package
static double withTax(double p) { return p * 1.18; }
}
package com.gocourse.shop;
import com.gocourse.shop.model.Product;
// import com.gocourse.shop.model.PriceCalculator; // compile error: not public
public class App {
void demo(Product p) {
System.out.println(p.getName()); // allowed: public
System.out.println(p.sku); // compile error: sku is not public
}
}
This lets a package keep implementation helpers private to itself while publishing only the classes and methods meant for outside use. Note that com.gocourse.shop and com.gocourse.shop.model are different packages for access purposes; being a "subpackage" grants no special visibility.
| Modifier | Same class | Same package | Subclass (other package) | Everywhere |
|---|---|---|---|---|
public | ✓ | ✓ | ✓ | ✓ |
protected | ✓ | ✓ | ✓ | |
| none (package-private) | ✓ | ✓ | ||
private | ✓ |
Access modifiers have their own lesson in the OOP section.
Organizing a Project into Packages
Two common strategies:
Package by layer groups classes by technical role:
com.gocourse.shop.controller
com.gocourse.shop.service
com.gocourse.shop.repository
com.gocourse.shop.model
Package by feature groups everything for one feature together:
com.gocourse.shop.cart (CartController, CartService, CartRepository, Cart)
com.gocourse.shop.order
com.gocourse.shop.payment
Package-by-layer is common in tutorials and smaller projects. Package-by-feature scales better in large applications, because a change to one feature touches one package, and package-private access can hide each feature's internals from the others.
Packages and Modules
Since Java 9, packages can be grouped into modules. A module declares, in a module-info.java file, which of its packages are exported for other modules to use. A public class in a non-exported package is not accessible from other modules. This adds a stronger level of encapsulation above packages. Ordinary classpath-based applications, including everything in the early lessons of this tutorial, do not need modules; they are covered in the Modules and Packages section.