COMP101 - PACKAGES

CONTENTS

1.Overview
2.Creating uour own package
3.Example problem - numeric input class
3.1.Requirements
3.2.Analysis
3.3.Design
3.4.Implementation
3.5.Testing
4.Adding a new classpath
4.1.HP-UX UNIX
4.2.Windows NT
4.3.LINUX


1. OVERVIEW

When a largish program is to be written it is often advantageous to divide the program up into chunks (modules) and compile the parts separately. This option is particularly desirable when several programmers are jointly developing a large program. Such chunks of code are called packages in Java. Each package is stored in a directory (folder) which has the same name as the package. Thus a package called LocalPackages will be stored in a directory called LocalPackages.

We have already seen how we can import Java's standard API packages, such as the java.io package, into a program and then use the classes defined in this package. We can also write our own user-defined packages containing implementations of our own classes.



2. CREATING YOUR OWN PACKAGE

Thus a package is a collection of classes grouped together and stored in a directory in such a way that they can be used by any applications program that we might wish to create.

We will create a package called LocalPackages which contains a single class PackageExample. We will first create a directory LocalJavaPackages in which to place all our packages. We will then create the first class for our LocalPackages package, this is given in Table 1. Note the keyword package which tells the compiler that this class will belong to a package (LocalPackages in tghis case).

// PACKAGE EXAMPLE
// Frans Coenen
// Wednesday 21 July 1999
// The University of Liverpool, UK   

package LocalPackages;

public class PackageExample {
    
    public void doit() {
    	System.out.println("Hooray I have successfully written a package!");
	}
    }

Table 1: Source code for class to be include in LocalPackages package

If we compile the above using the -d option we can tell the compiler where to place the resulting class:

javac -d . PackageExample.java

Provided that the PackageExample.java source file is contained in our LocalPackages directory this will cause a directory LocalPackages to be created in which we will find the class file PackageExample.java.

To use the classes in a package we must include an import statement in our source code of the form:

import LocalPackages.PackageExample;

However, how does the Java compiler know where to look for the classes contained in the LocalPackages.PackageExample package? The answer is that is has no idea, therefore we must tell it.

We can do this by including the pathname in our compile and execute commands. For example given the application presented in Table 2 we would compile this as follows:

javac -classpath ~frans/LocalJavaPackages/:. PackageExampleApp.java 
// PACKAGE EXAMPLE APPLICATION
// Frans Coenen
// Wednesday 21 July 1999
// The University of Liverpool, UK   

import LocalPackages.PackageExample;

class PackageExampleApp {

    public static void main(String[] arg) {
	
        // create instance of class Package Example
    
        PackageExample newObj = new PackageExample();
                                              
        // Call extended bigest
    
	newObj.doit();
    	}
    }

Table 2: Source code for application programme

To run the programme we would type:

java -classpath ~/LocalJavaPackages/:. PackageExampleApp

To produce:

Hooray I have successfully written a package!  

Note that it may be convenient to write two "shell" scripts to facilitate the above compilation and execution.



3. EXAMPLE PROBLEM - NUMERIC INPUT CLASS


3.1 Requirements

In the examples given on these WWW pagesso we have included a declaration of the form:

public  static InputStreamReader input = new InputStreamReader(System.in);
public  static BufferedReader    keyboardInput = new BufferedReader(input);

or an abbreviated version of this:

public  static BufferedReader    keyboardInput = new 
		BufferedReader(new InputStreamReader(System.in));

to facilitate input. In some examples we have also included code to check input and provide an "error recovery" mechanism. This has been implemented using a continuous loop which is only terminated on entry of appropriate input. The code used is fairly standard. Thus to avoid writing the same code again and again it would make sense to create a package, lets call it csio (Computer Science Input Output), which contains classes to handle input for various common primitive data types.

In this example problem we are therefore required to write a class that will facilitate the input of doubles, integers, and natural and positive numbers. At the same time the code should allow the user to specify particular limits if desired, where such limits are not prescribed default settings should be used.


3.2 Analysis

The different "types" of numbers we wish to input fall naturally into a class hierarchy of the form shown in Figure 1. Note that the input and keyboardInput objects are defined in the top class and are then inheritance by sub-classes. The inputInteger and inputDouble classes both have maximum and minimum data fields (of type integer in the first case, and of type double in the second). Both classes also have a read method.

CLASS DIAGRAM FOR NUMERIC INPUT PROBLEM

Figure 1: Class diagram for numeric input problem

