The Java Language.............................................................................................................................................

USING THE EXAMPLE APPLETS..............................................................................................................................

LANGUAGE BASICS: A QUICK TOUR....................................................................................................................

Variables and Scope...................................................................................................................................................

Finality..........................................................................................................................................................................

C++ Compatibility...................................................................................................................................................

CONTROL FLOW.........................................................................................................................................................

SIMPLE AND COMPOSITE TYPES.........................................................................................................................

TYPES AND INITIALIZATION................................................................................................................................

ARRAYS.........................................................................................................................................................................

Multi-Dimensional Arrays.......................................................................................................................................

OPERATORS.................................................................................................................................................................

INTERFACES................................................................................................................................................................

C/C++ INCOMPATIBILITY......................................................................................................................................

Operator Overloading.............................................................................................................................................

Pointers.......................................................................................................................................................................

Multiple Class Inheritance.....................................................................................................................................

JAVA STYLE.................................................................................................................................................................

CONCLUSION...............................................................................................................................................................

EXERCISES...................................................................................................................................................................


The Java Language

Java is new (in addition to being cool), but, even for novice programmers it will have a lot of familiar elements.  In this chapter, we’ll look at the elements of the Java language - control flow, data types, operators, interfaces and classes - and how they work together.  We’ll contrast Java’s elements with their C and C++ analogs and point out the pieces that are unique to Java.  Finally, we’ll look at Java documentation style using the javadoc tool.

The most basic element of becoming productive in a language is figuring out how to get a simple program to compile and run. So lets take a simple applet and compile it. Listing 2.1 shows our simple applet.

Listing 2.1: A simple applet.

package chap2;

 

import java.awt.Graphics;

import java.applet.Applet;

 

public class ch2_fig1 extends Applet {

String TheString;

 

public void init() {

     TheString = new String( "Hello Java" );

     resize( 200, 150 );

     show();

    }

 

public void paint(Graphics g) {

     g.drawString( TheString, 20, 50 );

    }

}

Like all the hello-world programs that have preceded it, the entire point of this one is to display the string “Hello Java” on the user’s screen.  To do that, we create a class named ch2_fig1.  Everything (methods and variables) in a Java program must exist within a class.  If you don’t have a class, you don’t have a Java program.  Our class sub-classes Applet.  This allows it to be loaded by a browser.  (We talk more about the Applet class in Chapter 4).  Within our class, we have one variable, TheString, and two methods (functions for you C people) - init and paint.  These methods are all overloads of methods in the Applet class.  The init method is called automatically when the applet is loaded and it sets our String variable, resizes and shows the applet.  The paint method is called automatically whenever the browser thinks the applet needs to repaint its screen, for instance, when the browser is resized.

To compile the applet, you’d enter the following command at the operating system prompt:

javac -classpath \jdk\java\lib\classes.zip ch2_fig1.java

javac is our compiler, the tool that turns source files into bytecode files. classpath is the location of the supplied Java class files AND the top-level directory for any other Java packages you’re trying to use.  Later, when we start developing pieces of the agent system, we’ll add our top-level directory, agent, to the classpath.  Finally, ch2_fig1.java is our source file.

Running this compilation command produces a file named ch2_fig1.class which contains the intermediate code. In order to run the simple applet, we need an HTML file that references the applet. Listing 2.2 shows an HTML file that uses our simple applet.

Listing 2.2: HTML code that runs the simple applet.

<title>Chapter 2 - figure 1 - A Simple Applet</title>

<body>

<applet code="chap2/ch2_fig1.class" width=200 height=150>

</applet>

</body>

When the user points his browser at this HTML page, the browser reads the <applet> tag and passes the class file “chap2/ch2_fig1.class” to the Java interpreter.  The applet referenced by the applet tag must be a Java .class file. Now that we have a compiled class file and an HTML wrapper, we can see the applet in action.  There are currently two ways to do this.  You can enter the command “appletviewer ch2_fig1.html,” which runs the applet within Sun’s appletviewer utility.  appletviewer is a shortcut way of viewing applets in action without cranking up a browser.  It displays ONLY the applet in the HTML file, and none of the other HTML. The other way to view this applet is to open the HTML file in Netscape. Figure 2.1 shows the applet running in Netscape.

Figure 2.1: The simple applet running in Netscape.

<< ch2_fig1.tif >>

Notice how our “Hello Java” text is indistinguishable from the HTML text around it. This is one of the beauties of the Java/HTML combination: seamless integration.

Java World consists of millions of small applets from thousands of independent developers. Because of this distributed development environment, Java has to provide a very large namespace for applets. Limiting applet names to the DOS filename convention of 8 characters, for instance, would give us approximately 26 to the 8th power, or two hundred billion possible unique applet names.  This is fine, if you want to name your applets RRRRXXHY or FRTYZZVC.  The real problem is that, of those two hundred billion possible names, only a very few are descriptive.  There are only so many meaningful English (or Chinese, or Russian) words that fit in eight characters.

