Main Page

Previous Next

Understanding Packages

Important 

Packages are fundamental to Java programs so make sure you understand this section.

Packages are implicit in the organization of the standard classes as well as your own programs, and they influence the names you can use for classes and the variables and methods they contain. Essentially, a package is a unique named collection of classes. The purpose of grouping classes in a package with a unique name is to make it easy to add any or all of the classes in a package into your program code. One aspect of this is that the names used for classes in one package will not interfere with the names of classes in another package, or your program, because the class names in a package are qualified by the package name.

Every class in Java is contained in a package, including all those we have defined in our examples. You haven't seen many references to package names so far because we have been implicitly using the default package to hold our classes, and this doesn't have a name.

All of the standard classes in Java are contained within packages. The package that contains most of the standard classes that we have used so far is called java.lang. You haven't seen any explicit reference to this in your code either, because this package is automatically available to your programs. Things are arranged this way because some of the classes in java.lang, such as String, are used in every program. There are other packages containing standard classes that you will need to include explicitly when you use them, as we did in the previous chapter with the StringTokenizer class.

Packaging Up Your Classes

Putting one of your classes in a package is very simple. You just add a package statement as the first statement in the source file containing the class definition. Note that it must always be the first statement. Only comments or blank lines are allowed to precede the package statement. A package statement consists of the keyword, package, followed by the package name, and is terminated by a semi-colon. If you want the classes in a package to be accessible outside the package, you must declare the class using the keyword public in the first line of your class definition. Class definitions that aren't preceded by the keyword public are only accessible from methods in classes that belong to the same package.

For example, to include the class Sphere in a package called Geometry, the contents of the file Sphere.java would need to be:

package Geometry;

public class Sphere {
  // Details of the class definition
}

Each class that you want to include in the package Geometry must contain the same package statement at the beginning, and you should save all the files for the classes in the package in a directory with the same name as the package, that is, Geometry. Note the use of the public keyword in the definition of the Sphere class. This is to make the class usable generally.

Note that you would also need to declare the constructors and methods in the class as public if you want them to be accessible from outside of the package. We will return to this in more detail a little later in this chapter.

Packages and the Directory Structure

Packages are actually a little more complicated than they appear at first sight, because a package is intimately related to the directory structure in which it is stored. You already know that the definition of a class with the name ClassName must be stored in a file with the name ClassName.java, and that all the files for classes within a package, PackageName, must be included in a directory with the name PackageName. You can compile the source for a class within a package and have the .class file that is generated stored in a different directory, but the directory name must still be the same as the package name.

A package need not have a single name. You can specify a package name as a sequence of names separated by periods. For example, you might have developed several collections of classes dealing with geometry, one dealing with 2D shapes and another with 3D shapes. In this case you might include the class Sphere in a package with the statement:

package Geometry.Shapes3D;

and the class for circles in a package using the statement:

package Geometry.Shapes2D;

In this situation, the packages are expected to be in the directories Shapes3D and Shapes2D, and both of these must be sub-directories of Geometry. In general, you can have as many names as you like separated by periods to identify a package, but the name must reflect the directory structure where the package is stored.

Click To expand

Compiling a Package

Compiling the classes in a package can be a bit tricky unless you are clear on how you go about it. We will illustrate what you need to do assuming you are using the JDK under Microsoft Windows. The path to the package directory has to be explicitly made known to the compiler, even when the current directory is the one containing the package. If we have stored the Geometry package source files in the directory with the path C:\Beg Java Stuff\Geometry, then the path to the Geometry directory is C:\Beg Java Stuff. You can tell the compiler about this path using the –classpath option on the command line. Assuming that the current directory is the Geometry directory, we could compile the Line.java source file with the command:

C:\JavaStuff\Geometry>javac –classpath "C:\Beg Java Stuff" Line.java

This will result in both the Line.java and Point.java files being compiled, since Line.java refers to the other class. Since the directory in the path contains spaces, we have to enclose the path between double quotes.

Accessing a Package

How you access a package, when you are compiling a program that uses the package, depends on where you have put it. There are a couple of options here. The first, but not the best, is to leave the .class files for the classes in the package in the directory with the package name.

Let's look at that before we go on to the second possibility.

