Name Spaces and Reusability

A major problem when developing reusable code is that of name conflicts.

Vendor B might develop a library of classes, while Vendor M might develop another library of classes. Customer C wants to use both libraries, but discovers that a number of class names have been duplicated across the two libraries.

What to do?

Qualified Names

A solution is to organize code into named packages.

In C++, the feature equivalent to Java’s packages is C++ namespaces.

Then, when class names conflict among different code libraries, we can explicitly place the code in separate packages, and qualify the name references with the appropriate package name.

The namespace represented is arranged hierarchically in terms of packages and sub-packages of a package, etc. For example, here is a reference to a method in the Java class library:

java.lang.String.substring()

where:

  • java is the package name
  • lang is the sub-package name
  • String is the class name
  • substring is the method name

And here is a reference to a class library method for a (mythical) vendor, Aardvark:

COM.Aardvark.eng.gui.Menu.add(String s)

where:

  • COM.Aardvark is from the vendor’s Internet domain name, aardvark.com
  • eng.gui is the vendor’s internal naming convention:
    • eng — Engineering
    • gui — Graphical User Interface development
  • Menu is the class name
  • add is the method name within that class

Note that the convention is to use the organization’s Internet domain names in reverse order. For example, common names might look like:

COM.Microsoft...
COM.Oracle...
COM.Borland...
COM.Symantec...

However, lots of vendors omit the COM., or just use their company name as the first name.

Also, some vendors use com, rather than COM.

The import Statement

It’s a royal pain to have to fully qualify every class name in your program.

So the Java folks added the import statement as a convenience:

import java.util.Hashtable; // import just HashTable

or:

import java.util.*; // import all classes in java.util

which allows the Java compiler to make a name accessible through an abbreviated name — the class name itself (in this case Hashtable).

Note: I try to discourage the use of the ‘*‘ method of importing, because I consider it bad — often sloppy/lazy — software engineering practice.  Please don’t use it, at least in my course!

If you wish, you can use a mix of import statements and fully qualified references.

If two packages imported in this way contain classes with the same name, you cannot use either of those classes without using the fully qualified name for each.

Note:  Remember:

  • There may be any number of import statements in a Java program.
  • They must follow any package statement in the source
  • They must precede the first class definition (or interface definition — more later) in the file.

Static imports

Starting in Java 5, the import statement was enhanced to allow the importing of static methods and fields from a class.

For example:

import static java.lang.System.exit;
import static java.lang.System.out;
import static java.lang.Math.sqrt;
import static java.lang.Math.PI;

public class StaticImportTest
{
  public static void main(String[] args)
  {
    System.out.println("Using System.out.println(...)");
    out.println("Using out.println(...)");

    out.println("The square root of 64 is " + Math.sqrt(64));
    out.println("The square root of 91 is " + sqrt(91));

    out.println("The value of PI is " + PI);
  }
}

which, when run in a Java Virtual Machine supporting Java 5 or above, produces the following output:

Using System.out.println(...)
Using out.println(...)
The square root of 64 is 8.0
The square root of 91 is 9.539392014169456
The value of PI is 3.141592653589793

In a JVM supporting an earlier version of Java than 5, the program will produce compilation errors.

Automatic import

PackageĀ java.lang

The following import statement is implicit in every Java program:

import java.lang.*; // import all classes in java.lang

so, you never have to add that particular import statement to your program source.

The following public types are defined in java.lang (this is not a complete list, and is subject to augmentation in every release of Java):

AbstractMethodError
ArithmeticException
ArrayStoreException
Boolean
Character
Class
ClassCastException
ClassCircularityError
ClassFormatError
ClassLoader
ClassNotFoundException
CloneNotSupportedException
Cloneable
Compiler
Double
Error
Exception
ExceptionInInitializerError
Float
IllegalAccessError
IllegalAccessException
IllegalArgumentException
IllegalMonitorStateException
IllegalThreadStateException
IncompatibleClassChangeError
IndexOutOfBoundsException
InstantiationError
InstantiationException
Integer
InternalError
InterruptedException
LinkageError
Long
Math
NegativeArraySizeException
NoClassDefFoundError
NoSuchFieldError
NoSuchMethodError
NullPointerException
Number
NumberFormatException
Object
OutOfMemoryError
Process
Runnable
Runtime
RuntimeException
SecurityException
SecurityManager
StackOverflowError
String
StringBuffer
System
Thread
ThreadDeath
ThreadGroup
Throwable
UnknownError
UnsatisfiedLinkError
VerifyError
VirtualMachineError

The Default Package

Another package that is implicitly and automatically imported in every Java program is the default package.  The default package is the package which contains every Java class that does not have an explicit package definition.

Note: I strongly discourage the use of the default package for other than truly trivial (i.e. not intended for any serious application) Java code.

The Current Package

