Packages in Java

By now you should be familiar with Java, and you have probably written several small projects or assignments consisting of a few separate Java files stored in one directory. This is fine for small projects, but as the number of files grows, organization and grouping of the files becomes important. You may also wish to use the same names for different classes. That's where packages in Java become very useful.

What Are Packages?

A package is a collection of related Java files stored in a directory or folder. Ideally, each package represents a logical grouping of functionality. For instance, SaM's packages group classes for the user interface, simulator, and machine instructions. A package can also contain another package. In this case, the directory that holds the parent package will contain a subdirectory corresponding to the child package. Thus, each package has a unique name based on the names of the directories in which they are stored. The package name is the path from the root directory of your code to the directory containing that package, using . to separate names instead of \ or /.

For instance, if I have the following directories:

   cis300\game\control\
   cis300\game\graphics\
   cis300\raytracer\

then cis300, cis300.game, cis300.game.control, cis300.game.graphics, and cis300.raytracer can all be packages. There's an additional, unnamed default package, that corresponds to the root of the tree. In the above example, the default package is the directory that contains the cis300.

If a Java file belongs to a package other than the default unnamed one, then you must declare so in the file. This is done via a package statement, which is a statement that alerts Java that classes in the current file belong to a particular package. For example, if I have a Java file Car3d.java in the cis300.game.graphics package, then at the top of the file (before any classes or import statements, I need to write the following line:

   package cis300.game.graphics;

Note that Java will complain if a file is in a different package than what the package statement declares. For instance, if Car3d.java was actually stored in the cis300\raytracer\ directory, then the above package statement would cause an error. If a file is in the default package, then no package statement is necessary (or allowed).

Classpaths

Since any directory could be a package, how does Java know where to look to find your code? It does so by looking at the CLASSPATH. If you use an IDE to develop code, this should already be taken care of. If you compile and run on the command line, however, you'll need to manually change the CLASSPATH. On Windows machines, you can run the following command:

   set CLASSPATH=C:\directory1;C:\directory2

which sets CLASSPATH to a list of directories separated by semicolons. Each directory in that list corresponds to a root directory in the hierarchy. Java files in those directories are in their respective default packages, and subdirectories in those directories can correspond to packages.

The easiest way to do set CLASSPATH is using the current directory, which is a single period .. For example, if I store all my code in C:\MyStuff\MyCode, I can run the following commands at the command line:

   C:\MyStuff\MyCode> set CLASSPATH=.
   C:\MyStuff\MyCode> javac cis300\game\*.java
   C:\MyStuff\MyCode> java cis300.game.MainGame

presuming the package structure above. Note: the change in CLASSPATH is only effective while that command window is open. If you close that window and open another one, you'll have to reset your CLASSPATH. To permanently change your system settings, refer to Applications.

Using Packages and Imports

Suppose I have two classes in the above hierarchy: cis300.game.MainGame and cis300.game.graphics.Display. I go into MainGame and write the following code:

   package cis300.game;

   public class MainGame {
      public MainGame() {
         Display d = new Display();
      }
   }

If you try and compile this code, Java will give you an error. Why? After all, you've told it where your packages are! The answer is that you aren't using the proper name for the class Display. The correct name for Display is actually cis300.game.graphics.Display, which is as the fully-qualified class name. If I want to create a Display object, I need to change that line of code to

   cis300.game.graphics.Display d = new cis300.game.graphics.Display();

Such long names get cumbersome very quickly. Instead, you should use import statements instead. An import allows you to use one or more classes in a given package without using the fully-qualified class name. For instance, if I add the line

   import cis300.game.graphics.Display;

inbetween the package statement and the class statement, then I can use the class name Display without the package name. If I want to import all of the classes in a given package (say, cis300.game.graphics), I can use a star * instead:

   import cis300.game.graphics.*;

The above statement is equivalent to writing an import statement for every class in that package. However, the * is usually frowned upon. Why? You are likely importing classes you do not use, creating potential collisions between names. For instance, suppose the package you import has a class named Sprite, which is the name of an entirely different class in the current package.

If you wish to use a class in the same package as another class, you do not need an import statement. For example, if package cis300.game contains classes HighScores and MainGame, either class can "see" each other with out importing the other.

Access Levels

Some of you may be familiar with the public / private / protected access modifiers. Much of the detail will be skipped here, but as it relates to packages, classes within the same package can access public, protected, and package-level (those without any of the other three modifiers) methods, classes, and variables. Classes in different packages can only access the public classes, methods, and variables in the respective packages.