Packages and Imports in Java

Packages give classes a unique name and a visibility boundary, and imports simply save you from writing that full name every time.

What a package is

A package is a named grouping of related types. It provides three things: a unique name for every class, a namespace so two libraries can both define Logger, and an access boundary that package private members respect.

package com.example.billing;      // must be the first statement in the file

public class Invoice { }

The fully qualified name of that class is com.example.billing.Invoice, and it is unique across the whole platform.

Folders mirror packages

src/
  com/
    example/
      billing/
        Invoice.java
        TaxCalculator.java
      notes/
        Note.java

The directory structure must match the package declaration. This is how the compiler and the class loader find a type from its name.

Naming convention

  • All lower case, dot separated.
  • Start with a domain you control, reversed: com.example.
  • Then the project and the area: com.example.notes.search.
  • Never begin a package with java.; those names are reserved by the platform.

Imports

import java.util.List;               // a single type
import java.util.ArrayList;
import java.util.*;                  // every type in the package, not subpackages

import static java.lang.Math.PI;     // a static member
import static java.util.Arrays.asList;
double circumference = 2 * PI * radius;   // no Math. prefix needed
List<String> names = asList("a", "b");
An import is purely a compile time convenience. It generates no code, costs nothing at runtime, and does not load a class. An unused import is untidy, not slow.

What needs no import

  • Types in java.lang, such as String, Integer, Math and Object.
  • Types in the same package.

Resolving name clashes

import java.util.List;

public class Report {

    private List<String> rows;                     // java.util.List
    private java.awt.List widget;                  // fully qualified

    // import java.util.List;
    // import java.awt.List;                       // ambiguous, will not compile
}

Two types with the same simple name cannot both be imported. Import the one used most and write the other in full.

A wildcard import does not reach subpackages

import java.util.*;

// Map and List are available
// Map.Entry is available as Map.Entry
// java.util.concurrent.ExecutorService is NOT available

Compiling and running with packages

javac -d out src/com/example/billing/Invoice.java
java  -cp out com.example.billing.Invoice

The launcher always takes the fully qualified class name.

Packages as a design tool

com.example.notes
  |
  +-- api        public types other packages use
  +-- domain     the model and its rules
  +-- storage    persistence, package private where possible
  +-- search     indexing and queries

Grouping by feature usually ages better than grouping by technical layer, because a change to one feature then touches one package. Package private classes inside a feature package are invisible elsewhere, which keeps the public surface deliberate.

Modules, briefly

module com.example.notes {
    requires java.sql;
    exports com.example.notes.api;      // only this package is visible outside
}

Since Java 9 a module declaration adds a stronger boundary on top of packages: a public class in a package that is not exported cannot be reached from another module at all.

Common mistakes

  • Putting the package statement after an import, or after the class.
  • A folder structure that does not match the declaration.
  • Using the default package, which has no name, cannot be imported from a named package, and does not scale beyond a single exercise.
  • Importing a class and then still writing its fully qualified name.
  • Believing wildcard imports slow the program down.

Best practices

  • Use a reversed domain you actually own as the prefix.
  • Prefer explicit imports; most editors manage them, and they document dependencies.
  • Group by feature rather than by technical layer.
  • Keep classes package private unless something outside genuinely needs them.
  • Use static imports sparingly, for genuinely well known members such as Math.max or test assertions.

Practice

  1. Create com.example.shop.Product and compile it into an output folder, then run a class that uses it.
  2. Why can a class in the default package not be imported by one in a named package?
  3. Two libraries both define Logger. Show two ways to use both in one file.
  4. Does import java.util.*; make java.util.concurrent.Future available? Explain.
  5. Describe a package layout for a small notes application, grouped by feature.

Conclusion

Packages give unique names and a real visibility boundary; imports only save typing. Mirror packages in folders, group by feature, and keep as much as possible package private.

Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All Java notes →
Java

Enums in Java

An enum is a class with a fixed set of instances, which makes an invalid value impossible rather than merely unlikely.

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.