Finally, one more package which is automatically imported is the package specified for the current Java class.

In other words, if you place your class Fontleroy into the little.lord package, then, when the Java compiler compiles your class, it implicitly does the following import:

import little.lord.*;

The package Statement

When you wish to create a class that is to belong to a named Java package, you must place a package statement as the first statement (i.e. first text other than comments and whitespace) in the class’s Java source code file.

Here is a package statement:

package COM.Aardvark.eng.gui;

where the package name must be fully qualified — that is, it must include the top-level package name and all intervening sub-package names .

A compilation unit that has no package statement is part of an unnamed package — the default package.

  • A Java system is required to support at least one unnamed package
  • It may support more than one, but is not required to do so.
  • Unnamed packages are a convenience feature when developing simple or temporary development, or when just starting to learn Java.
  • Unnamed packages are strongly discouraged in real-world Java code.

Note: From this point on, I will expect you to use only named packages in your Java code!

Compilation Units

A Java compilation unit is defined in the Java Language Specification as:

CompilationUnit :
   PackageDeclarationopt ImportDeclarationsopt TypeDeclarationsopt
TypeDeclarations :
   TypeDeclaration
   TypeDeclarations TypeDeclaration
TypeDeclaration :
   ClassDeclaration
   InterfaceDeclaration

Notice the subscript “opt”, which means optional.

The above means that a Java compilation unit consists of:

  • Optionally, a package declaration, followed by
  • Optionally, a set of one or more import declarations, followed by
  • Optionally, a set of one or more type declarations, each type declaration may comprise:
    • A class declaration, or 
    • An interface declaration (more about interfaces, soon)

Host Support for Packages

Each Java host determines:

  • How packages, compilation units, and sub-packages are created and stored,
  • Which top-level package names are in scope in a particular compilation, and
  • Which packages are accessible

The packages may be stored:

  • In a local file system, or:
  • In a distributed file system, or:
  • In some form of database

On Microsoft Windows and on Unix systems, they are typically stored in a directory hierarchy that matches the naming hierarchy. This typically means that a package is a directory containing .class files and/or subdirectories. The subdirectories are sub-packages of that package.

Note: Remember:

  • Package and class names are case-sensitive!
  • Somehow, the package directory must be accessible through the CLASSPATH environment variable.

Type Definitions

Within a compilation unit you may have several TypeDeclarations. However, note the following:From “The Java Language Specification”, by James Gosling, Bill Joy and Guy Steele, Addison-Wesley:

“When Java packages are stored in the file system, the host system may choose to enforce the restriction that it is a compile-time error if a type is not found in a file under a name composed of the type name plus an extension (such as .java or .jav) if either of the following is true:

  • The type is referred to by code in other compilation units of the package in which the type is declared, or:
  • The type is declared public (and therefore is potentially accessible from code in other packages).

This restriction implies that there must be at most one such type per compilation unit. This restriction makes it easy for a Java compiler and Java Virtual Machine to find a named class within a package. For example, the code for a public type wet.sprocket.Toad would be found in a file Toad.java in the directory wet/sprocket. The corresponding object code would be found in the file Toad.class in the same directory.

When Java packages are stored in a database, the host system need not enforce such restrictions.

In practice, many Java programmers choose to put each class or interface type in its own compilation unit, whether or not it is public, or is referred to by code in other compilation units.”

Access Control

Access to Package Contents

A package is accessible if the corresponding files and directories are accessible.

All classes (and interfaces) in a package are accessible to all other classes (and interfaces) in the same package.

A class declared public in one package is accessible from within another package. A non-public class is not accessible from outside of its package.

Members of a class are accessible from a different class within the same package, as long as they are not declared private.

private members are accessible only within their own class.

All members of a class are accessible from within that class.

Visibility Modifiers

The keywords public and private (and protected — later) are visibility modifiers, which have the following effect:

private member of a class is visible only in methods defined within that class.

public member of a class is visible to all class methods.

If a member is declared with no visibility modifiers, then it has default package visibility, and is visible only within the class that defines it and within classes defined in the same package. (This is analogous to the friend concept in C++ — all classes within a package are ‘friendly’ to each other.)

To summarize:


MemberVisibility
Accessible to:publicpackageprivate
Same classyesyesyes
Class in same Packageyesyesno
Subclass in different packageyesnono
Non-subclass, different packageyesnono

Here are some simple rules to help you choose which visibility modifiers to use, when:

  • Use public only for methods and constants that form part of the public interface (sometimes called the API) of the class.
  • Use the default package visibility for fields and methods that you want to be hidden from outside of the package, but which you want cooperating (‘friend’) classes within the package to have access to.
  • Use private for fields and methods that are only used inside the class and should be hidden from everywhere else

Note: Try to make all class/instance data (fields) private, except for static final fields (i.e. class constants).