Written by Jeff Friesen, Java technology expert
Java developers group related classes and other reference types into packages.
This Java language construct makes it easier to locate and use types, avoid name conflicts between same-named types, and control access to types.
This article introduces you to packages.
Hierarchical structures organize items according to hierarchical relationships that exist between those items.
For example, a file cabinet organizes drawers of file folders containing files (pieces of paper). A file is a member of a file folder, which is a member of a drawer that is a member of a file cabinet.
Also, a file system might contain an accounts directory with payable and receivable subdirectories. Additionally, a class can declare nested classes along with fields and methods.
Hierarchical structures help to avoid name conflicts.
For example, in a nonhierarchical file system (a single directory), it's not possible to assign the same name to multiple files.
In contrast, a hierarchical file system lets same-named files exist in different directories. Similarly, two enclosing classes can contain same-named nested classes. Name conflicts don't exist because items are partitioned into different namespaces.
Java also supports the partitioning of top-level (non-nested) reference types into multiple namespaces to better organize these types and to prevent name conflicts.
It accomplishes this task via its package language feature, where a package is a unique namespace for storing reference types.
Packages can store classes, interfaces, enums, and annotation types -- and subpackages (packages nested within other packages).
A package has a name, which must be a nonreserved identifier; for example, java. The member access operator (.) separates a package name from a subpackage name and separates a package or subpackage name from a type name.
For example, the two member access operators in java.lang.System separate package namejava from the lang subpackage name and separate subpackage name lang from the System type name.
Reference types must be declared public to be accessible from outside their packages. The same applies to any constants, constructors, methods, and nested types that must be accessible. You'll see examples later in this article.
This statement appears at the top of a source file and identifies the package to which the source file's types belong. It must conform to the following syntax:
A package statement starts with reserved word
package and continues with an identifier, which is optionally followed by a period-separated sequence of identifiers. A semicolon (
;) terminates this statement.
The first (left-most) identifier names the package and each subsequent identifier names a subpackage. For example, in
package a.b;, all types declared in the source file belong to the
b subpackage of the
By convention, a package/subpackage name is expressed in lowercase. When the name consists of multiple words, each word except for the first word is capitalized; for example,
A sequence of packages names must be unique, to avoid compilation problems.
For example, suppose you create two different
graphics packages, and suppose that each
graphics package contains a
Rectangle class with a different interface. When the Java compiler encounters, for example,
Rectangle r = new Rectangle (1, 20, 30, 40); in the source code, it needs to verify that the
Rectangle(int, int, int, int) constructor exists.
The compiler will search all accessible packages (the search algorithm is discussed later) until it finds a
graphics package that contains a
Rectangle class. If the found package contains the appropriate
Rectangle class with a
Rectangle(int, int, int, int) constructor, everything is fine.
Otherwise, if the found
Rectangle class doesn't have a
Rectangle(int, int, int, int) constructor, the compiler reports an error.
The convention in choosing a unique name sequence is to reverse your Internet domain name and use it as a prefix for the sequence.
For example, I would choose
ca.javajeff as my prefix because
javajeff.ca is my domain name. I would then specify
ca.javajeff.graphics.Rectangle to access
Domain name components are not always valid package names. One or more component names might start with a digit (
9.com), contain a hyphen (
-) or other illegal character (
ab-z.com), or be one of Java's reserved words (
Convention dictates that you prefix the digit with an underscore (
com._9), replace the illegal character with an underscore (
com.ab_z), and suffix the reserved word with an underscore (
To avoid additional problems with the package statement, there are a couple of rules that you need to follow:
The first rule, which is a special case of the second rule, exists because it doesn't make sense to store a reference type in multiple packages.
Although a package can store multiple types, a type can belong to only one package.
When a source file doesn't declare a package statement, the source file's types are said to belong to the unnamed package.
Non-trivial reference types are typically stored in their own packages and avoid the unnamed package.
Java implementations map package and subpackage names to same-named directories (or folders, if you prefer).
For example, an implementation would map
graphicsto a directory named
a would map to a directory named
b would map to a
b subdirectory of
a. The compiler stores the class files that implement the package's types in the corresponding directory.
Note that the unnamed package corresponds to the current directory.
A practical example will help you fully grasp the package statement. I'm demonstrating package in the context of an image library that lets you read image files and obtain image data. For brevity, only a skeletal version of the library is presented.
The image library currently consists of only three classes:
Image describes an image and is the library's main class. Listing 1 presents its source code.
public final class Image
private int argb;
private int width, height;
Image(int argb, int width, int height)
// argb is an array of alpha, red, blue, and green values.
this.argb = argb;
this.width = width;
this.height = height;
public int getARGB()
public int getHeight()
public int getWidth()
public static Image newImage(String filename) throws ImageException
throw new ImageException("unsupported format");
Image class is stored in file
Image.java. This listing begins with a package statement that identifies
ca.javajeff.image as the class's package.
Image is declared
public so that it can be referenced from outside of its package. Also, it's declared
final so that it cannot be extended (subclassed).
height fields to store image data. These fields are initialized to the values passed to
Image's constructor is declared package-private (the constructor isn't declared
protected) so that this class cannot be instantiated from outside of its package.
getWidth() methods for returning an image's pixel values, height, and width. Each method is declared
public so that it can be called from outside of
Image concludes with a
newImage() factory method for returning an
Image object corresponding to the
filename argument. If the image cannot be obtained,
ImageException (see Listing 2) is thrown.
public final class ImageException extends Exception
public ImageException(String message)
ImageException class is located in the same
ca.javajeff.image package as
Image, and is declared
public so that it's accessible beyond this package. Also,
ImageException extends the
Exception class in the default
java.lang package, and provides an appropriate constructor that forwards the string passed to
message to the
Exception(String message) constructor.
filename's extension with
.png (only PNG images are currently supported). If they match,
return PngReader.read(filename) is executed (return an
Image object with PNG image data). Listing 3 describes
final class PngReader
static Image read(String filename) throws ImageException
// Read the contents of filename's file and process it
// into argb, width, and height values. Throw
// ImageException if there is an I/O error.
return new Image(new int, 0, 0);
PngReader is intended to read a PNG file's contents into an
Image object. (The class will eventually be larger with additional
private fields and/or methods.) Notice that this class isn't declared
public, which makes
PngReader accessible to
Image but not to code outside of the
ca.javajeff.image package. Think of
PngReader as a helper class whose only reason for existence is to serve
ca/javajeff/imagesubdirectory hierarchy within the current directory.
PngReader.java, respectively; and store these files in the
javac ca/javajeff/image/*.javato compile the three source files in
ca/javajeff/image. If all goes well, you should discover
PngReader.classfiles in the
imagesubdirectory. (Alternatively, for this example, you could switch to the
imagesubdirectory and execute
Now that you've created the image library, you'll want to use it.
Later, I'll present a small Java application that property demonstrates this library, but first you need to learn about the import statement.
Imagine having to repeatedly specify
ca.javajeff.graphics.Rectangle for each occurrence of
Rectangle in source code.
Java provides a convenient alternative for omitting lengthy package details. This alternative is the import statement.
The import statement imports types from a package by telling the compiler where to look for unqualified (no package prefix) type names during compilation. It appears near the top of a source file and must conform to the following syntax:
import identifier[.identifier]*.(typeName | *);
An import statement starts with reserved word
import and continues with an identifier, which is optionally followed by a period-separated sequence of identifiers. A type name or asterisk (
*) follows, and a semicolon terminates this statement.
The syntax reveals two forms of the import statement.
* symbol is a wildcard that represents all unqualified type names. It tells the compiler to look for such names in the right-most package of the import statement's package sequence, unless the type name is found in a previously searched package.
Note that using the wildcard doesn't have a performance penalty or lead to code bloat. However, it can lead to name conflicts, which you will see.
import ca.javajeff.graphics.Rectangle; tells the compiler that an unqualified
Rectangle class exists in the
ca.javajeff.graphics package. Similarly,
import ca.javajeff.graphics.*; tells the compiler to look in this package when it encounters a
Rectangle name, a
Circle name, or even an
Account hasn't already been found).
When working on a multi-developer project, avoid using the
* wildcard so that other developers can easily see which types are used in your source code.
You can run into name conflicts when using the wildcard version of the import statement because any unqualified type name matches the wildcard.
For example, you have
geometry packages that each contain a
Rectangle class, the source code begins with
import geometry.*; and
import graphics.*;statements, and it also contains an unqualified occurrence of
Because the compiler doesn't know if
Rectangle refers to
Rectangle class or to
Rectangle class, it reports an error. You can fix this problem by qualifying
Rectangle with the correct package name (
To avoid additional problems with the import statement, there are a couple of rules that you need to follow:
The compiler automatically imports types from the
java.lang library package. As a result, you don't have to specify
import java.lang.System; (import
System class) or similar import statements in your source code.
Because Java implementations map package and subpackage names to same-named directories, an import statement is equivalent to loading a reference type's class file from the directory sequence corresponding to the package sequence.
I've created a
DemoImage application that demonstrates the image library. Listing 4 presents this application's source code.
public final class DemoImage
public static void main(String args) throws ImageException
if (args.length != 1)
System.err.println("usage: java DemoImage filename");
Image image = Image.newImage(args);
for (int i = 0; i < image.getARGB().length; i++)
System.out.print(image.getARGB()[i] + " ");
System.out.printf("Width: %d%n", image.getWidth());
System.out.printf("Height: %d%n", image.getHeight());
Listing 4 doesn't begin with a package statement because simple applications are typically not stored in packages. Instead, it begins with two import statements for importing the image library's
main() method first verifies that a single command-line argument has been specified. If verification succeeds, it passes this argument to
Image.newImage() and assigns the returned
Image object's reference to a local variable named
main() then proceeds to interrogate this
Image object, outputting the image's ARGB values along with its width and height.
Copy Listing 4 to a file named
DemoViewer.java and place this file in the same directory as the
ca directory that you previously created. Then, execute the following command to compile
If all goes well, you should observe
DemoImage.class in the current directory.
Execute the following command to run
DemoImage against a fictitious PNG file named
java DemoImage image.png
You should observe the following output:
DemoImage.java wasn't located in the same directory as
ca. How would you compile this source file and run the resulting application? The answer is to use the classpath.
The classpath is a sequence of packages that the Java virtual machine (JVM) searches for reference types. It's specified via the
-cp) option used to start the JVM or, when not present, the
CLASSPATH environment variable.
Whether you use the
-cp option or the
CLASSPATH environment variable to specify a classpath, there is a specific format that must be followed. Under Windows, this format is expressed as
path2, and so on are the locations of package directories. Under Mac OS X, Unix, and Linux, this format changes to
Suppose (on a Windows platform) that the image library is stored in
C:\image and that
DemoImage.java is stored in
C:\DemoImage, which is current. Specify the following commands to compile the source code and run the application:
javac -cp ../image DemoImage.java
java -cp ../image;. DemoImage image.png
The period character in the
java-prefixed command line represents the current directory. It must be specified so that the JVM can locate
The Java language includes a
protected keyword that's useful in a package context. Also, the JVM follows a specific search order when searching packages for reference types. This section explores these topics.
protected keyword assigns the protected access level to a class member, such as a field or method (e.g.,
protected void clear()). Declaring a class member
protected makes the member accessible to all code in any class located in the same package and to subclasses regardless of their packages.
Joshua Bloch explains the rationale for giving class members protected access in "Item 17: Design and document for inheritance or else prohibit it" of his book, Effective Java Second Edition.
They are hooks into a class's internal workings to let programmers "write efficient subclasses without undue pain." Check out this book for more information.
Newcomers to Java packages often become frustrated by "no class definition found" and other errors. This frustration can be partly avoided by understanding how the JVM looks for reference types.
To understand this process, you must realize that the compiler is a special Java application that runs under the control of the JVM. Also, there are two forms of search.
When the compiler encounters a type expression (such as a method call) in source code, it must locate that type's declaration to verify that the expression is legal (a method exists in the type's class whose parameter types match the types of the arguments passed in the method call, for example).
The compiler first searches the Java platform packages, which contain Java's standard class library types (such as
It then searches extension packages for extension types. If the
-sourcepath option is specified when starting the JVM (via the
javac compiler tool), the compiler searches the indicated path's source files.
Java platform packages are stored in
rt.jar and a few other important Java ARchive (JAR) files. (A JAR file is a Zip file with a
.jar extension that includes a
META-INF directory containing a
manifest.mf file and possibly additional content.) Extension packages are stored in a special extensions directory named
This directory is located in the
lib subdirectory of the Java home directory's
Otherwise, it records the package information in the class file.
When the compiler or any other Java application runs, the JVM will encounter types and must load their associated class files via special code known as a classloader.
The JVM will use the previously stored package information that's associated with the encountered type in a search for that type's class file.
The JVM searches the Java platform packages, followed by extension packages, followed by the classpath or current directory (when there is no classpath) for the first class file that contains the type.
If no package matches or the type cannot be found, a "no class definition found" error is reported. Otherwise, the class file is loaded into memory.
Now that you've learned how to construct libraries with the help of the package statement and how to import library types into your applications with the help of the import statement, consider creating your own useful library and application, to gain more experience with packages.
You might find it helpful to store your library's class files in a JAR file for more convenient distribution of the library.
Jeff Friesen teaches Java technology (including Android) to everyone via articles, books, blogs and software. In addition to writing Java books for Apress, Jeff has written numerous articles on Java and other technologies for JavaWorld, InformIT, Java.net and SitePoint. Jeff can be reached via his website at JavaJeff.ca.