Creating and using packages
To make classes easier to find and to use, to avoid naming conflicts, and to control
access, programmers bundle groups of related classes and interfaces into packages.
Definition 2. A package is a collection of related classes and interfaces providing access
protection and namespace management.
The classes and interfaces that are part of the Java platform are members of various
packages that bundle classes by function: fundamental classes are in java.lang, classes for
reading and writing (input and output) are in java.io, and so on. You can put your classes
and interfaces in packages, too.
Let's look at a set of classes and examine why you might want to put them in a package.
Suppose that you write a group of classes that represent a collection of graphic objects, such
as circles, rectangles, lines, and points. You also write an interface, Draggable, that classes
implement if they can be dragged with the mouse by the user:
| Code: |
//in the Graphic.java file
public abstract class Graphic {
. . .
}
//in the Circle.java file
public class Circle extends Graphic implements Draggable {
. . .
}
//in the Rectangle.java file
public class Rectangle extends Graphic implements Draggable {
. . .
}
//in the Draggable.java file
public interface Draggable {
. . .
}
|
You should bundle these classes and the interface in a package for several reasons:
- You and other programmers can easily determine that these classes and interfaces are
related.
- You and other programmers know where to find classes and interfaces that provide
graphics-related functions.
- The names of your classes wont conflict with class names in other packages, because
the package creates a new namespace.
- You can allow classes within the package to have unrestricted access to one another yet
still restrict access for classes outside the package.
Creating a package
To create a package, you put a class or an interface in it. To do this, you put a package
statement at the top of the source file in which the class or the interface is defined. For
example, the following code appears in the source file Circle.java and puts the Circle
class in the graphics package:
| Code: |
package graphics;
public class Circle extends Graphic implements Draggable {
. . .
}
|
The Circle class is a public member of the graphics package.
You must include a package statement at the top of every source file that defines a class
or an interface that is to be a member of the graphics package. So you would also include
the statement in Rectangle.java and so on:
| Code: |
package graphics;
public class Rectangle extends Graphic implements Draggable {
. . .
}
|
The scope of the package statement is the entire source file, so all classes and
interfaces defined in Circle.java and Rectangle.java are also members of the graphics
package. If you put multiple classes in a single source file, only one may be public, and it must
share the name of the source files base name. Only public package members are accessible
from outside the package.
If you do not use a package statement, your class or interface ends up in the default
package, which is a package that has no name. Generally speaking, the default package
is only for small or temporary applications or when you are just beginning development.
Otherwise, classes and interfaces belong in named packages.
Naming a package
With programmers all over the world writing classes and interfaces using the Java
programming language, it is likely that two programmers will use the same name for two
different classes. In fact, the previous example does just that: It defines a Rectangle class
when there is already a Rectangle class in the java.awt package. Yet the compiler allows
both classes to have the same name.
Why? Because they are in different packages, and
the fully qualified name of each class includes the package name. That is, the fully qualified
name of the Rectangle class in the graphics package is graphics.Rectangle, and the fully
qualified name of the Rectangle class in the java.awt package is java.awt.Rectangle.
This generally works just fine unless two independent programmers use the same name
for their packages. What prevents this problem? Convention.
By Convention: Companies use their reversed Internet domain name in their package
names, like this: com.company.package.
Some companies now choose to drop the
first element com.
in this example from their package names.
Name collisions that
occur within a single company need to be handled by convention within that company,
perhaps by including the region or the project name after the company name, for example, com.company.region.package.
Using package members
Only public package members are accessible outside the package in which they are
defined. To use a public package member from outside its package, you must do one or more
of the following:
- Refer to the member by its long (qualified) name.
- Import the package member.
- Import the members entire package.
Each is appropriate for different situations.
Referring to a package member by name
So far, the examples have referred to classes and interfaces by their simple names, such
as Rectangle and StockWatcher. You can use a package members simple name if the code
you are writing is in the same package as that member or if the members package has been
imported.
However, if you are trying to use a member from a different package and that package
has not been imported, you must use the members qualified name, which includes the
package name. This is the qualified name for the Rectangle class declared in the graphics
package in the previous example:
graphics.Rectangle
You could use this long name to create an instance of graphics.Rectangle:
| Code: |
graphics.Rectangle myRect = new graphics.Rectangle();
|
You'll find that using long names is okay for one-shot uses. But you'd likely get annoyed
if you had to write graphics.Rectangle again and again. Also, your code would get very
messy and difficult to read. In such cases, you can just import the member instead.
Importing a package member
To import a specific member into the current file, put an import statement at the
beginning of your file before any class or interface definitions but after the package statement,
if there is one. Here's how you would import the Circle class from the graphics package
created earlier:
| Code: |
import graphics.Circle;
|
Now you can refer to the Circle class by its simple name:
| Code: |
Circle myCircle = new Circle();
|
This approach works well if you use just a few members from the graphics package.
But if you use many classes and interfaces from a package, you can import the entire package.
Importing an entire package
To import all the classes and interfaces contained in a particular package, use the
import statement with the asterisk (*) wildcard character:
Now you can refer to any class or interface in the graphics package by its short name:
| Code: |
Circle myCircle = new Circle();</p>
Rectangle myRectangle = new Rectangle();
|
The asterisk in the import statement can be used only to specify all the classes within
a package, as shown here. It cannot be used to match a subset of the classes in a package.
For example, the following does not match all the classes in the graphics package that begin
with A:
| Code: |
import graphics.A*; // does not work
|
Instead, it generates a compiler error. With the import statement, you can import only
a single package member or an entire package.
For your convenience, the Java runtime system automatically imports two entire
packages:
- The java.lang package.
- The current package by default.
Disambiguating a name
If by some chance a member in one package shares the same name with a member
in another package and both packages are imported, you must refer to each member by its
qualified name. For example, the previous example defined a class named Rectangle in
the graphics package. The java.awt package also contains a Rectangle class. If both
graphics and java.awt have been imported, the following is ambiguous:
In such a situation, you have to be more specific and use the members qualified name
to indicate exactly which Rectangle class you want:
| Code: |
graphics.Rectangle rect;
|
Managing source and class files
Many implementations of the Java platform rely on hierarchical file systems to manage
source and class files, although The Java Language Specification does not require this. The
strategy is as follows.
You put the source code for a class or an interface in a text file whose name is the
simple name of the class or the interface and whose extension is .java. Then you put the
source file in a directory whose name reflects the name of the package to which the class
or the interface belongs. For example, the source code for the Rectangle class would be in
a file named Rectangle.java, and the file would be in a directory named graphics.
The
graphics directory might be anywhere on the file system. The figure below shows how this
works.

