Skip to content
elephantoo

Packages, imports & JARs

Lesson 20 of 43 13 min read

Organise code into packages, import classes, compile multi-package projects and build a JAR.


So far every example has lived in a single file. Real projects have hundreds of classes, and the JDK itself has thousands. Packages organise classes into named groups (like folders), prevent name clashes, and add a layer of access control. A JAR file then bundles a compiled project into one file you can run or share.

What is a package?#

A package is a namespace for related classes. You have been using them already:

PackageContains
java.langString, Math, System, Integer, Object (imported automatically)
java.utilList, ArrayList, Map, Scanner, Random
java.timeLocalDate, Duration, ZonedDateTime
java.nio.filePath, Files

A class's fully qualified name is its package plus its simple name: java.util.ArrayList. Two classes can share a simple name if they live in different packages: java.util.Date and java.sql.Date are different classes.

Naming conventions

  • All lower-case, words separated by dots: com.elephantoo.shop.model.
  • Start with your organisation's domain reversed (elephantoo.com becomes com.elephantoo), which makes names globally unique.
  • Then the project, then the area: com.elephantoo.shop.model, com.elephantoo.shop.util.
  • Never start your own packages with java. or javax..

Declaring a package#

The package statement must be the first statement in the file (only comments may come before it). The directory structure must mirror the package name:

Output
shop/
└── src/
    └── com/
        └── elephantoo/
            └── shop/
                ├── Main.java
                ├── model/
                │   └── Product.java
                └── util/
                    └── PriceFormatter.java
src/com/elephantoo/shop/model/Product.java
package com.elephantoo.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; }

    double internalCost() {          // package-private: only com.elephantoo.shop.model can call it
        return price * 0.6;
    }
}
src/com/elephantoo/shop/util/PriceFormatter.java
package com.elephantoo.shop.util;

public final class PriceFormatter {
    private PriceFormatter() { }

    public static String rupees(double amount) {
        return String.format("Rs %,.2f", amount);
    }
}

Only public classes can be used from other packages. A public class must live in a file with the same name (Product.java), so a file has at most one public top-level class.

Importing classes#

To use a class from another package, either write its fully qualified name every time, or import it once at the top of the file (after package, before the class):

src/com/elephantoo/shop/Main.java
package com.elephantoo.shop;

import com.elephantoo.shop.model.Product;
import com.elephantoo.shop.util.PriceFormatter;

import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Product> cart = List.of(
            new Product("Keyboard", 1299),
            new Product("Monitor", 10499.5)
        );

        double total = 0;
        for (Product p : cart) {
            System.out.println(p.getName() + ": " + PriceFormatter.rupees(p.getPrice()));
            total += p.getPrice();
        }
        System.out.println("Total: " + PriceFormatter.rupees(total));
        // p.internalCost();   // error: internalCost() is not public in Product; cannot be accessed from outside package
    }
}

The forms of import:

Java
import java.util.List;              // single-type import (preferred, explicit)
import java.util.*;                 // on-demand: every public type in java.util (not sub-packages)
import static java.lang.Math.max;   // static import of one member
import static java.lang.Math.*;     // static import of all static members

Facts worth knowing:

  • An import is just a naming shortcut. It doesn't load or copy code, and wildcard imports have no runtime cost.
  • import java.util.*; does not import java.util.function.*. Packages are not nested in the import sense.
  • java.lang and the class's own package never need imports.
  • Most teams prefer explicit single-type imports; IDEs add and tidy them for you (Ctrl+Alt+O in IntelliJ).

Name clashes

If two imported packages contain classes with the same simple name, using that name becomes ambiguous:

Java
import java.util.*;
import java.sql.*;

class Report {
    Date created;      // error: reference to Date is ambiguous
}

Fix it by importing the one you want explicitly (import java.util.Date;, since single-type imports win over wildcards), or use the fully qualified name for the other one: java.sql.Date sqlDate;.

Compiling and running a multi-package project#

From the shop folder, compile every source file into a separate output folder with -d:

Terminal
cd shop
javac -d out $(find src -name "*.java")
find out -type f
Output
out/com/elephantoo/shop/Main.class
out/com/elephantoo/shop/model/Product.class
out/com/elephantoo/shop/util/PriceFormatter.class

javac -d out recreates the package folders under out/. Now run the program by giving the JVM the classpath (where to look for classes) and the fully qualified main class:

Terminal
java -cp out com.elephantoo.shop.Main
Output
Keyboard: Rs 1,299.00
Monitor: Rs 10,499.50
Total: Rs 11,798.50

On Windows PowerShell, $(find ...) won't work. Either list the files, use javac -d out (Get-ChildItem -Recurse -Filter *.java).FullName, or (much more common in practice) let Maven or Gradle compile for you.

Two classic errors

Terminal
java -cp out Main
Output
Error: Could not find or load main class Main
Caused by: java.lang.ClassNotFoundException: Main

