Java Packages

Su Suriya Ravichandran Updated 14 Nov 2026
6 min read ·Lesson 40 of 133

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:

PackageContents
java.langCore classes: String, Math, Integer, System, Thread, Object
java.utilCollections (List, Map, ArrayList, HashMap), Scanner, Optional, Random
java.util.functionFunctional interfaces: Function, Predicate, Supplier
java.util.streamThe Stream API
java.ioClassic stream-based input and output
java.nio.fileModern file APIs: Path, Files
java.timeDates and times: LocalDate, Instant, Duration
java.mathBigDecimal, BigInteger
java.net / java.net.httpNetworking and the HTTP client
java.sqlJDBC 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, never com.Example.Billing.
  • Start with your organization's internet domain reversed: a company owning gocourse.in uses in.gocourse...; an open-source project on GitHub might use io.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 java or javax as 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.

ModifierSame classSame packageSubclass (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.

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about Java Packages and get answers drawn from it.

Signed-in readers only.