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.
-
Java Basics
- Introduction to Java
- Setting Up Java and Writing Your First Program
- Variables, Data Types and Literals in Java
- Type Casting and Type Conversion in Java
- Operators and Expressions in Java
- Input and Output in Java
- Comments, Keywords and Naming Conventions in Java
- Control Flow in Java: if, else and switch
- Loops in Java: for, while and do-while
- Methods
- Arrays and Strings
-
OOP
- Classes and Objects in Java
- Constructors in Java
- The this Keyword in Java
- The static Keyword in Java
- Encapsulation in Java
- Access Modifiers in Java
- Inheritance in Java
- Method Overriding and super in Java
- Polymorphism in Java
- Abstraction, Abstract Classes and Interfaces in Java
- Composition, Aggregation and Association in Java
- The Object Lifecycle in Java
- Core Java
- Exception Handling
-
Collections
- The Java Collections Framework
- List in Java: ArrayList, LinkedList, Vector and Stack
- Set in Java: HashSet, LinkedHashSet and TreeSet
- Map in Java: HashMap, LinkedHashMap and TreeMap
- How HashMap Works Internally in Java
- Queue and Deque in Java: ArrayDeque and PriorityQueue
- Iterators in Java
- Comparable and Comparator in Java
- Collections Utilities and Choosing the Right Collection
- Generics
- Java 8+
- Stream API
- Date and Time
- File and I/O
-
Multithreading
- Threads in Java: Processes, Runnable and Thread
- Thread Lifecycle in Java
- Synchronization in Java: synchronized and volatile
- Locks and Atomic Classes in Java
- Race Conditions and Deadlocks in Java
- The Executor Framework and Thread Pools in Java
- Future and CompletableFuture in Java
- Concurrent Collections in Java
- The Java Memory Model
- JVM and Memory
- Advanced Java
- Networking
- JDBC
- Testing
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.javaThe 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 asString,Integer,MathandObject. - 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 availableCompiling and running with packages
javac -d out src/com/example/billing/Invoice.java
java -cp out com.example.billing.InvoiceThe 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 queriesGrouping 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
packagestatement 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.maxor test assertions.
Practice
- Create
com.example.shop.Productand compile it into an output folder, then run a class that uses it. - Why can a class in the default package not be imported by one in a named package?
- Two libraries both define
Logger. Show two ways to use both in one file. - Does
import java.util.*;makejava.util.concurrent.Futureavailable? Explain. - 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.