All of the sub-classes have two constructors. One where a default maximum and minimum is defined and one where the user supplies these values. Note that by definition the minimum value for a natural number is always assumed to be 0, while that for a positive number is assumed to be 1.


3.3 Design

From Figure 1 the design comprises five classes, NumericInput, IntegerInput, DoubleInput, NaturalInput and PositiveInput of which the first has no methods (other than a default constructor created automatically by the Java compiler). The methods associated with the remaining classes (mostly constructors) are outlined below.


3.3.1 DoubleInput class

1. DoubleInput/0: constructor to create an instance of the class DoubleInput using the default maximum and minimum. This constructor has no code associated with it, but must be included so that is can be automatically called from a sub-class constructor. (Note that the forward slash zero, /0 used here indicates that the method has zero arguments. The number of arguments that a method has is known as its arity.)

2. DoubleInput/2: second constructor to create an instance of the class DoubleInput using the user supplied maximum and minimum which override the default values. (Note that this has an arity of 2.)

DoubleInput/2
IdentifierTypeUsage
newMin doubleFormal parameter
newMax doubleFormal parameter
minDoubledoubleInstance variable field
maxDoubledoubleInstance variable field

3. readDouble/0: method to get a double from the keyboard and check this it is within the desired limits. If so return the double. Otherwise output an error message and repeat so that the user has another chance to input the required number.

readDouble
IdentifierTypeUsage
inputDoubledoubleLocal variable
minDouble doubleInstance variable field
maxDouble doubleInstance variable field

4. getMin/0: access and returns the minDouble field value for a double input.

5. getMax/0: access and returns the maxDouble field value for a double input.


3.3.2 IntegerInput class

1. IntegerInput/0: constructor to create an instance of the class IntegerInput using the default maximum and minimum.

2. IntegerInput/2: second constructor to create an instance of the class IntegerInput using the user supplied maximum and minimum which override the default values.

IntegerInput/2
IdentifierTypeUsage
newMin intFormal parameter
newMax intFormal parameter
minIntegerintInstance variable field
maxIntegerintInstance variable field

3. readInt/0: method to get an integer from the keyboard and check this it is within the desired limits. If so return the integer. Otherwise output an error message and repeat so that the user has another chance to input the required number. This method is inherited by the NaturalInput and PositiveInput sub-classes.

readInt/0
IdentifierTypeUsage
inputIntegerintLocal variable
minInteger intInstance variable field
maxInteger intInstance variable field

4. getMin/0: access and returns the minInteger field value for an integer input.

5. getMax/0: access and returns the maxInteger field value for an integer input.


3.3.3 NaturalInput class

1. NaturalInput/0: constructor to create an instance of the class NaturalInput using the default maximum and setting the minimum to 0.

NaturalInput/0
IdentifierTypeUsage
minIntegerintInstance variable field

2. NaturalInput/1: second constructor to create an instance of the class NaturalInput using a user supplied maximum (minimum still automatically set to 0).

NaturalInput/1
IdentifierTypeUsage
newMax intFormal parameter
minIntegerintInstance variable field
maxIntegerintInstance variable field

3.3.4 PositiveInput class

1. PositiveInput/0: constructor to create an instance of the class PositiveInput using the default maximum and setting the minimum to 1.

PositiveInput/0
IdentifierTypeUsage
minIntegerintInstance variable field

2. PositiveInput/1: second constructor to create an instance of the class PositiveInput using a user supplied maximum (minimum still automatically set to 1). Note that we do not need to include an explicit super method to invoke the parent class constructor as we do not wish to pass any arguments to this parent constructor; the parent class constructor will be invoked automatically.

PositiveInput/1
IdentifierTypeUsage
newMax intFormal parameter
minIntegerintInstance variable field
maxIntegerintInstance variable field
Most of the above methods are straight forward involving only assignment statements. However, the readDouble and readInteger methods are slightly more involved. Nassi-Shneiderman charts for these two methods are presented in Figure 2.

NASSI-SHNEIDERMAN CHARTS FOR NUMERIC INPUT METHODS

Figure 2: Nassi Shneidserman charts for readDouble and readInteger methods


3.4 Implementation

Each public class must be contained in a separate source file. Thus to implement the above we need five separate files all contained in the LocalJavaPackages directory. The implementation for each class is given in Tables 3 to 7 inclusive.

   
// NUMERIC INPUT
// Frans Coenen
// Wednesday 19 May 1999
// The University of Liverpool, UK   

package csio;

import java.io.*;

