Stage 2: Object-oriented programming, lesson 3 of 10

Packages, imports and project structure

Beginner3 min read@since 16Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

A package groups related classes and gives them a unique name, like com.javaatlas.billing.Invoice. The convention is your domain name reversed, then the feature.

  • The package declaration is the first line: package com.javaatlas.billing;
  • The folders match it: src/main/java/com/javaatlas/billing/Invoice.java
  • import lets you use short names: import java.util.List;. Classes in java.lang (String, Math) need no import.
  • import static brings in static members: import static java.lang.Math.max;

Access levels decide what other packages can see: public (everyone), protected (the package and subclasses), no keyword (the package only), private (the class only).

In Maven and Gradle projects, code lives in src/main/java, tests in src/test/java and settings in src/main/resources. Organise packages by feature (billing, catalog) rather than by layer (controllers, services) so related code stays together.

Example

Java
// src/main/java/com/javaatlas/billing/Invoice.java
package com.javaatlas.billing;

import java.math.BigDecimal;
import java.util.List;
import static java.util.Objects.requireNonNull;

public class Invoice {                        // visible everywhere
    private final List<Line> lines;           // visible only inside Invoice

    public Invoice(List<Line> lines) {
        this.lines = List.copyOf(requireNonNull(lines));
    }

    BigDecimal total() {                      // package-private: billing package only
        return lines.stream().map(Line::amount).reduce(BigDecimal.ZERO, BigDecimal::add);
    }
}

record Line(String item, BigDecimal amount) {}   // package-private record
A typical project layout
src/main/java/com/javaatlas
├── JavaAtlasApplication.java
├── billing/     Invoice, InvoiceService, InvoiceController
├── catalog/     Course, CourseService, CourseController
└── common/      shared errors and configuration
src/test/java/com/javaatlas/billing/InvoiceServiceTest.java
src/main/resources/application.yml

Common mistake

Putting the Spring Boot main class in a sub-package. Component scanning starts from its package, so classes in sibling packages aren't found.

Under the hood

Package-private access is underused: keep classes package-private and expose only the few types other features need, and the compiler enforces your boundaries. Modules (Java 9) add a stronger layer, exporting only chosen packages. Wildcard imports compile to the same bytecode as explicit ones; teams usually prefer explicit imports for readability.

Check yourself

Which package is imported automatically?

How this connects

Part of Java from zero.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.