PackagesS2C Home « Packages

The rest of this section is about parts of the Java API, which unlike java.lang, are not implicitly imported into our programs. Before we look at these parts of the java API, we need to take a closer look at how Java stores predefined classes into namespaces, which Java calls packages, and how we can import these packages into our programs.

In Java we can keep libraries of related classes together using a package and this is in essence what the Java language is, a collection of packaged libraries. There are two major benefits to the package approach adopted by Java.

  • A package provides the apparatus for us to group related classes together under the same umbrella.
    1. All the example classes we have written on the site thus far, have all used the default namespace. This is fine for small simple classes where we are trying to teach a topic. Imagine a large system with hundreds of classes. We need a way to uniquely identify the classes and Java doesn't allow us to have two top-level classes with the same name, within the same namespace. By using packaging we can partition the namespace to alleviate naming conflicts.
    2. Within any reasonable sized system we will have classes that relate to different aspects of said system, such as the Model View Controller paradigm. Packaging allows us to separate concerns into areas such as a Model subpackage, a View subpackage and so on. This makes the whole development process easier and more manageable.
  • A package is part of the Java mechanism we use to enforce Encapsulation.
    1. By not marking members within a package with an access modifier, we are saying that these members are package-private and can only be accessed from within this package.
    2. By marking members with the protected access modifier, we are saying that these members can only be accessed from within this package or from a subclass outside the package.

Using the package KeywordTop

Every class written in Java exists within a package. When no package statements are present within a class, such as all the example classes we have written on the site thus far, then the default package is used. The default package has no name and is the reason we have been happily coding away without ever having to worry about packages. When we want to create a package for our files we do so using the package statement.

The following table shows usage of a single package statement and an example of a multiple hierarchy package statement.

Package Form Example Description
Single package
package pkg;package A;This file is part of package A.
Multiple package hierarchy
package pkg.subPkg1.subPkg2...subPkgN;package A.B.C;This file is part of Package C, which is a subpackage of B, which is a subpackage of A.

Java uses the underlying file system to manage packages, where each class within a package must be stored in a directory name that exactly matches the package name. Like all identifiers in Java, packages are case sensitive, so you need to be aware of this when naming your directories and packages.

Creating A Second Folder For Our API Contents Source Files

Because we are doing a lesson on packages we need another folder to highlight some of the topics covered in this lesson:

double click My Computer icon

double click C:\ drive (or whatever your local drive is)

right click the mouse in the window

from the drop down menu Select New

click the Folder option and call the folder _APIContents2 and press enter.


To illustrate the points covered in this lesson so far, we will write class and a test class that use different packages:


/*
  Our package statement is the first entry in a source file
*/
package _APIContents; 
 
class ATestPackage {
    String firstName;
    String lastName;

    ATestPackage(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        printName(firstName, lastName);  
    }

    private void printName(String firstName, String lastName) {
        System.out.println("First name of: " + firstName);
        System.out.println("Last name of: " + lastName);
    }
}


Save and compile the ATestPackage class in directory   c:\_APIContents in the usual way. Now we need to write a test class to make sure the ATestPackage class works as intended.


/*
  Test the ATestPackage class 
*/
package _APIContents2; 

public class TestATestPackage {
    public static void main(String[] args) {
        _APIContents.ATestPackage a  = new _APIContents.ATestPackage("bim", "bam");
    }
}

A point to note about the above code thats slightly different from what we have seen before is that we have to qualify the TestATestPackage class with the _APIContents package it resides in to use it. Save and compile the TestATestPackage test class in directory   c:\_APIContents2 in the usual way (remember to change to the   c:\_APIContents2 directory!).

run test a package

The above screenshot shows the output of compiling the TestATestPackage class. The compiler is saying the _APIContents package doesn't exist, but we know it does as we just created the folder for it. As mentioned above packages need to replicate the underlying file system exactly which in our case they do. But how does Java know where to look for the _APIContents package?? Well by default, the Java compiler will look for packages it needs in subdirectories of the current working directory. In our case when we try to compile the TestATestPackage class we are in the   c:\_APIContents2 directory. So the Java compiler looks in any subdirectories it can find for the _APIContents package. There aren't any so the compiler throws an error. We could have course set a classpath for this package as discussed in Setting A Classpath For The Java Compiler and it would have found the package.

We can use the -classpath option, (shorthand version is -cp), to tell the compiler where to find any dependencies we need to compile our TestATestPackage test class. So lets see an example of doing just this. Save and compile the TestATestPackage test class in directory   c:\_APIContents2 using the following command:


javac -cp c:\ TestATestPackage.java

What the above command is saying is compile the TestATestPackage class and look for any dependencies in subdirectories of c:\

run test a package2