The qualified name of the package member and the path name to the file are parallel,
assuming the Windows file name separator slash (\):
class name
graphics.Rectangle
pathname to file
graphics\Rectangle.java
As you may recall, by convention a company uses its reversed Internet domain name
in its package names. The fictional company whose Internet domain name is taranis.com
would precede all its package names with com.taranis. Each component of the package
name corresponds to a subdirectory. So if Taranis had a graphics package that contained
a Rectangle.java source file, it would be contained in a series of subdirectories, as shown
below.

When you compile a source file, the compiler creates a different output file for each class
and interface defined in it. The base name of the output file is the name of the class or the
interface, and its extension is .class, as shown in the following figure.

Like a .java file, a .class file should also be in a series of directories that reflect the
package name. However, it does not have to be in the same directory as its source. You could
arrange your source and class directories separately, as shown below.

By doing this, you can give the classes directory to other programmers without revealing
your sources.
Why all the bother about directories and file names? You need to manage your source
and class files in this manner so that the compiler and the interpreter can find all the classes
and interfaces your program uses. When the compiler encounters a new class as its compiling
your program, it must be able to find the class so as to resolve names, do type checking, and
so on. Similarly, when the interpreter encounters a new class as its running your program, it
must be able to find the class to invoke its methods, and so on. Both the compiler and the
interpreter search for classes in each directory or ZIP file listed in your class path.
Definition 3. A class path is an ordered list of directories or ZIP files in which to search for
class files.
Each directory listed in the class path is a top-level directory in which package directories
appear. From the top-level directory, the compiler and the interpreter can construct the rest of
the path, based on the package and the class name for the class. For example, the class path
entry for the directory structure shown in the previous diagram would include classes but not
com or any of the directories below com. Both the compiler and the interpreter construct the
path name to a .class file with its full package name.
By default, the compiler and the interpreter search the current directory and the ZIP file
containing the Java platform class files. In other words, the current directory and the Java
platform class files are automatically in your class path. Most, if not all, classes can be found
in these two locations. So its likely that you don't have to worry about your class path. In some
cases, however, you might have to set your class path.
13808 bytes more | comments? | | Score: 0
|