The net, the world in which Java applets are developed and run, is naturally divided into sites, directories and files. This is reflected in the URL, which has the format:

protocol://site/directory/subdirectory_a/subdirectory_b/filename

 

In order to provide a large namespace—enough so that names can be descriptive—Java package names use a subset of the URL namespace, the directory/filename section. The only two entities in the Java world, packages and classes, correspond exactly to directories and files. The top-level entity in the Java world is a package. For all intents and purposes, a package is a directory. A package contains from 1 to n classes. The physical entity “package” is actually just a directory.

All packages are named according to a hierarchical naming scheme of unlimited depth. The full name of a class has the form “package_name.class_name.” Take, for example, Java’s predefined Graphics class. This is part of the awt package, which is a sub-package of the java package. Thus, the full name of the Graphics class is java.awt.Graphics. Within an applet, we can refer to a Graphics object as either Graphics, or java.awt.Graphics. As an example, consider the class definition in our simple applet, shown in the code line below:

public class ch4_fig4 extends Applet {

 

We could rewrite this as follows:

public class figure ch4_fig4 extends java.applet.Applet {

 

Or, for another example, consider the paint method in our simple applet, shown in the code line below:

public void paint( Graphics g ) {

 

We could rewrite this as:

public void paint( java.awt.Graphics g ) {

 

Packages are reflected in at least two spots in a class file; in the package statement that leads off the file and in the import statements. The package statement indicates which package this class belongs to. It must be the first line in the file, and it should give the full package name. The package statement for Graphics reads:

package java.awt;

 

The package name must also reflect the directory structure of the compiled class files. Thus, a class named java.awt.Graphics must exist in a file named “java/awt/Graphics.class.” A single package can contain any number of classes and sub-packages.

Attaching a class to a package also has the effect of making the class public, in the sense that it can be imported by other classes. Classes that are not part of a package cannot be imported by other classes. You can define classes that are not part of a package, omitting the package statement, making them essentially private classes. Because they have no use to anyone else, many classes will fall into this category.

There are two types of classes, public and private. Public classes are denoted by the keyword public. Classes without the public keyword are private. Each Java source file can contain only one public class, but any number of private classes. The source file name and the class name must match exactly. This might sound like a stupid restriction, until you hark back to the new world order according to Java. Many, if not most, of the classes used by a particular Java application will exist out on the network. If the compiler had not only to find the file on the network but also load it and search its contents for a particular class, it would increase the network traffic, and slow down the compile—exponentially.

The import statement is similar to the #include directive in a C or C++ program. It’s used to get the class definition for external classes so that the compiler can perform proper type checking, among other things. Every class that is referenced in a Java program file must either exist within that file or be imported via an import statement. Thus, because our simple applet sub-classes Applet, we have to import java.applet. Notice that we use the wildcard operator * to indicate that we want to import all the classes in the java.applet sub-package. You can use the import statement to import a single class file, or to import all the classes in a directory. You can only use the * operator to import all the classes of a package, and not to import all the sub-packages of a package. In our simple applet, we can catch the definition of Applet by importing java.applet.*, but not by importing java.*. What import java.* literally means is “import java/*.class.”

In order actually to load a class imported via the ‘import package.filename” statement, Java must turn the package.filename statement into a fully qualified path. With package and filename, we have the relative part of the file name.  All we need to finish our fully qualified path is a path from the root directory to our class directories - the directory that has our packages as subdirectories. The java compiler gets this from the classpath environment variable. For the simple applet to compile, we need to supply a base directory for the imported java packages. In the current case, this is /jdk/java/classes. If we append an import statement to the classpath, it should give us the absolute filename of the class file we’re trying to import. For example, the Graphics class is imported by appending java.awt.graphics to /jdk/java/classes. Here are some examples of classpaths:

*   -classpath /jdk/java/classes

*   -classpath /agent/classes/rel

You can combine these classpaths in one statement separated by semi-colons, like so:

-classpath /jdk/java/classes;/agent/classes/rel

Using the Example Applets

This naming system suggests a logical structure for the classes in this book. We create a package for each chapter, as well as packages for each piece of the finished Agent system. In the event of any naming conflicts, we create sub-packages to distinguish between similar classes. Figure 2.2 shows the entire package hierarchy for the examples in the book.

Figure 2.2: Directory structure and Java package hierarchy for this book.

<ch2_fig2.tif>

The top-level directory, book, is not a package of it’s own, but each sub-directory is a package.  \book is the directory we supply in classpath, so that, for example, the class name chap2.ch2_fig1 actually resolves to the file \book\chap2\ch2_fig1.class

Each example applet gets its own HTML page. Each chapter gets its own page that lists its examples. The entry point to the book is the table of contents page, which, of course, contains links to all the chapter pages.

Language Basics: A Quick Tour

There are two types of classes: public and private. There can only be one public class in a Java source file, but any number of private classes. Each class ends up with its own .class file. Say you have a source file such as that shown in the code snippet below:

package MyPackage;

 

public class Pub {

     }

class Private1 {

     }

class Private2 {

     }

class Private3 {

     }

 

What you will end up with after compiling is four compiled bytecode files: Pub.class, Private1.class, Private2.class and Private3.class. Thus, in the same package/directory you cannot have both a public and a private class with the same name.

The class statement must declare which class this one is subclassing, and what interfaces it implements. A class can subclass one class, but it can implement any number of interfaces. For example, the code line below declares a class that extends the Applet class and implements the Runnable and ImageObserver interfaces:

class MyClass extends Applet implements Runnable, ImageObserver{ ...

 

A class that does not specify a superclass (i.e., does not include an extends clause) extends the Object class by default.

Methods always occur within a class. They are declared and used the same way you do in C++, so I won’t waste a lot of verbiage on it. The one thing to look out for in method declarations is that a method must declare all exceptions that it either throws or passes through. See Chapter 6 for complete coverage of exceptions. Methods can be overloaded, and, unless they are declared as final, can also be overridden. Methods have a return type, but (C programmers beware) experience has shown that most methods should return a void. Error conditions should never go back to the caller through the return value. Use exceptions (again, see Chapter 6).

Variables and Scope

There are two basic classes of variable: instance and local. Instance variables are accessible to any method in the class. Local variables, obviously, are local to the method, or block, within which they are declared. By and large, the scoping rules of C++ apply.  The two kinds of variable are illustrated in Listing 2.3.

Listing 2.3: Instance and local variables.

class X {

     int AnInstanceVariable;

     public void MyMethod() {

           int ALocalVariable;

           AnInstanceVariable = 2;

     }

     public void MyMethod1() {

           int AnotherLocalVariable;

           AnInstanceVariable = 1;

     }

}

 

You can create a scope (area) simply by bracketing a block of code with curly braces, and any variable declared within a scope will only be visible within that scope. Listing 2.4 illustrates a correct use of this technique.

Listing 2.4: Correct creation of a scope.

public void MyMethod() {

     int i,j;

     for( i = 0; i < 100; i++ ) {

           j = i;

     }

     System.out.println( “j=“+j );

     }

 

On the other hand, Listing 2.5 fails to compile because j is an undefined variable in the scope in which println is invoked.

Listing 2.5: Scope trips on an undefined variable.

public void MyMethod() {

     int i;

     for( i=0; i<100; i++ ) {

           int j = i;

           }

     System.out.println( “j=“+j );

     }

 

Like classes, instance variables can also be public or private. The default is private. Therefore, in Listing 2.6, j is public, but i is private.

Listing 2.6: Private and public instance variables.

public class MyClass {

     int i;

     public int j;

     ...

 

Static variables and methods apply to the whole class, rather than an instance of the class. Thus, to use a static variable or method, there doesn’t need to be even one instance of the class in existence. Listing 2.7 illustrates this point.

Listing 2.7: Using a static variable within a class without instantiating the class.

class MyMainClass {

     public MyMainClass() {

           MyClass.TheStaticInt = 1;

           MyClass.TheStaticMethod();

           }

     }

class MyClass {

     static int TheStaticInt;

     static void TheStaticMethod() {

           TheStaticInt=2;

           }

     }

 

In this case, we have not explicitly instantiated MyClass, yet we’ve used its static methods and variables anyway. Perhaps the most pervasive example of static variable/method use is the method System.out.println(). out is a static variable, of type PrintStream, in the class System, and println is a static method within the class PrintStream. System.out is actually a bit of an anomaly. Public instance variables are extremely rare in the supplied Java packages. Sun prefers to provide access to instance variables through a method with the prefix get, like Component.getGraphics, which gets a graphics context for drawing.

Java also allows static initialization. That is, you can declare a block of code (surrounded by curly braces) as static. It will run once and be applied to the class as a whole rather than instances of the class. This is very useful for, say, initializing a static array of composite types, as shown in Listing 2.8.

Listing 2.8: Initializing a static array.

class MyClass {

     static Integer j[] = new Integer[100];

     static {

           for( int k = 0; k < j.length; k++ )

                j[k] = new Integer(k);

           }

     ...

 

You can have as many static initialiazers as you want. Initializations are executed in the order in which they are encountered in the file. This can lead to subtle bugs, especially when you have statements that combine type declaration and initialization. For instance, consider the class shown in Listing 2.9.

Listing 2.9: Problems from multiple initializers.

class MyClass {

     int j = 2;

     int k = 1;

     static {

           x = j+k;

           }

     int x = 4;

     ...

 

In Listing 2.9, here’s what happens, and the order in which it occurs:

1.    An int named j is created.

2.    j is set to 2.

3.    An int named k is created.

4.    k is set to 1.

5.    The forward reference to x causes an int named x to be created.

6.    x is set to (2+1).

7.    x is set to 4.

Essentially, the declaration of x is “split off” from the initialization of x. It is important to remember that declaration and initialization may happen at different times, even though they can be combined in one statement.

Finality

The last modifier we need to think about is final. Final means different things in different contexts. When applied to a (public or private) static instance variable, you get the effect of a global constant. Consider Listing 2.10.

Listing 2.10: Using the final modifier.

     public class MyClass {

           public static final int GlobalInt = 10;

     }

 

Listing 2.10 is only a code snippet, of course. But if this is the code you used to declare the GlobalInt varialbe, then any class, anywhere can reference GlobalInt simply as MyClass.GlobalInt. As a result, the code line:

int x = MyClass.GlobalInt;

 

will set x to 10, no matter where it’s called, and even whether or not there is any instance of MyClass.

Declaring a method as final guarantees that it will not be overridden. Many of the methods in the supplied packages are declared final, a fact guaranteed to irritate those who might like to “optimize” some of Sun’s methods. Declaring a class as final guarantees that it can not be sub-classed. Again, many of the supplied classes, the composite types for instance, are declared final. Trying to override a final method or sub-class a final class will generate a compiler error.

C++ Compatibility

C++ compatibility is one of the features that has led to Java’s rapid acceptance. That syntax-compatibility can be summed up in these four categories: keywords, control flow, simple types and operators.

Keywords are the vocabulary of a programming language.  For example, for, if, while, int, and char are all keywords in C/C++ and Java.  The vast majority of Java keywords come directly from C and C++.  Java keywords are summarized in Appendix X.

John: First, we need a little more introductory text here. Second, let’s talk about the appendices, if any: we need to decide on that mucho pronto. J  --Scott.

Control Flow

John: An introductory paragraph or two?  --Scott.

Controlling which statements are executed, and in what order, is the most basic task of a programmer and every language provides flow-control structures to make that easier.  In the beginning there was if, and goto.  Now things are a little more sophisticated.

Java provides a set of flow-control structures, listed in table 2.1, that are identical to those of C and C++.

Table 2.1: Java Control Structures.

Control structures          What it does

for        Loop on a condition, with initialization, increment and top-exit.

do while            Loop on a condition, bottom-exit.

while     Loop on a condition, top-exit.

if else   Branch on condition.

try catch           Try a block of expressions, and catch any exceptions.  See Chapter 8.

throw    Throw an Exception. See Chapter 8.

The control structures if-else, while, do-while, for, and return all work the same as they do in C++. Most of these are familiar to users of any programming language, so we won’t waste any time on them. Conspicuous by its absence from this list is the infamous goto, one of C++’s C holdovers. The exception-handling structures, try-catch and throw, are covered in detail in Chapter 6.

Simple and Composite Types

Everything in a Java program is either a simple or composite type. Understanding the difference between them is one of the first hurdles you need to overcome when first learning Java. Java supports a set of simple types similar to that of many C++ compilers. int, char, byte, long, float, double are all here. Note that each simple type has a size that is the same for every platform. A Java int is 32 bits whether its running on a an Intel 8086, or a DEC Alpha. Table 2.2 shows the list of simple types and their sizes. Note that a char is 16-bit Unicode.

Table 2.2: Simple types and their sizes.

Type     Size in bytes

byte      8

short     16

int         32

long      64

char      16 (Unicode)

float     32 (IEEE 754 subset)

double  64 (IEEE 754 subset)

boolean            The size of a boolean isn’t really useful because there’s no way to convert back and forth from boolean to any of the numeric types.

UNICODE is a form of 16-bit character that works for international characters (like Kanji) as well as English alphabet.  IEE754 is a specification for the format and precision of floating point numbers.

In C and C++, knowing the size of a variable was often neccessary for doing pointer arithmetic, but because there are no pointers in Java, type sizes are really only useful for determining variable minima/maxima.

Composite types, such as classes, arrays, and interfaces, can be constructed from simple types and from other composite types. As an example, consider the class shown in Listing 2.11. Type SimpleClass consists of the simple types class, char, int and void (oneFunction).

Listing 2.11: A composite type.

class SimpleClass {

char oneChar;

int oneInt;

public void oneFunction() {

     oneInt = 2;

     }

}

 

One of the most confusing things about Java is that it comes with a set of composite types (in the java.lang package) that look a lot like the set of simple types. These types are:

*   Boolean

*   Character

*   Double

*   Float

*   Integer

*   Long

*   Number

*   String

These types exist to encapsulate basic type functionality often found in the C runtime library. For instance, C gives you an integer type, int.  In the C runtime library there are functions named atoi which converts a string to integer, and itoa which converts a C int to a string. Java lumps this functionality into the composite Integer type.  itoa’s equivalent would be the method Integer.toString(), while atoi’s equivalent would be the constructor Integer( String stringNum).

Remember too, that some of the casting tricks that used to work in C++ aren’t supported in Java. Java is very strictly typed. You cannot cast an object to any other type except one of its superclasses. So these composite versions of the simple types have to provide you with that ability to turn one type (particularly strings) into another type.

Types and Initialization

Simple and composite types have very different initialization requirements. The following code snippet will compile and run:

int j;

j = 1;

 

But change that simple int to a composite Integer, as in the code snippet below, and you get a compiler error complaining about incompatible types.

Integer j;

j = 1;

 

In general, composite types don’t support assignment via the = operator: instead, you need to pass the desired value as a parameter to the object’s constructor. In order to get the same effect as our valid simple type assignment then, we need to modify our code as follows:

Integer j = new Integer(1);

 

This also brings up another crucial difference between simple and composite types. An object of simple type exists the instant you declare it. So when we say “int j” there is a space in memory reserved for an int value. Not so when we say “Integer j.” No Integer object exists until we instantiate it via the new operator. If you try to reference j before instantiating it with new, you’ll probably end up throwing a NullPointerException.

Composite objects must be instantiated

It bears repeating: though objects of simple types are created automatically as soon as they are declared (e.g., int j), objects of composite types are not created automatically when declared (e.g., Integer j). They must be instantiated with the new keyword.

Arrays

Java arrays are composite types and, thus, are very different from arrays in C and C++. For one thing, as composite types, they have to be instantiated via new. All you can say about an array in the declaration is “this is an array,” as in the code line below.

Integer Jarray[];

 

In Java, you can’t “size” the array in the declaration the way you do in C and C++, which allow you to write code such as the following:

int jarray[25];

 

That code line, while perfectly legal in C and C++, will give you a compiler error in Java. To recreate that construction in Java you’d use the code line shown below:

int jarray[] = new int[25];

 

This gets you an array of 25 ints that are all initialized to 0. When you’re creating an array of simple types, such as int, that’s all you need to do. When you’re working with composite types, though, instantiating the array is only half the job. Consider the code line shown below.

Integer jarray[] = new Integer[25];

 

That statement only gets you an array full of null objects, which, if you tried to use them would, once again, throw a NullPointerException. In order to populate the array with initialized Integers, you need to run through it instantiating Integers with new, as in:

Integer jarray[] = new Integer[25];

for( int j = 0; j < jarray.length; j++ )

     jarray[j] = new Integer(0);

 

Like C and C++, Java arrays are 0-based.  The first item in a Java array will always be at array index 0.

Multi-Dimensional Arrays

Java doesn’t believe in multi-dimensional arrays, but does allow arrays of arrays, which achieves the same effect. To create an 8-by-16 integer array in C, you’d use a code line such as:

int x[8][16];

 

The equivalent statement in Java would read:

int x[][] = new int[8][16];

 

Literally translated, this says that x is an array of eight 16-int arrays. Remember that the array members are simple types, so we don’t have to instantiate them individually. The array x has eight elements, each of which is an array. Thus, you can say:

int y = x[3].length;

 

which queries the length of the fourth int array in the x array of arrays. This has another implication, too. Your array doesn’t have to be symmetrical. For instance, the following code is perfectly acceptable in Java:

int x[][] = new int[8][16];

x[1] = new int[25];

x[6] = new int[4];

 

This code creates an array of arrays, with each element of the array consisting of an array of 16 ints. Then it replaces the second 16-int array with a 25-int array and the seventh 16-int array with a four-int array. You can still reference these arrays just like C-style multi-dimensional arrays. The code in Listing 2.12, for example, runs through this array, printing every element to standard out.

Listing 2.12: Traversing an array of arrays.

for( int j = 0; j < x.length; j++ )

     for( int k = 0; k < x[j].length; k++ )

           System.out.println( “x[“+j+”][“+k+”] = “+x[j][k] );

 

The code in Listing 2.13, however, will throw an ArrayIndexOutOfBoundsException when j equals 6 and k equals 4, because we’ve replaced the original 16-int array with a four-int array.

Listing 2.13: Overrunning an array.

for( int j = 0; j < x.length; j++ )

     for( int k = 0; k < 16; k++ )

           System.out.println( “x[“+j+”][“+k+”] = “+x[j][k] );

Operators

Java supports the usual complement of C++ style operators, shown in Table 2.3.

John: Can we have a little more intro here – at least a couple of paragraphs? Also, I’ve added a second column to the table. The new column explains what each operator is. Would you please fill in the blanks? Thanks.  --Scott.

Table 2.3: Java operators in precedence order.

Operator           What it does

.[]()

++ -- ! ~ instanceof

* / %

+ -

<< >> >>>

< <= > >=

== !=

&

^

|

&&

||

?:

= op= (where op is +, -, * ...)

Most of these operators are familiar enough that I won’t explain them in detail. Operator order of precedence is identical to that of C/C++. The only unfamiliar operator in the list is instanceof, which we’ll use extensively later to pull the frame window from an unordered chain of Component objects.

Interfaces

In Chapter 1, we talked a little about the theory of interfaces. You can think of a class as two pieces, the description of the class (class declaration and method prototypes), and the implementation of the class (the actual code in the body of the class’s methods). An interface is basically a description of the input to, and output from a class, with nothing said about HOW the class creates the output from the input. Interfaces are declared exactly the same way as classes (substituting interface for class).

A class that implements an interface must provide all the methods specified by that interface and each method must match the interface’s definition exactly. If the interface calls for a method, as shown in the code snippet below, then any implementation of ABC must have a method xyz that takes an int argument and returns an int, but it can implement xyz in any way it wants.

interface ABC {

public int xyz( int a );

}

Listing 2.17 declares an interface, Sortable.  Listing 2.15 and 2.16 present two implementations of the sortable interface.  And the applet of Listing 2.14 creates one of each of our Sortable objects and sorts it using the Sortable interface method, sort.

Listing 2.14: The applet that uses our sortable objects.

package chap2;

 

import chap2.*;

import java.lang.*;

import java.util.*;

import java.applet.*;

 

public class ch2_fig14 extends Applet {

 

public void start() {

     AlphaList al = new AlphaList();

     al.addElement("abcd");

     al.addElement( "laksdjfdf" );

     al.addElement( "sdsdfdlfkj");

     al.addElement( "ouwet");

     al.addElement( "basdf");

 

     System.out.println( "AlphaList before the insertion sort" );

     for( int i = 0; i < al.size(); i++ )

           System.out.println( "al["+i+"] = "+(String)al.elementAt(i));

     SortTheSortableThing(al);

     System.out.println( "AlphaList after the insertion sort" );

     for( int i = 0; i < al.size(); i++ )

           System.out.println( "al["+i+"] = "+(String)al.elementAt(i));

 

     OtherList ol = new OtherList();

     ol.addElement("abcd");

     ol.addElement( "laksdjfdf" );

     ol.addElement( "sdsdfdlfkj");

     ol.addElement( "ouwet");

     ol.addElement( "basdf");

 

     System.out.println( "OtherList before the insertion sort" );

     for( int i = 0; i < ol.size(); i++ )

           System.out.println( "ol["+i+"] = "+(String)ol.elementAt(i));

     SortTheSortableThing(ol);

     System.out.println( "OtherList after the insertion sort" );

     for( int i = 0; i < ol.size(); i++ )

           System.out.println( "ol["+i+"] = "+(String)ol.elementAt(i));

     }

public void SortTheSortableThing( Sortable sortableThing ) {

     sortableThing.sort();

     }

}

 

Listing 2.15: The AlphaList implementation of our Sortable interface.

package chap2;

 

import chap2.*;

import java.lang.*;

import java.util.*;

 

/** A class that implements a sortable vector of Strings.

@see Sortable

@author John Rodley

@version 1.0

*/

public class AlphaList extends Vector implements Sortable {

 

     public AlphaList() {

           super(1);

           }

 

/** Bubble sort the Vector as Strings.  If they aren't strings, this'll

crash with an illegal cast exception.

*/

     public void sort() {

           int i, j;

           for( i = size()-1; i >= 1; i-- ) {

                for( j = 2; j <= i; j++ ) {

                     String s = (String)elementAt(j);

                     String sp = (String)elementAt(j-1);

                     if( sp.compareTo(s) > 0 ) {

                           setElementAt(s, j-1);

                           setElementAt(sp,j);

                           }

                     }

                }              

           }

     }

 

Listing 2.16: The OtherList implementation of our Sortable interface.

package chap2;

 

import chap2.*;

import java.lang.*;

import java.util.*;

import java.lang.*;

 

/** A class that implements a sortable vector of Strings.

@see Sortable

@author John Rodley

@version 1.0

*/

public class OtherList extends Vector implements Sortable {

 

     public OtherList() {

           super(1);

           }

 

/** Insertion sort the Vector as Strings.  If they aren't strings, this'll

crash with an illegal cast exception.

*/

     public void sort() {

           int i, j;

           for( i = 2; i < size(); i++ ) {

                String v = (String)elementAt(i);

                j = i;

                String s = (String)elementAt(j-1);

                while( s.compareTo(v) > 0 ) {

                     setElementAt(s, j );

                     j--;

                     s = (String)elementAt(j-1);

                     }

                setElementAt(v, j);

                }

           }

 

     }

 

Listing 2.17: The definition of the Sortable interface.

 

package chap2;

 

/** An interface that defines this object as sortable.  Many different

types of collections will implement this interface, using different

algorithms for the actual sort method.

@author John Rodley

@version 1.0

*/

public interface Sortable {

     // Tells the implementor to sort itself

     public void sort();

     }

The key point to look at here is the SortTheSortableThing method in Listing 2.14.  This method takes a Sortable object as its argument.  The Sortable interface specifies only one thing, that any implementor provide a method named sort. Thus, SortTheSortableThing knows only one thing about the sortableThing argument - that it will sort itself when we call sortableThing.sort. 

Notice, in Listings 2.15 and 2.16, that each of our Sortable implementors, AlphaList and OtherList, provides a sort method, but the sort methods themselves are quite different. Our applet, ch2_fig14 creates one of each of these classes, then has it sort itself, printing out the Vector before and after each sort. 

C/C++ Incompatibility

Java is not C/C++.  It supports a great deal of C/C+ syntax, but has some incompatibilities.  The most important of these are operator overloading, pointers, and multiple inheritance. Operator overloading, and to some extent, multiple inheritance are fairly advanced techniques which some C++ coders never use.  Pointers, on the other hand, are right at the heart of any C/C++ program and Java’s lack of pointers will probably seem a little scary to C/C++ converts.

Operator Overloading

No issue generated as much heat in the early days of Java as the issue of whether or not to allow operator overloading. Personally, I never used it in my own classes, so I don’t miss it at all. The thinking behind omitting it was that it made programs very difficult to maintain. This is easy enough to see. An operator, usually a single character, is simply shorthand for something that could be described in much more detail. a+b could just as easily be written a.Plus(b). When a and b are integers, a+b is perfectly, and completely descriptive. When a and b are complex derived types, then the meaning of a+b is crystal clear ONLY to whoever wrote the overload.

Thus, most operators are only implemented for the simple types to which they apply, not the composite types. It’s important to keep this in mind when dealing with the look-alike composite types, such as Integer. The perfectly innocent code in Listing 2.18 doesn’t even compile.

Listing 2.18: Create three Integers and add two together, the wrong way.

Integer i = new Integer(0);

Integer j = new Integer(1);

Integer k = new Integer(0);

k = i+j;

What we’re trying to do, is create three numbers with two of them initialized, then set the value of the third to be the sum of the other two.  To get the desired effect, you’d write code such as that in Listing 2.B:

Listing 2.19: Create three Integers and add two together, the right way.

Integer = new Integer(0);

Integer j = new Integer(1);

Integer k = new Integer( i.intValue()+j.intValue());

Integer.intValue returns an int, and we can use the + operator on ints, so we call intValue against our two Integers, add those int values together and initialize our third Integer with that new int value.

There is one exception to the no operator-overloading rule: the use of + and += on a String concatenates to that String.  Outside the world of programming, nobody thinks of “adding” sentences together as in “this is a test” + “ of the PA”.  However, Java Strings support the + and += operators.  Thus you can get code like this:

String s = new String(“abdefg”);

String t = new String(“hijklmnop”);

String u = new String( s+t );

In this example, the value of u is the concatenation of s and t.  This is extremely useful in debugging code, and throughout the agent system, if we catch an unexpected Exception you’ll see a block of the form:

catch( Exception e ) {System.out.println(“Exception “+e); }

which concatenates the String “Exception” to the String value of the Exception e using the + operator.

Pointers

There are no pointers in Java. End of story. If you want to walk through something as if it were an array, then use an array. Much of what we used char pointers for in C/C++ is handled in the constructors for String.  Perhaps the best example of a place in the agent system where C-style pointers would have been useful, but instead we go through serious contortions to use Java arrays is the message handling code in Listing 7.11.

Multiple Class Inheritance

There is no multiple class inheritance in Java. That is, a class can have only one superclass. This might seem a severe limitation, but it is mitigated by the ability to multiply inherit interfaces.

Multiply inherited interfaces are not the same as multiply inherited classes.  We talked earlier about how an interface splits the definition of a class from its implementation.  A C++ class that inherits multiple classes inherits both the definition and the implementation of those classes.  A Java class that implements multiple interfaces inherits only the definition of those classes, not the implementation.  Thus, our Java class has to re-write the implementation of the class.  This is a limitation, but not as big a one as it might seem.  We’ll see this as we go along.

Java Style

Having talked about the language, then built and run a simple applet, now is a good time to talk about programming style. Java World is a totally new place, where the traditional documentation models don’t apply.

It used to be that there were three levels of code documentation:

*   Inline doc: The minimal, in-line documentation you always place in code to keep yourself sane when you’re maintaining it.  This is the most accurate of all the doc forms, but a real pain in the neck to read.  It also couldn’t be distributed among people who couldn’t be trusted with the source code.  It was not very pretty and often contained snide remarks.

*   Readme style doc: syntax and return value for most of the functions in the lib.  This was the kind of doc you got when there was no professional tech-writer involved in the process.  It was a real pain in the neck to create and nearly impossible to maintain, since the guy writing it was also usually writing the product.

*   Commercial quality doc: description, syntax, return value, and error conditions for each function in the class library as well as theory of use and tutorials - suitable for use in a shrink-wrapped class library.  The kind of documentation we all love to use, and hate to write.  Also very expensive to maintain.  Once this kind of doc is in place, it takes an act of Congress just to change a return value.

Readme and commercial doc both had two problems: you had to print them, and because they were created from scratch, it was very expensive to keep them current.

Java operates on a different theory, namely that all documentation is inline, contained within the source code. To this end, Java provides a tool, javadoc, to help create automated package documentation using inline commentary. Since Java’s focus is to facilitate interoperability of classes, classes working together, javadoc creates HTML documentation only for the public parts of a class - interfaces implemented, public methods and variables.

Without requiring you to add anything to your source, javadoc can generate a complete set of linked HTML documents that list your classes, methods and variables. This “tree” of HTML documents is an outline of your class API. In order to fill in this outline, you need to add inline docmentation that conforms to certain standards.

Javadoc expects to encounter the documentation for an item, directly before that item appears in the source. That documentation must be enclosed in a /** */ pair, as in the code snippet below:

/**

this is my documentation for this class

*/

class MyClass {

...

 

All commentary intended to float through to javadoc documentation must be enclosed within /** */ pairs. Within a javadoc comment, you can also embed javadoc tags, similar to HTML tags, that will make javadoc format the comments in particular ways - adding hyperlinks, or emphasizing/deemphasizing items.

The three classes of javadoc commentary - class, method and variable - all support different sets of tags. Remember to keep all the tags of the same type together. Also take care when adding HTML tags of your own inside the javadoc commentary, because even if it works for this version, there’s no guarantee that future versions of javadoc won’t do things a little differently.

Table 2.4 shows javadoc class tags, while Table 2.5 shows javadoc method tags and Table 2.6 shows javadoc variable tags.

Table 2.4: Javadoc Class Tags.

Tagname           Arguments        Description

@see                   item-name                      adds a “see also” entry to the class documentation. This is a hyperlink to the item named in the see tag. The item-name can be a local class (@see classname), a fully-qualified class (@see fully-qualified classname) or a method (@see classname#methodname).

@version             version description          adds a version entry to the class doc

@author              author name                   adds an author entry to the class doc

Table 2.5: Javadoc Method Tags.

Tagname           Arguments        Description

@see                   same as above                                         

@param               parameter-name              adds an entry to the parameter section of the method doc.

@return               description                                               adds a Returns section to the method doc, which describes this method as returning the described value.

@exception          fully-qualified-class-name                           add an entry stating that this method throws the named exception.

Table 2.6: Javadoc Variable Tags.

Tagname           Arguments        Description

@see                   item to see                      adds a “see also” entry to the class documentation. This is a hyperlink to the item named in the see tag. The item-name can be a local class (@see classname), a fully-qualified class (@see fully-qualified classname) or a method (@see classname#methodname).

 

Figure 2.3: Javadoc output for our agent.util package viewed in Netscape.

<ch2_fig3.tif>

 

Figure 2.4: Javadoc output for ResultMessage class within agent.util package.

<ch2_fig4.tif>

Conclusion

Java is brand new, yet surprisingly familiar, especially to those steeped in the C/C++ programming tradition. Attention to a few small but important variations from C++ can make a C++ programmer productive in Java very quickly. And those who aren’t already C++ coders should be able to pick up Java very quickly, largely due to its lack of pointers.

Java also supplies a tool, javadoc, that allows coders to generate useable, hyperlinked class documentation directly from the inline documentation that they are already accustomed to writing.  This is a new style of documentation generation and it turns doc that used to be decipherable, and available, only to the coder into readable, end-user doc.

Exercises

1. Your classpath is C:\JavaStuff. You’ve written a class named MiniVan that’s part of a package named Automobiles. What is the fully qualified filename of the file containing the Java bytecodes of the MiniVan class?

2. Give me another name for the class Graphics that’s supplied with Java?

3. How many public classes can one source file contain? How many private classes?

4. How many classes, public or private, can one .class file contain?

3. This code will not compile:

Integer x = 1;

Why not?

4. Do simple types need to be instantiated?

5. Given the following code fragment:

class TheClass {

static int x = 2;

static {

     y=x*2;

     }

static int y=3;

static {

     y *= 2;

     }

What is the value of y at the end of initialization?

6. Is an array a simple or composite type? How about an array of simple types?

7. Will the following code fragment work?

Integer Xint[25];

Xint[0] = 0;

How would you change it to make it work as intended?

8. The following C++ code:

            #define RED 5

defines a constant named RED and sets its value to 5. Rewrite this code in Java.

9. You’re writing a new class, MiniVan, that needs all the functionality of two existing classes, Car and Van. In C++ MiniVan might subclass both Car and Van. How would you implement it in Java?

10. Can this statement:

int x = 3;

occur in an interface? Why? Why not?

 11. Give two reasons why Java doesn’t support pointers?

Why would javadoc choose not to document private methods and variables?