The class is called com.elephantoo.shop.Main, not Main. Similarly, cd-ing into out/com/elephantoo/shop and running java Main fails with wrong name: com/elephantoo/shop/Main. Always run from the classpath root with the full name.

The classpath#

The classpath is a list of folders and JAR files where the JVM (and javac) look for classes. Set it with -cp (or -classpath, or --class-path). Entries are separated by : on Linux/macOS and ; on Windows:

Terminal
java -cp "out:lib/*" com.elephantoo.app.Blog       # Linux / macOS
java -cp "out;lib/*" com.elephantoo.app.Blog       # Windows

lib/* means "every JAR in lib". Quote it so the shell doesn't expand the * itself. If you don't pass -cp, the classpath defaults to the current directory (.).

Building a JAR#

A JAR (Java ARchive) is a ZIP file of .class files plus a META-INF/MANIFEST.MF file. Create an executable JAR with the jar tool that ships with the JDK:

Terminal
jar --create --file shop.jar --main-class com.elephantoo.shop.Main -C out .
java -jar shop.jar
Output
Keyboard: Rs 1,299.00
Monitor: Rs 10,499.50
Total: Rs 11,798.50
  • --create --file shop.jar makes a new archive (the short form is jar cfe shop.jar com.elephantoo.shop.Main -C out .).
  • --main-class writes Main-Class: com.elephantoo.shop.Main into the manifest, which is what makes java -jar work.
  • -C out . means "change into out and add everything", so paths inside the JAR start at com/.

Inspect what's inside:

Terminal
jar --list --file shop.jar
Output
META-INF/
META-INF/MANIFEST.MF
com/
com/elephantoo/
com/elephantoo/shop/
com/elephantoo/shop/Main.class
com/elephantoo/shop/model/
com/elephantoo/shop/model/Product.class
com/elephantoo/shop/util/
com/elephantoo/shop/util/PriceFormatter.class

Using a library JAR#

Libraries are just JARs on the classpath. Suppose a teammate gives you textutils.jar containing com.elephantoo.text.Slugs:

app/src/com/elephantoo/app/Blog.java
package com.elephantoo.app;

import com.elephantoo.text.Slugs;

public class Blog {
    public static void main(String[] args) {
        System.out.println(Slugs.slugify("  Packages, Imports & JARs!  "));
    }
}

Put the JAR in lib/ and add it to the classpath for both compiling and running:

Terminal
cd app
javac -cp lib/textutils.jar -d out $(find src -name "*.java")
java -cp "out:lib/*" com.elephantoo.app.Blog
Output
packages-imports-jars

Forget the JAR at runtime (java -cp out com.elephantoo.app.Blog) and the program compiles fine but crashes with NoClassDefFoundError: com/elephantoo/text/Slugs. Managing these JARs and their versions by hand quickly becomes painful, which is exactly why Maven and Gradle exist (covered in the Build tools lesson). They download libraries for you and use the standard layout src/main/java/com/elephantoo/....

Packages and access control#

Packages are also an access boundary, which you saw in the encapsulation lesson:

  • public: usable from any package.
  • no modifier (package-private): only inside the same package. Great for implementation details, like internalCost() above.
  • protected: same package, plus subclasses in other packages.
  • private: only the class itself.

A good design exposes a small public API from each package and keeps helpers package-private.

Sub-packages get no special access. com.elephantoo.shop and com.elephantoo.shop.model are completely separate packages as far as access rules go.

Running a single file directly#

For quick experiments, Java 11+ can compile and run a single source file in one step, without javac:

Terminal
java Hello.java

This is handy for scripts and learning, but real projects with packages use javac (or a build tool) and the classpath as shown above.

The default package and modules#

  • A file with no package statement is in the unnamed (default) package. That's fine for tiny examples like the earlier lessons, but classes in the default package cannot be imported by classes in named packages. Always use packages for real code.
  • Java 9 added modules (module-info.java), a level above packages that declares which packages a JAR exports and which modules it requires. The JDK itself is modular. Most application code still works on the classpath, and you can learn modules later when you need them.

Common mistakes#

  • Folder structure not matching the package statement, so classes can't be found.
  • Running java Main instead of java -cp out com.elephantoo.shop.Main.
  • Forgetting library JARs on the runtime classpath (NoClassDefFoundError).
  • Using : vs ; for the wrong operating system in -cp.
  • Assuming import a.b.* also imports a.b.c.*.
  • Leaving production code in the default package.

What's next#

With code neatly organised, it's time to make it robust. Next: exception handling with try, catch, finally, and the difference between checked and unchecked exceptions.

Check your understanding

Quick quiz

0/3 answered
  1. 1.A file starts with package com.elephantoo.shop.model; and declares public class Product. Where should the source file live (relative to src/)?

  2. 2.Which package is imported automatically into every Java file?

  3. 3.You compiled into out/ and the main class is com.elephantoo.shop.Main. Which command runs it?

Finished reading?

Mark this lesson complete to track your progress.