With the .class files in the original package directory, either the path to your package must appear in the string set for the CLASSPATH environment variable, or you must use the classpath option on the command line when you invoke the compiler or the interpreter. This overrides the CLASSPATH environment variable if it happens to be set. Note that it is up to you to make sure the classes in your package are in the right directory. Java will not prevent you from saving a file in a directory that is quite different from that appearing in the package statement. Of the two options here, using the –classpath option on the command line is preferable, because it sets the classpaths transiently each time, and can't interfere with anything you do subsequently. In any event we will look at both possibilities.

If you elect to use the CLASSPATH environment variable, it only needs to contain the paths to your packages. The standard packages supplied with Java do not need to be considered as the compiler and the interpreter can always find them. For example, you might set it under Windows 95 or 98 by adding the command,

set CLASSPATH=.;C:\MySource;C:\MyPackages

to your autoexec.bat file. Now the compiler and the interpreter will look for the directories containing your packages in the current directory, as specified by the period, and the directories C:\MySource and C:\MyPackages. Of course, you may have as many paths as you want defined in CLASSPATH. They just need to be separated by semi-colons under Windows.

Under Unix, the equivalent to this might be:

CLASSPATH=.:/usr/local/mysource:/usr/local/mypackages

If you are using the Sun Java Development Kit, you also specify where your packages can be found by using the -classpath option when you execute the Java compiler or the interpreter. This has the advantage that it only applies for the current compilation or execution so you can easily set it to suit each run. The command to compile MyProgram.java defining the classpath as in the environment variable above would be:

javac –classpath ".;C:\MySource;C:\MyPackages" MyProgram.java

If you don't set the classpath in one of these ways, or you set it incorrectly, Java will not be able to find the classes in any new packages you might create.

A new feature introduced with Java 2 provides you with a second way to make your packages available once you have compiled them. This provides a way of adding extensions to the set of standard packages.

Using Extensions

Extensions are .jar files stored within the ext directory that is created when you install the JDK. For more information on the use of the JAR tool to create .jar archives, see Appendix A. The default directory structure that is created is shown below.

Click To expand

The classes and packages in the .jar archives that you place in the ext directory will automatically be accessible when you compile or run your Java programs, without the need to set the CLASSPATH environment variable, or to use the –classpath command line option. When you create a .jar file for a package, you need to make sure that you add the .class files with the directory structure corresponding to the package name – you can't just add the .class files to the archive. For example, suppose we want to store our Geometry package in an archive. Assuming we have already compiled the package and the current directory contains the package directory, the following command can be used to create the archive:

C:\JavaStuff>jar cvf Geometry.jar Geometry\*.class

This will create the archive Geometry.jar, and add all the .class files that are in the Geometry directory to it. All you now need to do, to make the package available to any program that needs it is to copy it, to the ext directory in the JDK directory hierarchy.

The diagram above also shows the classes directory, which may not be created by default. You can put .class files in this directory and they will be found automatically when a program uses the classes they contain.

Adding Classes from a Package to Your Program

Assuming they have been defined with the public keyword, you can add all or any of the classes in a package to the code in your program by using an import statement. You can reference the classes that you make available to your program using the import statement just by using the class names. For example, to make available all the classes in the package Geometry.Shapes3D to a source file, you just need to add the following import statement to the beginning of the file:

import Geometry.Shapes3D.*;   // Include all classes from this package

The keyword import is followed by the specification of what you want to import. The wildcard *, following the period after the package name, selects all the classes in the package, rather like selecting all the files in a directory. Now you can refer to any public class in the package just by using the class name. Again, the names of other classes in your program must be different from the names of the classes in the package.

If you want to add a particular class rather than an entire package, you specify its name explicitly in the import statement:

import Geometry.Shapes3D.Sphere;  // Include the class Sphere 

This includes only the Sphere class into the source file. By using a separate import statement for each individual class from the package, you can ensure that your source file only includes the classes that you need. This reduces the likelihood of name conflicts with your own classes, particularly if you are not fully familiar with the contents of the package and it contains a large number of classes.

Important 

Note that the * can only be used to select all the classes in a package. You can't use Geometry.* to select all the packages in the directory Geometry.

Packages and Names in Your Programs

A package creates a self-contained environment for naming your classes. This is the primary reason for having packages in Java. You can specify the names for classes in one package without worrying about whether the same names have been used elsewhere. Java makes this possible by treating the package name as part of the class name – actually as a prefix. This means that the class Sphere in the package Geometry.Shapes3D has the full name Geometry.Shapes3D.Sphere. If you don't use an import statement to incorporate the class in your program, you can still make use of the class by referring to it using its full class name. If you needed to do this with the class Sphere, you might declare a variable with the statement:

