Creating unique package names
You might observe that, since a package never really gets packaged into a single file, a package could be made up of many .class files, and things could get a bit cluttered. To prevent this, a logical thing to do is to place all the .class files for a particular package into a single directory; that is, use the hierarchical file structure of the operating system to your advantage. This is one way that Java references the problem of clutter; youll see the other way later when the jar utility is introduced.
Collecting the package files into a single subdirectory solves two other problems: creating unique package names, and finding those classes that might be buried in a directory structure someplace. This is accomplished, as was introduced in Chapter 2, by encoding the path of the location of the .class file into the name of the package. By convention, the first part of the package name is the reversed Internet domain name of the creator of the class. Since Internet domain names are guaranteed to be unique, if you follow this convention, your package name will be unique and youll never have a name clash. (That is, until you lose the domain name to someone else who starts writing Java code with the same path names as you did.) Of course, if you dont have your own domain name, then you must fabricate an unlikely combination (such as your first and last name) to create unique package names. If youve decided to start publishing Java code, its worth the relatively small effort to get a domain name.
The second part of this trick is resolving the package name into a directory on your machine, so when the Java program runs and it needs to load the .class file (which it does dynamically, at the point in the program where it needs to create an object of that particular class, or the first time you access a static member of the class), it can locate the directory where the .class file resides.
The Java interpreter proceeds as follows. First, it finds the environment variable CLASSPATH[27] (set via the operating system, and sometimes by the installation program that installs Java or a Java-based tool on your machine). CLASSPATH contains one or more directories that are used as roots in a search for .class files. Starting at that root, the interpreter will take the package name and replace each dot with a slash to generate a path name from the CLASSPATH root (so package foo.bar.baz becomes foo\bar\baz or foo/bar/baz or possibly something else, depending on your operating system). This is then concatenated to the various entries in the CLASSPATH. Thats where it looks for the .class file with the name corresponding to the class youre trying to create. (It also searches some standard directories relative to where the Java interpreter resides).
To understand this, consider my domain name, which is bruceeckel.com. By reversing this, com.bruceeckel establishes my unique global name for my classes. (The com, edu, org, etc., extensions were formerly capitalized in Java packages, but this was changed in Java 2 so the entire package name is lowercase.) I can further subdivide this by deciding that I want to create a library named simple, so Ill end up with a package name:
package com.bruceeckel.simple;
Now this package name can be used as an umbrella name space for the following two files:
//: com:bruceeckel:simple:Vector.java
// Creating a package.
package com.bruceeckel.simple;
public class Vector {
public Vector() {
System.out.println("com.bruceeckel.simple.Vector");
}
} ///:~
When you create your own packages, youll discover that the package statement must be the first noncomment code in the file. The second file looks much the same:
//: com:bruceeckel:simple:List.java
// Creating a package.
package com.bruceeckel.simple;
public class List {
public List() {
System.out.println("com.bruceeckel.simple.List");
}
} ///:~
Both of these files are placed in the subdirectory on my system:
C:\DOC\JavaT\com\bruceeckel\simple
If you walk back through this, you can see the package name com.bruceeckel.simple, but what about the first portion of the path? Thats taken care of in the CLASSPATH environment variable, which is, on my machine:
CLASSPATH=.;D:\JAVA\LIB;C:\DOC\JavaT
You can see that the CLASSPATH can contain a number of alternative search paths.
Theres a variation when using JAR files, however. You must put the name of the JAR file in the classpath, not just the path where its located. So for a JAR named grape.jar your classpath would include:
CLASSPATH=.;D:\JAVA\LIB;C:\flavors\grape.jar
Once the classpath is set up properly, the following file can be placed in any directory:
//: c05:LibTest.java
// Uses the library.
import com.bruceeckel.simpletest.*;
import com.bruceeckel.simple.*;
public class LibTest {
static Test monitor = new Test();
public static void main(String[] args) {
Vector v = new Vector();
List l = new List();
monitor.expect(new String[] {
"com.bruceeckel.simple.Vector",
"com.bruceeckel.simple.List"
});
}
} ///:~
When the compiler encounters the import statement for the simple library, it begins searching at the directories specified by CLASSPATH, looking for subdirectory com\bruceeckel\simple, then seeking the compiled files of the appropriate names (Vector.class for Vector, and List.class for List). Note that both the classes and the desired methods in Vector and List must be public.
Setting the CLASSPATH has been such a trial for beginning Java users (it was for me, when I started) that Sun made the JDK in Java 2 a bit smarter. Youll find that when you install it, even if you dont set the CLASSPATH, youll be able to compile and run basic Java programs. To compile and run the source-code package for this book (available at www.BruceEckel.com), however, you will need to add the base directory of the books code tree to your CLASSPATH.
Collisions
What happens if two libraries are imported via * and they include the same names? For example, suppose a program does this:
import com.bruceeckel.simple.*;
import java.util.*;
Since java.util.* also contains a Vector class, this causes a potential collision. However, as long as you dont write the code that actually causes the collision, everything is OKthis is good, because otherwise you might end up doing a lot of typing to prevent collisions that would never happen.
The collision does occur if you now try to make a Vector:
Vector v = new Vector();
Which Vector class does this refer to? The compiler cant know, and the reader cant know either. So the compiler complains and forces you to be explicit. If I want the standard Java Vector, for example, I must say:
java.util.Vector v = new java.util.Vector();
Since this (along with the CLASSPATH) completely specifies the location of that Vector, theres no need for the import java.util.* statement unless Im using something else from java.util.