Packages are Java's way of grouping classes together. This isn't much of an
issue when you're first starting out. For beginners, it's quite adequate
just to compile classes and leave them all in the same directory. Later on,
though, when you start to feel like that one directory is getting a tad
cluttered, it's a good time to invest a few brain cells in learning about
packages.
Package statements look like this:
package com.neo.ui;
This statement means that the class defined in this file belongs to the
com.neo.ui package. So, for example, suppose you defined a class as
follows:
public class Widget extends Component
This means that your Widget class is part of the com.neo.ui package. When
the Java1 virtual machine (JVM) looks for your Widget class, it will be looking for
com.neo.ui.Widget. But what does that mean?
It means that Java will look in the com/neo/ui directory for a file named
Widget.class when it tries to load this class. If your CLASSPATH is ~/java,
it will look for ~/java/com/neo/ui/Widget.class. If your CLASSPATH is
C:\Java it will look for C:\Java\com\neo\ui\Widget.class. Of course, your
CLASSPATH will usually include your current working directory, so in
addition to the above places, it would also look in the com/neo/ui
directory relative to your current directory to find Widget.class.
If, for example, you wish to use this class from an applet on the server
www.neo.com, and the applet is called MyApplet, your HTML might look like
this:
<APPLET CODE="MyApplet"
CODEBASE="http://www.neo.com/Java/Classes"
WIDTH="40" HEIGHT="30"> </applet>
In this case, the file MyApplet.class should be in the Java/Classes
directory relative to the document root on your server, and
Widget.class must be in Java/Classes/com/neo/ui.
And if you wish to refer to this class, you will need to let the compiler
know which package it's in. You can do this one of two ways. The first,
seldom used, but more explicit way is to declare a variable using the fully
qualified name of the class:
com.neo.ui.Widget myWidget =
new com.neo.ui.Widget("A Widget!");
The second and much more common way (in fact you've probably used it
youself many times) is to import the package containing the widget. Include
the following statement at the beginning of your .java file:
import com.neo.ui.Widget;
From then on, you can just refer to that widget as Widget, and the compiler
will know what kind of widget you mean, as shown:
Widget myWidget = new Widget("A Widget!");
You can likewise import all of the classes in a package with the following
syntax:
import com.neo.ui.*;
That way, if you had defined both Widget and another class Gadget as being
part of package com.neo.ui, you could refer to either by just their class
name:
import com.neo.ui.*;
Widget myWidget = new Widget("A Widget!");
Gadget myGadget = new Gadget();
So which is better?
Most of the time it really doesn't matter too much which of these
approaches you take. The class files they produce will be identical. The
only places where it makes any difference are in compile time, and in cases
where you wish to use two different classes that have the same name.
The difference in compile time has to do with the fact that it takes the
compiler a little longer to search through a longer list of possible class
names to find a match. The more explicitly you tell it the class to which
you're referring (through the import statement, or through the explicit use
of fully qualified classnames), the less time it has to spend trying to
match up the class to the package that contains it.
The other rare case, and the only one where it's actually necessary to use
fully qualified class names, occurs when you intend to use two
classes with exactly the same name:
com.neo.ui.Button myFirstButton =
new com.neo.ui.Button("One kind of button");
java.awt.Button mySecondButton =
new java.awt.Button("Another kind of button");
Reuse of names should be avoided where possible, as it makes code much
harder to read and interpret (for the human programmer, though not for the
Java Virtual Machine). Ten pages into the code, you might find it hard to
remember whether myFirstButton referred to a regular java.awt.Button or to
a custom com.neo.ui.Button. It also means that you'll have to type out the
fully qualified class name every time you use it, since there will be no
way for the compiler to know that you meant java.awt.Button when you simply
typed Button. (Or was that com.neo.ui.Button?)
You may run into a situation where you have no choice about this, for
example when using a third-party library with another third-party library,
where both define an ImageButton. Other than that, though, it should be
easy to avoid.
So what should I name my package?
There is a convention to name your packages based on the domain name of
your company or of your web site. This helps to prevent name conflicts of
the type mentioned above, but of a more intractable type. (Suppose you had
two classes, from different providers, both named interface.Widget.) The
domain name is reversed, so that the least specific part is at the left,
and the more specific parts to the right. Therefore, neo.com becomes
com.neo.
Within a domain, a lot depends on the organization of the entity the domain
name represents. At a small company like Neo Communication, we break this
down into client names next, so we use either com.neo.msp or com.neo.gcpw.
For individuals, breaking this down by email address is attractive, so you
could have a name such as com.netcom.ix.netranger or
com.aol.surfdog977653. The main thing is to assure that the name will be
unique. For this reason, just using com.netcom or com.compuserve is really
not enough.
Having decided on a unique identifier for all of your classes, package
names are broken down further still based on the particular application or
project the files belong to, or if they are general resources, according to
category. com.neo.ui is the package where we keep all of our generic user
interface classes. com.neo.imf.mcnotes is where I keep my McNotes project
files. The main thing is that the structure make sense to you.
So what about protected data?
In addition to keeping files organized, packages help with encapsulation
and data hiding. By using the protected keyword, variables can be made
visible only to classes within the same package as the class to which the
variables belong. It makes sense to group related classes into packages, so
that they can share access to methods and variables, while hiding the
complexity of their interaction from other objects that don't use that
information. For example, a chat program might be defined within package
com.neo.chat, but all the networking code might reside within
com.neo.chat.network, and all the user interface code might reside
within com.neo.chat.ui. This way, the size of the interface between the
different sections can be kept small, so it's easier for teams to work on
the same project, and for portions of a project to be revised without
impacting other portions of a project.
Lessons most people learn the hard way
These are the hidden assumptions of Java that often bite beginners:
The package statement must be the first line of code in any file where it
is used. (Comments excluded.)
The package to which an object belongs is implicitly imported and
available within any file where such a declaration appears. Therefore, the
following is legal:
package com.neo.ui;
import java.awt.Panel;
public class WidgetPanel extends Panel { Widget[]
myWidgets; . . .
}
The import statement only imports classes from the specified package, not
from subpackages. This means that import com.neo.*; will import
com.neo.FunApplet.class, but not com.neo.ui.Widget.class. This is to
improve compiler performance and to mitigate namespace conflicts. You won't
want to import all the image manipulation classes in java.awt.image every
time you want to use something in java.awt, for instance.
You should also know that if you don't specify a package, your class
becomes part of the "default package," which means that it has access to
other classes not specifically belonging to other packages.
Where should you go from here?
Now you might want to take a look at all that code with the mysterious
package statement at the beginning (remember that it must be the very first
line of code), and see if the reasoning behind it is clearer. You might
try using a package statement in some of your code, to group it all
together. Don't forget that member classes of a given package must reside
in a directory with the same name as the package, and that the directory
itself (and not the class files) must be in the search path. And if you don't
get it at first, reread the beginning of this article, and check to make
sure you understand which directories are on the search path. It's a new
way of thinking, but if you're persistent in trying to understand it, it
sinks in eventually.
_______
1 As used on this web site, the terms
"Java virtual machine" or "JVM" mean a virtual machine for the Java platform.