Packages, imports & JARs
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:
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.combecomescom.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.orjavax..
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:
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):
The forms of import:
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 importjava.util.function.*. Packages are not nested in the import sense.java.langand 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:
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:
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:
On Windows PowerShell,
$(find ...)won't work. Either list the files, usejavac -d out (Get-ChildItem -Recurse -Filter *.java).FullName, or (much more common in practice) let Maven or Gradle compile for you.
Two classic errors
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:
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:
--create --file shop.jarmakes a new archive (the short form isjar cfe shop.jar com.elephantoo.shop.Main -C out .).--main-classwritesMain-Class: com.elephantoo.shop.Maininto the manifest, which is what makesjava -jarwork.-C out .means "change intooutand add everything", so paths inside the JAR start atcom/.
Inspect what's inside:
Using a library JAR#
Libraries are just JARs on the classpath. Suppose a teammate gives you textutils.jar containing com.elephantoo.text.Slugs:
Put the JAR in lib/ and add it to the classpath for both compiling and running:
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.shopandcom.elephantoo.shop.modelare 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:
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
packagestatement 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
packagestatement, so classes can't be found. - Running
java Maininstead ofjava -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 importsa.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
1.A file starts with
package com.elephantoo.shop.model;and declarespublic class Product. Where should the source file live (relative tosrc/)?2.Which package is imported automatically into every Java file?
3.You compiled into
out/and the main class iscom.elephantoo.shop.Main. Which command runs it?
Finished reading?
Mark this lesson complete to track your progress.