/***************************************/
/*                                     */
/*      NUMERIC INPUT CLASS            */
/*                                     */
/***************************************/

public class NumericInput {

   // ------------------- FIELDS ------------------------ 
     
   // Create BufferedReader class instance

   protected  static InputStreamReader input = 
   			new InputStreamReader(System.in);
   protected  static BufferedReader keyboardInput = 
   			new BufferedReader(input);
   }

Table 3: Source code for NumericInput class

   
// DOUBLE INPUT 
// Frans Coenen
// Wednesday 19 May 1999
// The University of Liverpool, UK   

package csio;
import java.io.*;

/**************************************/
/*                                    */
/*      DOUBLE INPUT CLASS            */
/*                                    */ 
/**************************************/

public class DoubleInput extends NumericInput {

   // ------------------- FIELDS ------------------------ 

   protected double maxDouble = Double.MAX_VALUE; 
   protected double minDouble = Double.MIN_VALUE;
	
   // ------------------ METHODS ------------------------  
   
   /* Constructors */
   
   public DoubleInput() {
     }
	
   public DoubleInput(double newMin, double newMax) {
	minDouble = newMin;
	maxDouble = newMax;
     }

   /* Read integer */

   public double readDouble() throws IOException {
	double inputDouble;

	// Read doubles from keyboard till appropriate double obtained.
	   
	do {
	   inputDouble = new Double(keyboardInput.readLine()).doubleValue();
	   if (inputDouble < minDouble || inputDouble > maxDouble) {
	     System.out.println("INPUT ERROR: input must be a double " +
			"between " + minDouble + " and " + maxDouble);
		System.out.println("Try again! ");
	     }
	   else break;
	   } while (true);

	// Return Double

	return(inputDouble);
	}
   
   /* Get minimum */
   
   public double getMin() {
   	return(minDouble);
	}

   /* Get minimum */
   
   public double getMax() {
   	return(maxDouble);
	}		
   }

Table 4: Source code for DoubleInput class

   
// INTEGER INPUT 
// Frans Coenen
// Wednesday 19 May 1999
// The University of Liverpool, UK   

package csio;

import java.io.*;

/***************************************/
/*                                     */
/*      INTEGER INPUT CLASS            */
/*                                     */
/***************************************/

public class IntegerInput extends NumericInput {

   // ------------------- FIELDS ------------------------ 

   protected int maxInteger = Integer.MAX_VALUE; 
   protected int minInteger = Integer.MIN_VALUE;
	
   // ------------------ METHODS ------------------------  
   
   /* Constructors */
   
   public IntegerInput() {
     }
	
   public IntegerInput(int newMin, int newMax) {
	minInteger = newMin;
	maxInteger = newMax;
     }

   /* Read integer */

   public int readInt() throws IOException {
	int inputInteger;

	// Read integers from keyboard till appropriate integer obtained.
	   
	do {
	   inputInteger = new Integer(keyboardInput.readLine()).intValue();
	   if (inputInteger < minInteger || inputInteger > maxInteger) {
	     System.out.println("INPUT ERROR: input must be an integer " +
			"between " + minInteger + " and " + maxInteger);
		System.out.println("Try again! ");
	     }
	   else break;
	   } while (true);

	// Return integer

	return(inputInteger);
	}	
   
   /* Get minimum */
   
   public int getMin() {
   	return(minInteger);
	}

   /* Get minimum */
   
   public int getMax() {
   	return(maxInteger);
	}
   }

Table 5: Source code for IntegerInput class

   
// NATURAL INPUT
// Frans Coenen
// Wednesday 19 May 1999
// The University of Liverpool, UK   

package csio;

import java.io.*;

/***************************************/
/*                                     */
/*      NATURAL INPUT CLASS            */
/*                                     */
/***************************************/

public class NaturalInput extends IntegerInput {

   /* Constructors */

   public NaturalInput() {
	minInteger = 0;
	}

   public NaturalInput(int maxValue) {
	minInteger = 0;
	maxInteger = maxValue;
	}
   }

Table 6: Source code for NaturalInput class

   
// POSITIVE INPUT 
// Frans Coenen
// Wednesday 19 May 1999
// The University of Liverpool, UK   

package csio;

import java.io.*;
   
/****************************************/
/*                                      */
/*      POSITIVE INPUT CLASS            */
/*                                      */
/****************************************/

public class PositiveInput extends IntegerInput {

   /* Constructors */

   public PositiveInput() {
	minInteger = 1;
	}

