Software Design/Construction -- Week 9

Introduction

This week we'll look at packaging in Java.

Note that the links from this page are to handouts that will be distributed the night of class.  Only print out those handouts if you could not attend class.

Main topics this week:

Advanced Language Concepts Assignment Assigned
Midterm Review
Java Packages
Classpath
JAR Files
Next Week

Advanced Language Concepts Assignment Assigned

The next programming assignment is assigned this week, and is due week 12.  This assignment is a bit more straightforward than the others, and is to be done in Java.   You will essentially implement a binary search tree.  We will talk a bit in class about binary search trees for those of you who have not had Algorithm Analysis yet.   The full description of the assignment is in your student manual.

Note, there will be no interface provided by the instructor.  The interface described in the student manual is what you should use, after changing what is thrown by each method to exceptions you have created.

Midterm Review

We will review the midterm exam from last week.

Java Packages

We'll start out with topic that may be familiar.  You've probably read about packages while you were in CS II, but it was not required in CS II to understand packages.   In this class, you'll need to understand both how packages are used.

A package is a collection of Java classes that somehow belong together.  For example, the package java.io contains a bunch of Java classes related to input and output.  When you want to use one of the classes from the java.io package, you have three choices:

1) Everywhere in the code that the class name is used, prepend java.io to it.   For example, to use FileInputStream:

java.io.FileInputStream fs = new java.io.FileInputStream ("input.dat");

This approach results in quite a bit of typing.

2) At the top of the .java file where you use the class, provide an import statement that tells Java what classes in other packages you want to use.  For example:

import java.io.FileInputStream;

This then allows you to use FileInputStream as a class name alone, and Java will know that you mean the one from the java.io package.  This approach means having one import statement for every class you want to use from another package.

3) Use a wildcard in the import statement to say that you want access to all the class in a package.  For example:

import java.io.*;

You can now use any of the classes in the java.io package in your code. 

The exact method you use depends on your personal preference.  Most programmers tend toward either option 2 or 3.

You can create your own packages.  To place a class in a package. you must provide a package statement in the .java file (this is typically the first line of the file).   For example, to put class Foo into the package franklin.student.jay, add this line as the first line in the file Foo.java:

package franklin.student.jay;

Now, if you add a line like that to Foo.java, and compile it, it will compile fine.   But then when you try to run it using:

java Foo

You will get an exception, java.lang.NoClassDefFoundError.  This is because of the way that Java tries to find packages.

Classpath

The classpath is how Java finds packages.  You can picture all the Java packages as being a file system.  In the root of the file system are all the Java classes that are not in packages.  In subdirectories off the root are the first level package names.  For example, let's say that we have a file NoPackage.java that is not in a package, and a file Foo.java that is in the package franklin.student.jay.  We'll also throw in FileInputStream from java.io.  Our imaginary directory structure would look like this:

wpe2.jpg (2545 bytes)

Inside the root directory would be the file NoPackage.java, inside the jay directory would be the file Foo.java, and inside the io directory would be the file FileInputStream.java.

It is important to realize that this directory structure does not exist like this physically.  But this is how you can visualize the package structure in Java. 

Now it gets a bit more complicated.  Java needs a way to map the imaginary directory structure onto the real hard disk.  The way it does this is by using the classpath.

Java's classpath is a list of directories and .jar files.  For now, we'll just worry about the directories.  Here is an example classpath:

.:~/java:/opt/java_1.2/classes

The colon (:) is used in Unix classpaths to separate entries.  Note that the first entry is a single dot (.), meaning the directory you are in when you run the java command.  

Each of the directories in the classpath represents the root of the imaginary Java package directory structure. 

This is the key to understanding how classpaths work.  Each of the directories in the classpath is the root of the package structure.  Given our sample classpath above, a .java file without a package could be in either the current directory (.), in ~/java (a directory named java in your home directory), or in /opt/java_1.2/classes (presumably where the Java libraries are kept). 

The franklin.student package would be found by Java if it were in any one of three positions:

  1. ./franklin/student
  2. ~/java/franklin/student
  3. /opt/java_1.2/classes/franklin/student

In this way, using the classpath, you can combine directories in many different areas into a single imaginary package directory structure for Java to search. 

Now, the reason that running our Foo class did not work was because Foo is in the package franklin.student.jay.  Therefore, Foo.java must be in a directory structure off one of the classpath root directories.  Given our sample classpath above, Foo.java could be in any of these places:

  1. ./franklin/student/jay/Foo.java
  2. ~/java/franklin/student/jay/Foo.java
  3. /opt/java_1.2/classes/franklin/student/jay/Foo.java

So when we ran the command "java Foo" it was looking for a Foo in one of the root directories.  But our package statement said our Foo was in a package.  To run Foo when it is in the right package directory, we must use:

java franklin.student.jay.Foo

This tells Java the location of Foo in the package structure.  When you run that command, Java will look for the Foo class using each of the classpath entries as the root of a directory structure.  It will use the first Foo class it finds, and will give an error if it does not find one.

If the Java classpath does not include a directory you need, you can specify an additional directory on the command line.  For example, if Foo was not in any of the classpath directory structures, but was in ~/temp, then you would need to use the following command line:

java -classpath ~/temp franklin.student.jay.Foo

You can do the same thing when compiling, if needed:

javac -classpath ~/temp Foo.java

JAR Files

A very common way of distributing Java classes is to put them into a .jar file.  A .jar file compresses the .class files and provides a single file to distribute.  You may recall from CS II that the sample labs were provided as .jar files. 

A .jar file is nothing more than a compressed directory structure.  So when the classpath includes a .jar file, Java treats the directory structure in the .jar file as part of the package directory structure.  If you recall how you had to run the CS II sample solutions:

java -classpath Lab1.jar Lab1

Now that we've talked about packages, classpaths, and .jar files, you should understand what this is doing.  We're running a class called Lab1 that is not in any package.   We're saying that one of the places Java can look for this class is inside the Lab1.jar file.  Assuming that Lab1.class is inside the .jar file, it will be found and run.

The Java documentation contains information on using the jar utility, including command line flags and examples.  The documentation for jar at Sun's site is at http://java.sun.com/j2se/1.4.2/docs/tooldocs/solaris/jar.html.

The basic command for creating a jar file is:

jar -cf myfile.jar *.java

You can also use the jar command for viewing the contents of jar files or extracing files from a jar file, but it is usually more convenient to use a graphical utility that understands archives, like WinZip.

Next Week

Next week we'll look at templates in C++, and inner classes in Java.