Geometry.Shapes3D.Sphere ball = new Geometry.Shapes3D.Sphere(10.0, 1.0, 1.0, 1.0);

While this is rather verbose, and certainly doesn't help the readability of the program, it does ensure there will be no conflict between this class and any other Sphere class that might be part of your program. You can usually contrive that your class names do not conflict with those in the commonly used standard Java packages, but in cases where you can't manage this, you can always fall back on using fully qualified class names. Indeed, there are occasions when you have to do this. This is necessary when you are using two different classes from different packages that share the same basic class name.

Standard Packages

All of the standard classes that are provided with Java are stored in standard packages. There is a substantial (more than 130 in SDK1.4) and growing list of standard packages but some of the ones you may hear about quite frequently are:

java.lang

Contains classes that are fundamental to Java (e.g. the Math class) and all of these are available in your programs automatically. You do not need an import statement to include them.

java.io

Contains classes supporting stream input/output operations.

java.nio

Contains classes supporting new input/output operations in JDK1.4 – especially with files.

java.nio.channels

Contains more classes supporting new input/output operations in JDK1.4 – the ones that actually read and write files.

java.awt

Contains classes that support Java's Graphical User Interface (GUI). While you can use these classes for GUI programming, it is almost always easier and better to use the alternative Swing classes.

javax.swing

Provides classes supporting the 'Swing' GUI components. These are not only more flexible and easier to use than the java.awt equivalents, but they are also implemented largely in Java with minimal dependency on native code.

javax.swing.border

Classes to support generating borders around Swing components.

javax.swing.event

Classes supporting event handling for Swing components.

java.awt.event

Contains classes that support event handling.

java.awt.geom

Contains classes for drawing and operating with 2D geometric entities.

java.awt.image

Contains classes to support image processing.

java.applet

This contains classes that enable you to write applets – programs that are embedded in a web page.

java.util

This contains classes that support a range of standard operations for managing collections of data, accessing date and time information, and analyzing strings.

The standard packages and the classes they contain cover an enormous amount of ground, so even in a book of this size it is impossible to cover them all exhaustively. There are now many more classes in the standard packages with JDK1.4 than there are pages in this book. However, we will be applying some classes from all of the packages in the table above, plus one or two others besides, in later chapters of the book.

Standard Classes Encapsulating the Basic Data Types

You saw in the previous chapter that we have classes available that allow you to define objects that encapsulate each of the basic data types in Java. These classes are:

Boolean

Character

Byte

Short

Integer

Long

Float

Double

 

These are all contained in the package java.lang along with quite a few other classes such as the String and StringBuffer classes that we saw in Chapter 4, and the Math class. Each of these classes encapsulates the corresponding basic type, and includes methods for manipulating and interrogating objects of the class, as well as a number of static methods that provide utility functions for the underlying basic types. Each of the classes corresponding to a numeric type provides a static toString() method to convert to a String object, as we saw in the last chapter. There is also a non-static toString()method in all of these classes that returns a String representation of a class object.

The classes encapsulating the numeric basic types each contain the static final constants MAX_VALUE and MIN_VALUE that define the maximum and minimum values that can be represented. The floating-point classes also define the constants POSITIVE_INFINITY, NEGATIVE_INFINITY, and NaN (stands for Not a Number as it is the result of 0/0), so you can use these in comparisons. Alternatively, you can test floating point values with the static methods isInfinite() and isNaN() – you pass your variable as an argument, and the methods return true for an infinite value or the NaN value respectively. Remember that an infinite value can arise without necessarily dividing by zero. Any computation that results in an exponent that is too large to be represented will produce either POSITIVE_INFINITY or NEGATIVE_INFINITY.

Conversely there are methods to convert from a String to a basic type. For example, the static parseInt()member of the class Integer accepts a String representation of an integer as an argument, and returns the equivalent value as type int. An alternative version of this method accepts a second argument of type int that specifies the radix to be used. If the String object cannot be parsed for any reason, if it contains invalid characters for instance, the method will throw an exception of type NumberFormatException. All the standard classes define methods to parse strings – parseShort(), parseByte(), and parseLong().

There are many other operations supported by these classes so it is well worth browsing the JDK documentation for them.

Previous Next
JavaScript Editor Java Tutorials Free JavaScript Editor