Packages & Imports
BeginnerOrganise classes into packages, control visibility with package-private access, and import types cleanly including static imports.
Overview
A package is a namespace that groups related classes and interfaces. It maps directly to a directory structure on disk: class com.example.util.Helper lives in com/example/util/Helper.java. Packages solve name-collision problems (java.util.Date vs java.sql.Date), control access (package-private is the default access level), and form the logical module boundary of a Java application. The import statement is purely a compile-time convenience — it tells the compiler where to find types so you don't have to write fully-qualified names everywhere.
Package Declaration & Naming Conventions
The package statement must be the first non-comment line in a source file. The directory structure must exactly mirror the package name — the compiler and JVM both enforce this.
Naming convention: reverse domain name in lowercase, followed by project and module names. com.mycompany.project.module. Avoid using java.* or javax.* — those are reserved for the JDK.
Classes in the same package can access each other's package-private (no-modifier) members. The four access levels from most to least restrictive: private < package-private < protected < public.
// File: src/com/example/model/User.java
package com.example.model;
public class User {
private String email; // only this class
String username; // package-private — visible to all in com.example.model
protected int age; // package + subclasses
public String displayName; // everywhere
public User(String email, String username, int age) {
this.email = email;
this.username = username;
this.age = age;
this.displayName = username;
}
public String getEmail() { return email; }
}
// File: src/com/example/model/UserRepository.java
package com.example.model; // same package
public class UserRepository {
public User findByUsername(String username) {
User u = new User("a@b.com", username, 25);
// Can access package-private field directly — same package
System.out.println("Looking for: " + u.username);
return u;
}
}
// File: src/com/example/service/UserService.java
package com.example.service; // different package
import com.example.model.User; // must import
public class UserService {
public void greet(User user) {
System.out.println("Hello, " + user.displayName); // public — OK
// user.username; // compile error — package-private, different package
// user.age; // compile error — protected, not a subclass
}
}Import Statements & Static Imports
import lets you use a short class name instead of the fully qualified name. import java.util.* imports all public types in the package (not sub-packages). This is slightly less readable — explicit single-type imports are preferred in professional code.
Static imports (import static) bring static members into scope so you can use them without the class prefix — commonly used for test assertions (assertEquals), Math constants (PI, E), and EnumSet factory methods.
Name conflicts: if two imported classes have the same simple name, use the fully-qualified name for one of them.
package com.example;
// Single-type import — preferred
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
// On-demand import (wildcard) — imports everything in java.util
// import java.util.*;
// Static import — import static members directly
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
import static java.util.Collections.unmodifiableList;
// Name conflict: both java.util and java.sql have Date
import java.util.Date; // one is imported normally
// import java.sql.Date; // would clash — use fully-qualified instead
public class ImportDemo {
public static void main(String[] args) {
// Static imports used without class prefix
double circumference = 2 * PI * 5; // instead of Math.PI
double hypotenuse = sqrt(9 + 16); // instead of Math.sqrt
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
List<String> safe = unmodifiableList(list); // instead of Collections.unmodifiableList
System.out.println(circumference); // 31.41592653589793
System.out.println(hypotenuse); // 5.0
// Fully-qualified name avoids ambiguity
java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis());
System.out.println(utilDate.getClass().getName()); // java.util.Date
}
}The Default Package & Classpath
Classes with no package declaration belong to the unnamed (default) package. Avoid it — classes in the default package cannot be imported by classes in named packages, making it impossible to reuse them in real projects. Always declare a package.
The classpath tells the JVM where to look for .class files. Use -cp or -classpath on the command line, or set the CLASSPATH environment variable. Modern Java projects use build tools (Maven, Gradle) which manage the classpath automatically.
With the Java Module System (JPMS, Java 9+), packages must be explicitly exported in module-info.java for other modules to use them — packages are the unit of export.
// Compile with explicit source path:
// javac -d out src/com/example/model/User.java src/com/example/service/UserService.java
// Run with classpath pointing to compiled output:
// java -cp out com.example.service.Main
// With multiple JARs on classpath (Unix : separator, Windows ; separator):
// java -cp out:libs/guava.jar com.example.service.Main
// module-info.java (Java 9+) — controls which packages are accessible
/*
module com.example {
requires java.sql; // depends on java.sql module
exports com.example.model; // exposes this package to other modules
exports com.example.service to com.example.client; // restricted export
}
*/
// Verify package structure at runtime
public class PackageInfo {
public static void main(String[] args) {
Package pkg = PackageInfo.class.getPackage();
System.out.println(pkg.getName()); // com.example (or null for default pkg)
// List all loaded packages
Package[] packages = Package.getPackages();
System.out.println("Loaded packages: " + packages.length);
}
}Key Points to Remember
- Package name maps 1-to-1 to directory structure — javac enforces this
- Package-private (no modifier) is the default — accessible within the same package only
- Use reverse-domain naming: com.company.project.module — never use java.* or javax.*
- Static imports (import static) bring static members into scope — great for Math, assertions
- Name conflicts: import only one; use the fully-qualified name for the other
- Never use the default (unnamed) package in production — classes there cannot be imported
Practice Packages & Imports in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhat is the purpose of a package in Java?
What is the default access modifier in Java?
What is the difference between import java.util.* and import java.util.List?
What is a static import? When is it useful?
How do you resolve a class name conflict when two packages have the same class name?
Ask Aria about Packages & Imports
Your personal AI tutor — ask anything about this concept