The above screenshot shows the output of compiling the TestATestPackage class. The compiler can now find the APIContents package but won't allow us access to the ATestPackage class and contructor as these have no access modifier, and so the ATestPackage class and its constructor are package-private. So we need to make the ATestPackage class and its constructor public so we can access them from outside their package:


/*
  Our package statement is the first entry in a source file
*/
package _APIContents; 
 
public class ATestPackage {
    String firstName;
    String lastName;

    public ATestPackage(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        printName(firstName, lastName);  
    }

    private void printName(String firstName, String lastName) {
        System.out.println("First name of: " + firstName);
        System.out.println("Last name of: " + lastName);
    }
}

Recode the ATestPackage class in directory   c:\_APIContents, as above to include public modifers for the class and contructor, and then save and compile in the usual way.

Now we need to go back to the   c:\_APIContents2 directory. Save and compile using the -cp option as above and this time we should get a clean compile. Now we can run the TestATestPackage test class in the usual way.

run test a package3

The above screenshot shows the output of running the TestATestPackage test class. This time we get a NoClassDefFoundError runtime exception as the java intepreter can't find our package/bitcode. We also have to let the intepreter know where our package is and the following typed on the command line will do this:


java -cp c:\ _APIContents2.TestATestPackage

What the above command is saying is run the TestATestPackage class from package _APIContents2 which is within a subdirectory of the c:\ drive. Notice how we use dot notation to qualify the TestATestPackage class within the _APIContents2 package, just as you would use it within a java class.

run test a package4

The above screenshot shows the output of running the TestATestPackage class. The intereter can now find the bitcode and runs and produces a couple of lines of output.

Using the import KeywordTop

In the preceding part of this lesson we saw how we had to qualify the TestATestPackage class with the _APIContents package it resides in to use it. Following is the line of code we used to do this


_APIContents.ATestPackage a  = new _APIContents.ATestPackage("bim", "bam");

Having to qualify a class like this means more typing and it also makes the code harder to read. Luckily for us, Java allows us to import parts of a package, or even the whole package if required, and we do this using the import keyword.

The following table shows how to import a single class from a package and all classes from a package using the import statement.

Import Form Example Description
Single class import
import pkg.class;import java.rmi.Remote;Import the Remote class from java.rmi
Multiple class import
import pkg.subPkg1.subPkg2...subPkgN;import java.rmi.*;Import all java.rmi classes

The following code amendments to the TestATestPackage class shows how we can use the import statement:


package _APIContents2; 
/*
  here we import the ATestPackage class of the _APIContents package
*/
import _APIContents.ATestPackage; 

public class TestATestPackage {
    public static void main(String[] args) {
        // We no longer need to qualify the ATestPackage class to use it
        ATestPackage a  = new ATestPackage("bim", "bam");
    }
}

Save, compile and run the TestATestPackage class using the following commands, as we did above:


javac -cp c:\ TestATestPackage.java
java -cp c:\ _APIContents2.TestATestPackage

run test a package5

The above screenshot shows the output of running the TestATestPackage class after using the import keyword. The results are the same as before with more readable code.

Although this is a simple example and you may not see the real benefits of using the import keyword, imagine you were using lots of different classes in you files and each had to be qualified. Using the import keyword can really save you a lot of typing in this scenario and there is no performance hit when running your code, the compile will take a little longer, but won't even be noticeable.

Static ImportsTop

With the introduction of java a new feature became available when using the import statement which is commonly known as static imports. When using the import keyword followed by static we can import all the static members of a class or interface. This works in much the same way as non-static imports where the import means we don't have to qualify the member with package and subpackage information.

The following table shows how to import a single static member from a package and all static members from a package using the import static statement.

Import Static Form Example Description
Single static member import
import static pkg.staticMember;import static java.lang.Math.acos;Import the acos static member from java.lang.Math
Multiple static member import
import static pkg.allStaticMembers;import static java.lang.Math.*;Import all java.lang.Math static members

The following A class shows how we can use the import static statement:


/*
  Our Static import statement for the Math acos Member
*/
import static java.lang.Math.acos;
 
public class A {
    public static void main(String[] args) {
        double d = acos(0.5);  // Here we just have to use acos because of the static import
        System.out.println("The arc cosine of 0.5 is " + d);
    }
}

Save, compile and run the A class in directory _APIContents in the usual way.

run test import static

The above screenshot shows the output of running the A class after using the import static keywords. The results shows how we can use the unqualified static import of the java.lang.Math.acos member.

Lesson 3 Complete

We learnt how Java stores predefined classes into namespaces, which Java calls packages, and how we can import these packages into our programs.

What's Next?

It is now time to look at Java I/O in much more detail and we start three lessons on the subject with an overview of the various streams available in Java.

go to home page Homepage go to top of page Top