   public PositiveInput(int maxValue) {
	minInteger = 1;
	maxInteger = maxValue;
	}
   }

Table 7: Source code for class

Once compiled each of the resulting class files will be contained in the directory csio. We now have a package called csio that supports numeric input!


4.5 Testing

To test our package we can write a simple test harness such as that given in Table 9. Note that we have imported the csio package using an import statement of the form import csio.*.

// NUMERIC INPUT TEST APPLICATION
// Frans Coenen
// Wednesday 19 May 1999
// The University of Liverpool, UK   

import java.io.*;
import csio.*;

class NumericInputTestApp {

   /* Main method */
   
   public static void main(String[] args) throws IOException {
   	DoubleInput newDouble;
     IntegerInput newInteger;
	NaturalInput newNatural;
	PositiveInput newPositive;
	double real1, real2;
	int num1, num2;
	
	// The newDouble instance has the default range.
	
	newDouble = new DoubleInput(); 
	System.out.println("Input two Doubles in the range of " + 
			newDouble.getMin() + " to " + newDouble.getMax());
	real1 = newDouble.readDouble();
	real2 = newDouble.readDouble();
	System.out.println("Doubles with default range (" +
			newDouble.getMin() + ".." + newDouble.getMax() + 
			"): " + real1 + " " + real2 + "\n");
	
	// The newDouble instance has a given max and min
	
	newDouble = new DoubleInput(-50.0,100.0); 
	System.out.println("Input two Doubles in the range of " + 
			newDouble.getMin() + " to " + newDouble.getMax());
	real1 = newDouble.readDouble();
	real2 = newDouble.readDouble();
	System.out.println("Doubles with given range (" +
			newDouble.getMin() + ".." + newDouble.getMax() + 
			"): " + real1 + " " + real2 + "\n");
			
	// The newInteger instance has the default range.
	
	newInteger = new IntegerInput(); 
	System.out.println("Input two integers in the range of " + 
			newInteger.getMin() + " to " + newInteger.getMax());
	num1 = newInteger.readInt();
	num2 = newInteger.readInt();
	System.out.println("Integers with default range (" +
			newInteger.getMin() + ".." + newInteger.getMax() + 
			"): " + num1 + " " + num2 + "\n");
	
	// The newInteger instance has a given max and min
	
	newInteger = new IntegerInput(-50,100); 
	System.out.println("Input two integers in the range of " + 
			newInteger.getMin() + " to " + newInteger.getMax());
	num1 = newInteger.readInt();
	num2 = newInteger.readInt();
	System.out.println("Integers with given range (" +
			newInteger.getMin() + ".." + newInteger.getMax() + 
			"): " + num1 + " " + num2 + "\n");
	
	// The newNatural instance has the default range.
	
	newNatural = new NaturalInput(); 
	System.out.println("Input two natural numbers in the range of " + 
			newNatural.getMin() + " to " + newNatural.getMax());
	num1 = newNatural.readInt();
	num2 = newNatural.readInt();
	System.out.println("Natural numbers with default range (" +
			newNatural.getMin() + ".." + newNatural.getMax() + 
			"): " + num1 + " " + num2 + "\n");
	
	// The newNatural instance has a given max
	
	newNatural = new NaturalInput(100); 
	System.out.println("Input two natural numbers in the range of " + 
			newNatural.getMin() + " to " + newNatural.getMax());
	num1 = newNatural.readInt();
	num2 = newNatural.readInt();
	System.out.println("natural numbers with given range (" +
			newNatural.getMin() + ".." + newNatural.getMax() + 
			"): " + num1 + " " + num2 + "\n");
	
	// The newPoitive instance has the default range.
	
	newPositive = new PositiveInput(); 
	System.out.println("Input two positive numbers in the range of " + 
			newPositive.getMin() + " to " + newPositive.getMax());
	num1 = newPositive.readInt();
	num2 = newPositive.readInt();
	System.out.println("Positive numbers with default range (" +
			newPositive.getMin() + ".." + newPositive.getMax() + 
			"): " + num1 + " " + num2 + "\n");
	
	// The newPositive instance has a given max
	
	newPositive = new PositiveInput(100); 
	System.out.println("Input two positive numbers in the range of " + 
			newPositive.getMin() + " to " + newPositive.getMax());
	num1 = newPositive.readInt();
	num2 = newPositive.readInt();
	System.out.println("Positive number with given range (" +
			newPositive.getMin() + ".." + newPositive.getMax() + 
			"): " + num1 + " " + num2 + "\n");
   	}	
   }

