Skip to content

Java Packages

In Java, packages are used to group related classes, interfaces, enumerations, and annotations. Think of them like folders on your computer that organize your files. Packages serve several important purposes:

  • Namespace Management: Prevent naming conflicts. Two classes can have the same name if they reside in different packages (e.g., java.util.Date and java.sql.Date).
  • Access Control: Control the visibility of types and members (using access modifiers like public, protected, private, and default/package-private).
  • Organization: Make it easier to locate and manage related code components.
  • Distribution: Bundle related functionalities together for sharing and reuse.

Java comes with a rich set of standard library packages, such as:

  • java.lang: Fundamental classes (like Object, String, System). Automatically imported into every Java program.
  • java.util: Utility classes (collections, date/time utilities, Scanner, etc.).
  • java.io: Classes for input/output operations.
  • java.net: Classes for network programming.
  • java.nio: Newer I/O and file system APIs.
  • java.time: Modern date and time API.

You can (and should) also define your own packages to organize your application code.

To place a class or other type into a package, you use the package statement as the very first line in your source file (.java file).

`package com.yourcompany.yourproject.module;`
  • There can be only one package statement per source file.
  • It must be the first non-comment line.
  • All types defined within that source file will belong to the specified package.
  • If a source file does not have a package statement, its types belong to the unnamed package (also known as the default package). Relying on the unnamed package is discouraged for non-trivial projects.

To ensure uniqueness globally, the standard convention is to use your organization’s reversed Internet domain name. For example, if your domain is example.com, your packages might start with com.example.

  • Use all lowercase letters.
  • Separate components with dots (.).
  • Avoid using Java keywords in package names.
  • Example: com.mycompany.ecommerce.util, org.apache.commons.lang3

Let’s create a simple package com.myapp.util containing a utility class.

Source file: src/com/myapp/util/StringUtils.java (See Directory Structure section below)

package com.myapp.util;
public class StringUtils {
public static boolean isNullOrEmpty(String str) {
return str == null || str.trim().isEmpty();
}
// Other utility methods...
}

Another class in a different package:

Source file: src/com/myapp/main/App.java

package com.myapp.main;
// Need to import the StringUtils class to use it
import com.myapp.util.StringUtils;
// Alternatively, import all types from the package:
// import com.myapp.util.*;
public class App {
public static void main(String[] args) {
String name = "";
if (StringUtils.isNullOrEmpty(name)) {
System.out.println("Name is missing.");
}
// Using a class from the standard library (implicitly requires import)
java.util.Scanner scanner = new java.util.Scanner(System.in);
}
}

To use a type (class, interface, etc.) from a different package, you generally need to import it or refer to it using its fully qualified name (package name + type name).

Types within the same package do not need to be imported; they can refer to each other directly by their simple names.

  1. Import Single Type: Import a specific class or interface using its fully qualified name. This is the preferred method for clarity.

import java.util.ArrayList; // … ArrayList list = new ArrayList<>();

3. **Import Entire Package (On-Demand/Wildcard Import):** Import all `public` types from a package using the asterisk (`*`) wildcard. Use this sparingly, as it can sometimes make it less clear where a type originates.
4. ```java
import java.util.*;
// ...
List<String> list = new ArrayList<>();
Scanner scanner = new Scanner(System.in);
  1. Use Fully Qualified Name: Refer to the type using its complete package name every time. This is generally verbose and less readable but avoids potential import conflicts.

java.util.ArrayList list = new java.util.ArrayList<>();

`import` statements appear after the `package` statement (if present) and before the class declaration.
### Static Imports
You can also import `static` members (methods and fields) of a class using `import static`. This allows you to use the static members without qualifying them with the class name.
```java
import static java.lang.Math.PI;
import static java.lang.System.out;
public class StaticImportExample {
public static void main(String[] args) {
double radius = 5.0;
double area = PI * radius * radius; // Using PI directly
out.println("Area: " + area); // Using out directly
}
}

Use static imports judiciously, as overusing them can make code harder to understand.

Crucially, the package structure must match the directory structure of your source code (.java files) and compiled bytecode (.class files).

If a class MyClass is in package com.mycompany.app, its source file MyClass.java must be located in a directory structure like:

<source_root>/com/mycompany/app/MyClass.java

Where <source_root> is the base directory for your source code (e.g., src, src/main/java).

Similarly, after compilation, the MyClass.class file must reside in:

<output_root>/com/mycompany/app/MyClass.class

Where <output_root> is the base directory for your compiled classes (e.g., bin, build/classes/java/main).

The Java compiler (javac) and the Java Virtual Machine (java) use this directory structure, combined with the classpath, to locate the necessary .class files.

The classpath is a list of directories, JAR files (Java Archives), and ZIP archives where the JVM and compiler search for class files.

When you run java com.mycompany.app.MyClass, the JVM needs to find MyClass.class. It looks in the locations specified by the classpath. If your output root is build/classes, and build/classes is on the classpath, the JVM will look for build/classes/com/mycompany/app/MyClass.class.

Modern Development: While understanding the classpath is important, manually managing it using the CLASSPATH environment variable or -cp/-classpath command-line options is less common in modern Java development. Build tools like Maven and Gradle automate the process of compiling code, managing dependencies (external JARs), and setting up the correct classpath for running and testing applications. They define standard project structures (like src/main/java for source code) and handle dependency resolution automatically.

If you need to manage the classpath manually (e.g., for simple examples without build tools):

  • Environment Variable: Set the CLASSPATH environment variable system-wide or in your shell.
    • Windows: set CLASSPATH=C:\path\to\classes;C:\path\to\lib\library.jar;. (Use semicolons ; to separate entries)
    • Linux/macOS: export CLASSPATH=/path/to/classes:/path/to/lib/library.jar:. (Use colons : to separate entries)
    • . represents the current directory.
  • Command-Line Option: Specify the classpath when compiling or running.
    • javac -cp <classpath_entries> MyClass.java
    • java -cp <classpath_entries> com.mycompany.app.MyClass
    • <classpath_entries> uses the same format as the environment variable (semicolons or colons).

Relying on the default classpath (often just the current directory) or managing it manually becomes cumbersome quickly for projects with multiple packages or external libraries. Using a build tool is highly recommended.

Understanding packages is crucial for organizing larger Java projects. The following chapters will delve into object-oriented concepts like Inheritance, Interfaces, and Polymorphism, which often involve interactions between classes in different packages.