Table 8: Test code for numeric input program



4. ADDING A NEW CLASSPATH

WARNING: THIS WAS WRITTEN IN JUNE 1999 AND MANY NO LONGER REFLECT CURRENT SYSTEMS>

An alternative (more sophisticated way) of telling Java wherte to finf packages is by assigning an appropriate value to a kind of data item known as an environmental variable. The particular environmental variable that we are interested in, in the context of Java packages, is called CLASSPATH. This contains the directory paths indicating the places where the Java compiler should look when searching for packages. This variable will already be set with a number of directory paths indicate where the Java API packages are to be found. Thus when the Java compiler encounters a statement of the form:

import LocalPackages.PackageExample;

It looks for the package LocalPackages.PackageExample according to the paths contained in the CLASSPATH environmental variable in the order that that are presented in this variable. If the Java compiler cannot find an appropriate sub-directory called PackageExamples a compiler error will result.

How you go about changing your CLASSPATH environmental variable depends on the operating system you are using. Details for HP-UX UNIX, Windows NT and LINUX are presented in the following sub-sections

4.1. HP-UX UNIX

To adjust the CLASSPATH environmental variable in UNIX we must add some appropriate statements in a file known as the "start up" file or "login script" --- a file that is always invoked when you login. This start up file is an invisible dot (.) file; these are files whose name commences with a dot and which are not normally displayed by a ls command --- hence the tag "invisible" (you can list them by doing a ls .*). The name of this start-up file will depend on what UNIX shell you are using. A selection of common shells with the name of there associated start up (login script) files is given in Table 9. To find out which shell you are in you can type the command echo $SHELL.

Shell nameLogin script filename
Bourne, Korn, Posix.profile
C.login
PAM.environ
Bash.bashrc

Table 9: Login script dot file names for some common UNIX/LINUX shells

Within the Department of Computer Science at the University of Liverpool the UNIX system is configured so that the Korn shell is the default shell. The process of changing an evironmental variable varies (slightly) from shell to shell. The following discussion assumes that you are using the Korn shell, in which case you need to edit your .profile. When you have the file in an edit window you will see the contents of your login script. Scroll to the bottom of this script and add the following line:

CLASSPATH=~/LocalJavaPackages
export CLASSPATH 

After editing the login script you need to logout and log back in again to ensure that the login script is executed correctly. If you now type the UNIX command:

echo $CLASSPATH

You will now see something like:

/HOME/frans/localJavaUtilities

This now means that the Java compiler will now also look in the directory /HOME/frans/localJavaUtilities when looking for packages. (If you wish to include more than one classpath you will have seperate each with a colon.)


4.2. WINDOWS NT

Using Windows NT do the following:

  1. Call up a "DOS Prompt" window.
  2. Type set C (List the values of all the environmental variables whose identifier begins with the character C).
  3. In the same window type:
    setx CLASSPATH %CLASSPATH%;H:\LocalJavaPackages
    
  4. If you do set C now you will not see any apparent change. However if you close the current DOS prompt window and call up a new one and then type set C you will see the effect.

The CLASSPATH environmental variable will keep this value (even when you log of and log on again) until the next time it is changed (if ever).


4.3. LINUX

Linux systems typically run under the Bash shell and thus you will have to edit the .bashrc file. Using the Bash shell the CLASSPATH environmental variable already contains the paths to the Java API packages. You can "echo" the contents of the CLASSPATH variable to the screen as follows:

echo $CLASSPATH 

you will see something like:

.:/usr/local/jdk1.1.7/lib:/usr/local/jdk1.1.7/lib/classes.zip  

In this case we have three paths each separated by a ':' character. The first is '.' and means "the current directory". The other two:

/usr/local/jdk1.1.7/lib

and

/usr/local/jdk1.1.7/lib/classes.zip  

To adjust the CLASSPATH environmental variable under LINUX (as in UNIX) we must add some appropriate statements in our start-up file, i.e. the .basnrc file when using the Bash shell (see Table 9). Simply add the following to the end of the login script.

CLASSPATH=.:~/LocalJavaPackages:$CLASSPATH
export CLASSPATH 

As with UNIX, after editing the login script, you need to logout and log back in again to ensure that the login script is executed correctly. If you again "echo" the path you will now see something like:

/HOME/frans/localJavaUtilities:.:/usr/local/jdk1.1.7/lib:
/usr/local/jdk1.1.7/lib/classes.zip  



Created and maintained by Frans Coenen. Last updated 04 September 2002