Chapter 10

A Java Tutorial


CONTENTS

JScript is an extremely powerful tool for developing Web pages. You have already seen a number of significant applications using JScript in the preceding chapters. The complexity and power of applications that can be developed in JScript is almost unlimited. There are certain situations in which the Java programming language may be a better solution, however.

The difference between JScript and Java is very much like the difference between hand tools and power tools. Anything you can do with a lathe, you can also do with a rasp, a hand saw, and sandpaper. It is quite possible to produce beautiful woodwork using only the simplest tools. One gains time, and perhaps uniformity, by using a lathe. To do this, however, one must know how to operate a lathe properly, without losing fingers. (In this analogy JScript is the lathe.) JScript is a simpler language than Java, with fewer built-in functions, yet it is still extremely expressive. Java has a much larger set of capabilities, yet it is also a bit more difficult to use.

The correct approach, of course, is to use all the tools that are available. Nevertheless, it is very important to realize when to pick up the fine-grit sandpaper and when to power up the lathe. This chapter introduces the Java language and describes its differences from JScript. The basic constructs of Java applets are explored and some simple examples are given.

The Java Language

If you have ever seen any Java code, you have probably noticed that it bears a substantial resemblance to JScript. A large part of the Java language is identical to JScript. There are, however, several significant differences between Java and JScript that are critical in learning how to use both tools effectively. These differences can be grouped into the following three categories:

The way in which the two languages handle objects is fundamental to how they are each used. Their interactions with the Web browser are also fundamentally different-the concept of an event is completely different in Java. Finally, the Java language is much stricter in its usage than JScript. Before we plunge into a detailed description of Java code, it is useful to look at these differences in a little more detail. Java and JScript are very different under the hood.

Java and JScript Compared

In Part II of this book, "JScript Objects," we took a very close look at objects in JScript. JScript objects are used to access the built-in mathematical, string, and date functions. JScript objects are also used to access and manipulate HTML elements inside JScript code. Java takes this object-oriented approach even further. Everything in Java is based on objects (known as classes in Java), and their properties (instance variables in Java) and methods. In JScript, you often create functions that are methods of your own objects. You are also perfectly free to have functions that are not methods. Event-handler functions are usually not method functions, for example. In Java, all functions must be methods of some object, and all variables must be properties of some object.

In JScript, the focus is on responding to events. A user action produces an event that triggers a JScript event handler, which does something useful. In Java, user events are handled very differently. When the user loads a Web page containing Java code, in the form of a Java applet, the browser tells the applet to start. When the user leaves that page, the applet is told to stop. While JScript code is ultimately event-driven and intimately tied to its HTML environment, Java applets are much more independent. An applet may respond to a mouse click within its active area, but it won't be listening for the sound of a Submit button being pressed. An applet is a little application that lives in its own world for the most part. JScript code is more like a Dynamically Loaded Library (DLL), which is activated in response to something.

Finally, we know that JScript takes a very relaxed attitude toward variables and functions. Variables are typeless, and the distinction between functions, objects, and arrays is blurry at best. By contrast, Java is an extremely strict language. All Java variables have an explicit data type. Types may be converted to one another only under very well-defined conditions, and only by using explicit type conversion functions. Java also enforces static name binding, instead of JScript's dynamic binding. It is impossible (so they say) to reference an undefined function.

See the "Dynamic Binding" section of Chapter 4 "JScript Objects," for a discussion of the name-binding concept.

Java is actually a very small language when compared with other object-oriented programming languages such as C++. Nevertheless, it has a large number of capabilities. The extensive set of built-in functions and objects known as the Java class hierarchy, for example, implements an extremely rich and powerful set of tools for image manipulation and network access, among other things. This Java tutorial focuses on the core part of Java necessary to create meaningful and interesting Web content.

Data Types in Java

Java variables must be explicitly declared with a particular data type. Java is very similar to the C and C++ programming languages in terms of the types it supports. Java, however, rigidly specifies the size and representation of its various types, so that there can be no confusion. If you have ever tried to port a C program from a DOS or Windows environment with 16-bit integers to a UNIX or Windows-NT environment with 32-bit integers, you know from firsthand experience how frustrating such low-level problems can be.

In addition to its primitive types, such as int, float, and boolean, Java also has object types, just like JScript. In Java, however, you must say which object was used to create a particular instance. The declarations that follow say that s is an instance of the String object, and that d is an instance of the Date object:

String s;
Date d;

Note
For the most part, Java statements are similar in form to their JScript counterparts. Every Java statement must end in a semicolon, however.

As you might suspect, these are uninitialized instances. The variables s and d are of type String and Date, respectively, but have no values yet. They are unbound, just as the JScript declaration:

var myvar;

creates an uninitialized (unbound) variable myvar. The only difference between the two languages is that in Java we at least know what the underlying type of s and d are, while in JScript, myvar is a complete mystery until it is given some value.

There are several differences between the object models of Java and JScript as well as their terminologies. Note that Java refers to its objects as classes, unlike JScript. Java object members are referred to as instance variables, rather than properties. Instances and methods have the same meaning in both languages. Note particularly that Java has no independent functions, only methods. These differences arise from the fact that Java is both explicitly typed and strongly typed. In Java, every piece of data must have a type. Every structured data type, such as String, is a class, while the data itself is an instance of that class. This concept of strong typing pervades all of Java, and is reflected even in the differences in terminology with JScript.

In Java, almost all the built-in data types are numeric. This is a reflection of the fact that everything that is more complex than a number is represented by a Java class. The built-in data types in Java are as follows:

The boolean data is a 1-bit type, which may have the familiar values true and false. Java is more strict than JScript in that it does not allow you to use a numeric expression in a context in which a Boolean value is expected. You must say while ( true ) rather than while ( 1 ), for example, because the clause of a while statement must be a logical (Boolean) value.

The byte, short, int, and long types are the basic fixed-point numeric types. All are signed quantities. They are represented using 8, 16, 32, and 64 bits, respectively. If you are a C programmer from either the 16- or 32-bit worlds, this may seem a little confusing. In the 16-bit world, int and short are mostly the same, while in the 32-bit world, int and long are often the same. Java is actually more explicit. All the basic types are platform-independent. Their sizes are fixed as part of the language itself.

You may be wondering what the char data type is. Java has taken a very modern approach and adopted a standard known as the Unicode standard for character representation. Unicode is a way of representing almost any character in any language of the world using a fixed Unicode sequence. Unicode sequences look like \uNNNN, where NNNN is a four-digit hexadecimal number. This is something like an extension to the escape sequences of the C programming language. In C, you can write "\007" to represent the character with ASCII code 7 (Ctrl+G, which usually makes the computer go "ding"). In Unicode, you can write "\u212B" to represent the Angstrom symbol Å and "\u1039" for the Tibetan Rinchanphungshad.

Tip
With the exception of Unicode characters, Java has the same syntax for literals as JScript.

Caution
What you see is not necessarily what you get with Unicode. Many browsers and most display devices are not able to handle properly most Unicode sequences. Avoid Unicode in your Java code unless you are sure your users have the appropriate fonts and software to display it.

The char data type is a Unicode character. It is 16 bits wide, and is an unsigned quantity, unlike all the other Java data types. This can also lead to some confusion for programmers who are familiar with 8-bit characters, since a char is twice as big as a byte in Java. One immediate consequence of the use of Unicode is that strings and arrays of bytes are not the same; some work must be done to convert from one to another. Another consequence is that if you ask a string such as Hiya how long it is, it will tell you 4. This means that it is 4 chars long, which is actually 8 bytes.

The float and double data types are standard single and double precision floating-point data types. The Java language mandates that these data types conform to the IEEE (Institute of Electrical and Electronics Engineers) 754 standard, so that a float will always be a 32-bit quantity and a double a 64-bit quantity, with very precisely defined notions of accuracy, precision, and permitted maximum and minimum values. Imposing a particular standard may be pushy, but at least it ensures that correct implementations will all work the same way.

On the surface, Java variables and JScript variables seem to behave in the same way. Because Java is a strongly typed language, unlike JScript, Java variables can be used only in much more restrictive ways. It is not possible to change the data type of a variable in Java, as it is in JScript. In order to convert between different data types, you must use explicit conversion routines. We'll see several examples of this, particularly in the final section of this chapter, "An Accounting Applet in Java."

Java Classes as Structured Data Types

Java would be very underpowered if it had only the built-in types listed in the previous section. Of course, it not only has these primitive types, it also has complex types that are built up from smaller components. These are classes in Java. They are very similar to JScript objects and also to the classes of C++. In fact, the Java class model is a very simplified version of the one used by C++. Java has a very rich set of predefined classes, known as the Java class hierarchy. Some of the components of this hierarchy are described in the final section of this chapter. Still more are discussed in Chapter 11, "More About Java." In this section, we discuss the basic concept of a class and show how it is defined and used.

The Java concept of a class is quite close to the JScript concept of an object. The primary difference is that Java is much stricter about how instances may be used, and has a more detailed set of rules that must be followed. For example, it is not possible dynamically to extend a Java instance, as it is in JScript.

See the section on "Using Variable Length Arrays and Extended Instances" in Chapter 4 "JScript Objects," which describes how to extend JScript instances.

A Java class is a collection of variables and methods. When a class is created, its variables and methods are defined as part of the class definition. Therefore, the shape of the class is fixed when it is created. Listing 10.1 shows a very simple Java class definition.


Listing 10.1  A Java Class for Keeping Track of Money
class Account {               // name of the class is "Account"
     int ivegot = 0;          // instance variable, initialized to zero

     void deposit ( int n ) {     // method for adding money
          ivegot += n;
     }
// method for determining how much is left
     int balance( ) {    
          return(ivegot);
     }
// method for attempting to withdraw money
     boolean withdraw( int n ) {     
          boolean result;     // local variable
          if ( n <= ivegot ) {
               ivegot -= n;
               result = true;
          } else {
               result = false;
          }
          return(result);
     }
}

Tip
Java class names should begin with an uppercase letter. Instance names often begin with a lowercase letter, and contain the class name of which they are an instance.

Listing 10.1 defines a class known as Account. It has a single instance variable, ivegot, which records the total amount of money stored in the Account. It is initialized to 0. It also has three method functions: deposit, balance, and withdraw. These method functions perform the operations specified by their names; they deposit money, get the account balance, and attempt to withdraw money.

There are several things to notice about this class definition. The first, and most obvious, thing about the class Account is that all its components are declared inside the class definition. In particular, all the class methods are given explicitly as part of the class itself. Methods and variables are not attached, as they are in JScript-they are a required part of the definition itself.

The second important aspect of these methods is the fact that each of them is declared with its own data type. The balance method is declared to be an int method, which indicates that it returns an int value, the amount of money left in the account given by the int ivegot. The balance method is said to have a return type of int. Similarly, the withdraw method has a return type of boolean; it returns a boolean quantity.

Note
The return type of a method must match the value returned. It is a serious error to attempt to return something whose type is different from the return type.

The void Keyword. The deposit method is interesting because it introduces a new keyword: void. The void keyword is used to indicate that nothing is returned. The deposit method simply takes its argument, adds it to the instance variable ivegot, and then falls off the end of its { } definition block. There is no return statement. void means what it says-there is nothing being returned.

The same rule applies for the empty argument list of the balance method. This indicates that the balance function accepts no arguments. This is in contrast to the deposit and withdraw methods, both of which accept a single argument, which we are told is an int. Just as it would be an error to pass a floating-point value to deposit, it would also be an error to pass any value to balance, or to try to take the value of a method function declared to be void.

If we assume myacct is an instance of the Account class, then both of the following statements would be in error by virtue of misusing the void type:

int i = myacct.balance(0); // bad: void args
int j = myacct.deposit(10); // bad: void return

Declaring Java Classes. With the example of Listing 10.1 in mind, you can see the general pattern for declaring both kinds of class members, namely instance variables and method functions. The general structure of a class declaration looks like the template shown in Listing 10.2.


Listing 10.2  Declaring a Java Class and Its Members
class Classname {         // a class named Classname
     Type1 Var1;          // instance variable Var1 of type Type1
     Type2 Var2;             // instance variable Var2 of type Type2
     ...                       // more instance variables
// Method Method1, return type RetType, arguments Arglist
     RetType Method1( Arglist ) {
          ...
          return( Thing );  // return statement if not void
          }                   // end of Method1
     ...                      // more methods
}                             // end of class definition

This class declaration consists of three basic parts, as follows:

The class declaration line declares the name of the class. It is Java tradition that this name begin with an uppercase letter, as noted earlier. This makes it easy to distinguish class names from variable names (and from the names' built-in types) which traditionally begin with a lowercase letter. In Listing 10.1, we declared a class named Account.

The instance variables are then declared immediately following the opening of the class definition, which is indicated by the opening bracket ({). It is possible in Java to declare instance variables anywhere outside a method definition, but it is simpler and easier to understand if they are all placed at the very top of the class definition. Our Account example had a single instance variable ivegot. Note that every instance variable must have a type, and may be initialized. The Account variable ivegot was initialized to 0, for example. As usual, it is good programming practice to initialize all instance variables to reasonable defaults, if possible.

The method function should be placed after the instance variables have been declared. Each method function declaration is itself composed of the following four parts, all of which are mandatory for (almost) every method:

The return type is given immediately before the name of the method itself. With one critical exception (constructor methods, which are described next), all methods must have a return type. If the method executes the return statement, it must declare what type of quantity it is returning in its return type. If the method does not return anything, it must declare its return type to be void. Java is very strict about mismatches of this form.

The method name is the name by which the method is invoked. This is exactly the same as the function and method names of JScript, with one exception. If the name of a method is exactly the same as the name of the class, then the method is known as a constructor method, or simply a constructor. Later in this section, you will see how these are used.

The argument list declares which arguments, if any, will be given to this method function. The argument list should contain the argument types, as well as the names of the arguments. In Listing 10.1, there is a method named deposit with a void return type and a single int argument named n; a balance method with int return type and no (void) arguments; and a boolean withdraw method, which also takes a single int argument named n, just like deposit. The argument list must match the arguments used exactly. We cannot call deposit with two arguments or with a string argument, and we cannot call balance with any arguments at all.

Finally, the set of Java code between the opening and closing brackets ({}) constitutes the method body. The method body does the work of the method. In general, the method body may make use of its arguments and of the instance variables. The method function deposit is a perfect example of this. Its method body consists of a single statement:

ivegot += n;

which adds the argument n, the amount being deposited, to the instance variable ivegot. Method functions can also call other method functions within the class.

Let's consider an example that makes use of the Account class. In this example, we will open an account, make a deposit of 100, and then make successive withdrawals of 40 and 70. The code to do this is shown in Listing 10.3. (Note that these deposits and withdrawals are not associated with any specific currency. The deposit of 100 could be 100 dollars, 100 francs, or even 100 coconuts.)


Listing 10.3  Using the Account Class
Account myacct;        // 1; declare an instance of the Account class
boolean gotit;                    // 2; got the money?

myacct = new Account();               // 3; initialize it
myacct.deposit(100);                  // 4; deposit 100
gotit = myacct.withdraw(40);         // 5; try to withdraw 40
if ( gotit == true ) {                 // 6; got it
     System.out.println("Withdrawal ok");     // 7; print a message
} else {                         // 8; didn't get it
     System.out.println("Insufficient funds");
     System.out.println("Balance: " + myacct.balance()); // 10; print balance
}
gotit = myacct.withdraw(70);               // 12; try for 70 now
if ( gotit == true ) {                       // 13; got it
     System.out.println("Withdrawal ok");
} else {                         // 15; didn't get it
// 16; print failure message
     System.out.println("Insufficient funds");
// 17; print balance
     System.out.println("Balance: " + myacct.balance());
}

This code shows a typical sequence of operations in Java. Statement 1 declares an instance of the class Account. It is an uninitialized instance, so it cannot be used until we initialize it. This initialization happens in statement 3 using the familiar new operator:

myacct = new Account();               // 3; initialize it

Note that the Account class is invoked as if it were a function (with no arguments). The variable myacct is now a fully initialized instance of the class Account, so we are free to use its methods.

Caution
Do not confuse instances with instance variables. Instances are structured data items created from classes using the new operator. Instance variables are variables contained within a class definition.

In statement 4, we make a deposit of 100, so that the ivegot now has the value 100. Similarly, statement 5 withdraws 40, so that ivegot is then reduced to 60. Both these statements invoke methods of the myacct instance, as follows:

myacct.deposit(100);                    // 4; deposit 100
gotit = myacct.withdraw(40);            // 5; try to withdraw 40

This withdrawal succeeds so that the boolean variable gotit, which holds the return value of the method function withdraw, is true. Therefore, the if test in statement 6 succeeds, and statement 7 is executed, as follows:

if ( gotit == true ) {                      // 6; got it
     System.out.println("Withdrawal ok");   // 7; print a message
}

We have enough experience to guess that System.out.println calls the println method of the subobject out of the system object System, and prints a message somehow.

Note
The dot operator (.) works the same way in Java and JScript. It is used to reference an element (instance variable, property, or method) of an instance.

We now grow bold and attempt to withdraw 70 from the account represented by the instance myacct, by calling the method function withdraw again in statement 12, as follows:

gotit = myacct.withdraw(70);               // 12; try for 70 now

This time, it doesn't work, however, since the account holds only 60 at this time. If you examine the body of the method function withdraw in Listing 10.1, you see that it is quite careful to test and make sure that there are sufficient funds. In this case, therefore, myacct.withdraw returns false.

The if test of statement 13 fails and the else pathway of statement 15 takes us to statement 16, which prints out a discouraging but accurate assessment of our financial state. Statement 17 is also invoked to print our balance, as follows:

if ( gotit == true ) {                    // 13; got it
     System.out.println("Withdrawal ok");
} else {                         // 15; didn't get it
// 16; print failure message
     System.out.println("Insufficient funds");
// 17; print balance
     System.out.println("Balance: " + myacct.balance());
}

Statement 17 uses the method function balance to get the value, and also makes use of + as a string concatenation operator. This is one of the few cases in which Java relaxes its strict rules on data types. It is usually possible to use + to convert nonstrings into strings, but there are certain exceptions. We learn more about this topic in the next chapter. For the moment, just know that converting any of Java's built-in numerical types to strings, as line 17 does, is safe.

This example probably raises several questions. Based on your experience with JScript, you are probably wondering why we need any of the methods of the Account class. After all, can't we just refer to the instance variable ivegot as myacct.ivegot, and use the following statements:

myacct.ivegot += n;
myacct.ivegot -= n;
int howmuch = myacct.ivegot;

to deposit n, withdraw n, and get the account balance into the variable howmuch? This example code in Listing 10.3 is also very unrealistic. Banks do not simply let you open an account; they want you to open an account with an initial balance. There should be some way of specifying that initial balance when we call new, just as we do in JScript. Finally, this example is insecure. We really do not want anyone to have access to our account balance, nor do we want people to withdraw our money. They should be able to deposit as much as they like.

All three of these observations are valid. To make this example more meaningful, we must introduce two more Java constructions-private instance variables and constructor methods.

Private Variables. The basic deficiency of the class Account defined in Listing 10.1 is that the instance variable ivegot is completely wide open. After the account is opened (new is called to create an instance of Account), we can simply manipulate the balance directly. This makes the three methods of Account fairly useless, and is also very insecure. We would like to hide ivegot from prying eyes, and also restrict the withdraw and balance methods. Listing 10.4 shows a revised definition of the Account class that does this. This file is ex10_4.java on the CD-ROM.


Listing 10.4  ex10_4.java-A Safer Version of the Account Class
class Account {                  // new and improved Account
     private int ivegot = 0;     // 2; amount on deposit
     private int password = 29;    // 3; instance var for password
     boolean isopen = false;       // 4; account actually has money

     void deposit(int n) {         // 5; anyone can deposit
          if ( n > 0 )               // 6; cannot deposit negative money
               ivegot += n;         // 7; do the deposit
/*
   Check account and make sure it is open
   Update the isopen variable
*/
          isopen = ( ivegot > 0 ? true: false ); // 8; 
     }                         // end of deposit method
// 10; password protected balance method
     int balance(int pword) {     
          if ( pword == password )   // 11; correct password
               return( ivegot );     // 12; return accurate balance
          else                       // 13; incorrect password
               return( -1 );         // 14; return bogus balance
     }                         // 15; end of balance method
// 16; password protection here too
     boolean withdraw(int pword, int n) {
          boolean ok = true;          // 17; ok to withdraw?
          if ( pword != password )    // 18; bad password
               ok = false;             // 19; cannot withdraw
          if ( n > ivegot )           // 20; too much
               ok = false;            // 21; cannot withdraw
          if ( ok == true ) {         // 22; withdrawal allowed
               ivegot -= n;           // 23; update balance
// 24; update isopen variable
               isopen = ( ivegot > 0 ? true: false );
          }
          return(ok);        // 26; return status
     }                         // end of withdraw method
}                              // end of Account class

This version of the Account class has three instance variables: ivegot, password, and isopen. The first two are declared to be of type int, and also have the special keyword private. A private variable is one that cannot be accessed outside the class. We can no longer refer to myacct.ivegot, nor can we refer to myacct.password, since both are declared private. We can, however, refer to the boolean variable isopen using myacct.isopen. This variable will be used to indicate whether the account has any money, so it is initialized to false. We can redundantly declare isopen as:

public boolean isopen = false;

using the public keyword. public is the opposite of private, and indicates that isopen may be accessed outside the class. By default, instance variables are public unless specified otherwise.

The methods deposit, withdraw, and balance are now essential. Because these methods are all within the Account class, they are permitted to access its private variables, as well as its public ones. The deposit method illustrates this in a very simple way. In statement 6, it tests its argument to ensure that it is positive, so that no one can make a sneaky withdrawal by depositing a negative amount. If the test passes, then statement 7 is executed. It adds the argument n to the private variable ivegot. It also updates the public instance variable isopen in statement 8. If there is some money on deposit, the account is declared to be open (isopen is true); otherwise, it is closed (isopen is false). The following three statements constitute the body of the deposit method:

if ( n > 0 )          // 6; cannot deposit negative money
     ivegot += n;     // 7; do the deposit
isopen = ( ivegot > 0 ? true: false );     // 8; update isopen

The new version of the balance method now makes use of password protection. To successfully call this method function, a password must be supplied as the argument pword. This argument is tested against the private variable password. If the passwords match, the actual balance is returned via the statement return(ivegot) on line 12. If they do not match, -1 is returned in statement 14. Note that because external access to a private variable is prohibited, it is not possible to steal the password by saying:

int ha = myacct.password;

It is also not possible to gain access to the balance without supplying a password. The statement:

int left = myacct.balance();

will be instantly rejected by Java, because any call to balance() must have exactly one int argument. The withdraw method operates in a similar way. It now takes two arguments, the password argument pword and the amount to withdraw n. If the passwords do not match (pword != password on line 18) or the amount is too great (n > ivegot on line 20), the local variable ok is set to false. If ok remains true, both tests must have passed and the withdrawal takes place (statement 23). In this case, the status of the account is also updated in statement 24. If there is no money left, the account is automatically closed (isopen is set to false). Finally, the status of the transaction is returned using return(ok) on line 26.

Note
Variables declared inside methods are known as local variables. They may be accessed only within the body of the method in which they are declared.

This version of the Account class satisfies our security concerns. No one can tamper with our myacct instance and withdraw money or even get our balance without the proper password. The password and the account balance are hidden. However, we have allowed anyone to determine whether or not we have an active account using the public instance variable myacct.isopen. Anyone may also deposit as much money as they like.

We still do not have any way of simulating the real-life experience of opening an account, because we must still execute two separate statements to open the account, as follows:

Account myacct = new Account();
myacct.deposit(100);

In addition, there is no way to set the account password. It is stuck at 29 forever. This means that any instance of the Account class will have this password. If you know the password on youracct, which is 29, then you also know the password on myacct, which is also 29. We can, of course, add a newpassword() method, which changes the password, but then we would have to execute three statements to open the account: a new statement to create the instance, a call to deposit to deposit some money, and a call to newpassword to change the password. The solution to this inefficient situation is the use of constructor methods.

Constructor Methods. Constructor methods, or constructors as they are often called, are used to initialize instances. They are called when the new operator is used on a Java class. From your experience with JScript, this would seem to be the natural approach. In JScript, you call new on a function, and pass it arguments which become the properties and methods of that new instance. You use the special keyword this to denote the current instance.

In Java, constructors are used somewhat differently. For one thing, constructors are methods of the class itself. Constructors have two special aspects, as follows:

The second aspect is the only case in which a method function does not have a return type. Other than these two special rules, a constructor is the same as any other method. Typically, you use a constructor to perform initialization, such as depositing money and setting the password to our Account class. Listing 10.5 shows the code for a constructor for Account which performs these two operations.


Listing 10.5  A Constructor for the Account Class
Account(int initdep, int newpword) {    // Constructor declaration
     ivegot = initdep;                  // initialize amount on deposit
     password = newpword;      // set new password
     isopen = true;            // declare account open
}                              // end of constructor

This code must be inside the definition of the Account class, of course. This constructor meets both our requirements. It initializes the private variables ivegot and password with the two arguments to the constructor, and also sets the public instance variable isopen to true to declare to the world that the account is now open. We must now use the new operator with two integer arguments to create a new account:

Account myacct = new Account(100, 12345);

This statement creates an instance myacct of the Java class Account, with an initial deposit of 100 and a new password of 12345. There is still a problem with this class definition, because there is nothing stopping us from making the erroneous statement:

Account badacct = new Account(-100, 12345);

This creates a perfectly valid instance, named badacct, with an initial balance of -100. The result here is simply nonsensical, but, in other cases, spurious initialization can lead to disastrous results. There is, in fact, a way of providing error-checking by using the isopen instance variable. Listing 10.6 shows a modified version of the Account constructor, which checks the initial deposit and makes sure that it is at least 100.


Listing 10.6  A Constructor for the Account Class with Error-Checking
Account(int initdep, int newpword) {  // Constructor
     if ( initdep >= 100 ) {   // 2; minimum deposit requirement met
          ivegot = initdep;
          password = newpword;
          isopen = true;
          }
     else                  // 7; minimum deposit requirement not met
          isopen = false;  // 8; declare failure
}

This constructor tests the argument initdep, in statement 2, to make sure that it passes the minimum deposit test. If it does pass, the same three initialization statements of Listing 10.5 are executed. The constructor then sets the isopen variable to true to indicate that the instance was successfully constructed (line 6). If the initial deposit test failed, the code branches to line 8 instead. This statement ensures that isopen is set to false to indicate that the instance construction failed.

Method Signatures in Java. At this point, our Account class has many of the features of a real bank account. We have password protection, all the methods that represent everyday transactions, and a reasonably accurate constructor. A little fine-tuning will give it even more verisimilitude, as well as illustrate one of the most important aspects of Java methods.

In real life, many bank accounts are rarely this simple. Accounts often have several different pools of money (savings, checking, checking/NOW, CD) with different rules on how these pools must be handled. You might want to open a checking account and a savings account at the same time. We could accommodate this by rewriting the Account constructor to accept three arguments representing the initial savings deposit, the initial checking deposit, and the new password. If either of the two initial deposit amounts is zero, we would interpret this as meaning that no account of that type was to be opened.

There is a simpler way, however. In Java, we can have more than one method with the same name, so long as all the argument lists are different. Suppose we assume that the default is to open only a checking account, and use the constructor shown in Listing 10.6 to perform that operation. We now need another constructor that will open both a checking and a savings account. Listing 10.7 shows this new constructor. Note that it references a new private instance variable named ivegotsav, which holds the savings account balance.


Listing 10.7  An Alternate Constructor for the Account Class
Account(int initdep, int initsdep, int newpword) { 
     if ( initdep >= 100 && initsdep >= 1 ) { // min balance tests
          ivegot = initdep;               // initialize checking
          ivegotsav = initsdep;          // initialize savings
          password = pword;               // reset password
          isopen = true;                  // accounts are open
          }
     else
          isopen = false;   // below minima; don't open account
}

The constructor of Listings 10.6 and 10.7 can both be used in the same class. Java tells them apart by virtue of the fact that their argument lists are different. The constructor of Listing 10.6 takes two int arguments, while that of Listing 10.7 takes three. This is often referred to as the method signature or the method shape, and is written as (int, int) or (int, int, int), respectively. The following statements open two new accounts (create two new instances of the Account class):

Account myacct = new Account(100, 12345);
Account wifesacct = new Account(500, 100, 54321);

The instance myacct represents a checking account with an initial deposit of 100, and a password of 12345. The instance wifesacct has both a checking account and a savings account, with initial deposits of 500 and 100, respectively, and a password of 54321.

Note
Multiple class methods can have the same name so long as they have different method signatures. This technique is known as overloading. While overloading is most useful for constructors, because the name of the constructor is fixed by the name of the class, it can be used for any class method.

The static and final Keywords. Now that we have introduced the concept of two pools of money within an Account, we must obviously modify the deposit, balance, and withdraw methods to make them aware of this fact. Let us suppose that we can withdraw money only from the checking account, but we can deposit money to either account, and query either account's balance. It would be nice to give the deposit and balance methods a tag indicating which pool of money to use.

If we were writing this code in C or C++ (or several other languages), we could make the tag be the member of an enumerated type. We could also use the #define construct to define symbolic constants to stand for the two types of account. Finally, we could create consts in C++ and use those for the two account types. How does one create a constant in Java? This question is answered as we dissect the code in Listing 10.8, which shows our final version of the Account class. This file is ex10_8.java on the CD-ROM.


Listing 10.8  ex10_8.java-A Fully Functional Version of the Account Class
class Account {                  // Account Class
     private int ivegot = 0;     // 2; amount in checking account
     private int ivegotsav = 0;  // 3; amount in savings account
     private int password = 29;     // 4; account password
     public boolean isopen = false; // 5; account  has money?
// these constants refer to the checking and saving accounts
     public static final int CHECKING = 1;         // 6;
     public static final int SAVINGS = 2;          // 7;
// all accts at this bank have this id
     public static int Bankid = 2167;              // 8;
// Constructor: open checking acct only
     Account(int initdep, int newpword) {          // 9;
          if ( initdep >= 100 ) {   // 10; min deposit reqt met
               ivegot = initdep;    // 11; init checking acct
               password = newpword; // 12; set acct password
               isopen = true;       // 13; the acct is open
               }
          else                // 15; minimum deposit requirement not met
               isopen = false;      // 16; insure failure
     }                              // 17; end of first constructor
// 3 argument constructor
     Account(int initdep, int initsdep, int newpword) { // 18;
          if ( initdep >= 100 && initsdep >= 1 ) { // 19; min balance?
               ivegot = initdep;          // 20; initialize checking
               ivegotsav = initsdep;      // 21; initialize savings
               password = pword;          // 22; set password
               isopen = true;             // 23; accounts are open
               }
          else
               isopen = false;     // 26; below min; don't open
     }                             // 27; end of 3 arg constructor
// deposit method: anyone can deposit anywhere ( no password )
     void deposit(int n, int which) {    // 28;
          if ( n <= 0 ) return;          // 29; no negative deposits
          if ( which == Account.CHECKING ) // 30; to checking
               ivegot += n;                // 31; deposit to checking
          else if  ( which == Account.SAVINGS ) // 32; to savings
               ivegotsav += n;      // 33; deposit to savings
     }                              // 34; end of deposit method
// password protected balance method
     int balance(int pword, int which) {   // 35;
          if ( pword != password )         // 36; incorrect password
               return( -1 );               // 37; return bogus balance
// checking account balance wanted
          if ( which == Account.CHECKING ) // 38;
               return(ivegot);          // 39; return it
// savings account balance wanted
          else if ( which == Account.SAVINGS )     // 40;
               return(ivegotsav);      // 41; return it
          else                         // 42; some strange 'where'
               return( -2 );           // 43; return error code
     }                                 // 44; end of balance method
// password protected checking acct withdrawal
     boolean withdraw(int pword, int n) {   // 45;
          if ( pword != password )          // 46; bad password
               return(false);               // 47; cannot withdraw
          if ( n > ivegot )                 // 48; too much
               return(false);               // 49; cannot withdraw
          ivegot -= n; // 50; update checking acct balance
// update the isopen variable
          isopen = ( (ivegot+ivegotsav) > 0 ? true: false ); // 51;
          return(true);             // 52; return status
     }                              // 53; end of withdraw method
}                                   // 54; end of Account class

For the most part, this version of the Account class is an amalgamation of the two constructor methods we introduced in the previous sections, together with updated versions of the deposit, withdraw, and balance methods from Listing 10.4. This version does introduce two new keywords, static and final, and one new concept, that of a class variable. We will examine in detail how this class now works.

There are seven variables declared in lines 2 through 8. The first four have already been introduced: ivegot and ivegotsav hold the checking and savings account balances, password holds the account password, and isopen is the overall account status. The only change we have made is to explicitly declare isopen to be public. These four variables are instance variables; the first three are also private. The next three statements (lines 6 through 8) use the new keywords, as follows:

public static final int CHECKING = 1;          // 6
public static final int SAVINGS = 2;           // 7
public static int Bankid = 2167;                   // 8

The final keyword simply states that this value may never be altered. A final variable must be initialized. final in Java serves the same purpose as const does in C++. The static keyword has a different purpose. It indicates that all instances refer to exactly the same shared variable. The static keyword makes a variable a class variable rather than an instance variable.

Tip
Declare class constants to be both final and static.

To understand the difference between a class (static) variable and an instance variable, consider the difference between the instance variable ivegot and the class variable Bankid, which we have just invented to hold an identifier associated with all accounts at this particular bank. Every instance of the Account class will have its own copy of the instance variable ivegot. The amount of money in my account, represented by the myacct instance, is unrelated to the amount of money in your account, represented by the youracct instance. You can conduct thousands of transactions, and amass millions of dollars in the ivegot instance variable of youracct without it having any effect on the ivegot instance variable of myacct (unfortunately).

This is not the case with the class variable Bankid. There is exactly one such variable, and it is shared among all instances of the Account class. This is what makes it a class variable: It belongs to the class, and not to the individual instances of the class. This also means that we may refer to it as Account.Bankid, as well as myacct.Bankid and youracct.Bankid. Note that the static and final keywords may also be applied to methods. We have already seen examples of static methods in JScript, in the Date object.

See the section, "The Date Object" in Chapter 5 "Built-In JScript Objects," for a complete description of its static methods and how they are used.

The Account class has two constructors, which we have already seen. The two-argument constructor is given in lines 9 through 17. It creates a checking account only. The three-argument constructor, which allows us to open both checking and saving accounts simultaneously, is shown in lines 18 through 27. Both constructors check their arguments to ensure that minimum deposit requirements are met, and set isopen to false if they are not.

We have rewritten the deposit method so that is takes a second mandatory argument, called which. This argument is used to indicate which account should receive the deposit of n. Error-checking of n happens in statement 29, which refuses to make a deposit if the amount is negative, as follows:

if ( n <= 0 ) return;          // 29; negative deposit forbidden

If the test passes, then the value of which is examined. It is expected to refer to one of the class constants CHECKING or SAVINGS. Note that we refer to them as Account.CHECKING and Account.SAVINGS, in statements 30 and 32. This is a class reference, which is permitted since they are static. We could just as well have used the instance references this.CHECKING and this.SAVINGS, since these constants are part of each instance, too.

If this is a checking account deposit, then the test in statement 30 passes and n is added to the checking account instance variable ivegot in statement 31. If which is Account.SAVINGS instead, then n is added to ivegotsav in statement 33 as follows:

if ( which == Account.CHECKING )        // 30; checking account deposit
          ivegot += n;                  // 31; deposit to checking
else if  ( which == Account.SAVINGS )      // 32; saving acct deposit
          ivegotsav += n;                     // 33; deposit to savings

If which is not equal to either constant, nothing happens. We just fall off the end of the deposit method, which is quite acceptable since it is a void method.

The code for the balance method, on lines 35 to 44, operates in the same way as the deposit method. It performs its usual password test (line 36). If that test passes, it tests the value of which and returns the corresponding balance. If which is neither CHECKING nor SAVINGS, the method returns an error code of -2. This value was deliberately chosen to be different from the bad password error return of -1 on line 37. The caller can distinguish the two error cases based on which bogus balance was returned.

The implementation of the withdraw method (lines 45 to 53) is almost unchanged from our previous version. We assume that we are permitted to withdraw only from the checking account, so no which parameter is needed. The test that updates the isopen variable has been updated to keep the account open so long as the total balance in both accounts (ivegot+ivegotsav) is greater than 0. This test is shown on line 51, as follows:

isopen = ( (ivegot+ivegotsav) > 0 ? true: false ); // 51; open?

Arrays in Java. There is one final piece of Java object machinery that we need before we can launch forward and actually make something appear on a Web page. We need Java arrays. It should come as absolutely no surprise that arrays are actually objects (classes)
in Java. The similarity with JScript arrays ends there, however. There are no associative arrays in Java, and there are no extensible arrays. Java's usual strictness is carried to fanatic extremes in dealing with arrays.

Java enforces the following five rules for all of its arrays:

This very restrictive approach is part of Java's security model. One of the most common ways of accessing memory that is not really yours is to declare an array, say int i[10], and then look at elements such as i[-6]. Veteran FORTRAN and C programmers will recognize this as the famous "stack creep" technique for reaching into system memory. Of course, arrays are also a source of completely innocent but vicious errors, such as referring to i[10], even though only i[0] through i[9] really belong to us.

Tip
Java arrays are zero-indexed, as in C, C++, and JScript.

Let us briefly consider how to use arrays in Java. If we actually do want an array of 10 ints, we must declare a variable to hold this array, and then allocate it using the new operator. The following statements do the trick:

int iarr[]; // declare an int array variable
iarr = new int[10]; // allocate space

Before we call the new operator, the variable iarr is absolutely uninitialized, just as the statement Account myacct; declares an instance myacct of the Account class, but does not actually create such an instance. It is absolutely prohibited to attempt to make an array declaration such as:

int badiarr[10];// hopelessly bad, awful, and wrong

The format used to allocate iarr is the pattern that should be followed to allocate an array of anything; do not attempt anything like the declaration of badiarr. In particular, we can use these two statements to allocate an array of Account instances:

Account acctarr[];
acctarr = new Account[10];

The variable iarr represents an array of 10 ints, and the variable acctarr represents an array of 10 Account instances. None of these is initialized yet, however, so it is unwise to attempt to refer to iarr[5] or acctarr[3]. Each of the array slots must be initialized. Array creation is really a two-step process, in which the memory is first allocated using new, and the individual values are then set. We could say:

acctarr[0] = myacct;
acctarr[1] = youracct;
acctarr[2] = new Account(2000, 14141);

and so forth to fill in the various slots in the acctarr. We can also use explicit initialization, which creates an array and fills in its values at the same time. The following statement, for example, creates an array of four floating-point values:

float fltarr[] = { 3.14159, 2.71828, 1.4141, 0.7071 };

In each of these cases, we may get the length of the array using the instance variable, so both iarr.length and acctarr.length are 10, while fltarr.length is 4. The valid elements of the array range from index 0 through index (length-1). An out-of-bounds error results if any other elements are accessed.

Caution
It is often worthwhile to check an array reference to make sure that it is in bounds. This can be accomplished using an if test against the length member, as follows:
if ( 0 <= idx && idx < arr.length )
   ok to use arr[idx];

The other grievous mistake in Java is to attempt to set an array element to any type other than its base type. Therefore, any member of iarr[] must be an int, any member of acctarr[] must be an instance of the Account class, and every member of fltarr must be a float. A statement such as fltarr[2] = "pi" generates a Java exception.

Java Statements

So far, we have said very little about statements in Java. You have no doubt noticed that, in each of the previous listings, Java statements greatly resemble JScript statements. Java has a few extra rules, though, and also a few new statement types that are not supported in JScript. There are also some JScript constructions that cannot be done or can be done only very awkwardly in Java. The reader is strongly encouraged to review Chapter 2 "JScript: The Language," particularly the section on "Control Structures" and the discussion of "Operator Precedence."

Because Java follows almost the same set of rules as JScript, we will not attempt an exhaustive discussion of those rules. Instead, we will focus on a few of the major differences. As mentioned quite early in this chapter, Java statements must be terminated with a semicolon. While this is a matter of style in JScript, it is mandatory in Java. If you omit the semicolons, Java attempts to interpret your program as a single gigantic statement, to your eternal embarrassment.

It is already apparent that Java has the if statement; it also has the while and for statements of JScript. Java has three more very interesting control structures that are not present in JScript: the do...while statement, the switch statement, and a variant on the break and continue statements that takes a label. In compensation, Java does not have the for...in statement of JScript. The reason for this latter omission has to do with the more circumscribed way that Java defines objects, as we have just seen.

The do…while Statement. The while statement in Java and the while statement in JScript are identical. Both evaluate their while clause and then execute the while body only if the conditional in the while clause was true. This means that the while body may be executed an infinite number of times, once, or not at all. If we were foolish enough to write:

while ( false ) {
find the meaning of life;
}

the while body would never be executed. The valid but meaningless while ( false ) would never be used in practice, of course, but it is quite possible to have a while clause that does evaluate to false immediately. This is unfortunate in cases where it is desirable to execute the while body at least once.

The do...while statement solves this problem. A do...while statement still contains a while body and a while test, but the while test is at the end, ensuring that the body of the do...while loop is executed at least once. The format of this statement is as
follows:

do {
while-body;
} while ( conditional ) ;

Caution
The semicolon at the end of the while clause in a do...while statement is mandatory. The usual rule that the closing brace of a { } code body terminates the body does not apply to the do...while statement, because the while clause must occur after the closing brace.

The switch Statement. The switch case secondval: statement is used to select one alternative from a set of possible choices. It is designed to be a more compact form of the if...else construction, particularly in cases where there are many possibilities. The format of the switch statement is shown in Listing 10.9.


Listing 10.9  The Java switch Statement
switch ( numberthing ) {
     case firstval:
          statements;
          break;
          statements;
          break;
          ...
     default:
          statements;
     break;
}

Unlike the other conditional statements, the numberthing element inside the switch test is not a logical value, it is a numerical value. In particular, it must be a numerical value whose underlying type is byte, short, char, or int. The value of the numberthing is compared against each of numerical values in the case statements. Note that each case statement ends with a colon (:). This is mandatory. If it finds a match, it executes the statements after the case statement but before the first break statement. If none of the case clauses provides a match, it looks for a clause of the form:

default:

which matches anything that is not otherwise matched. In this situation, all the statements between the default and the next break statement are executed. As an example, consider the balance method in Listing 10.8. It does a three-way test on its argument which. This three-way test can be easily rewritten as a switch statement; the code is shown in Listing 10.10.

Tip
Default cases in switch statements are not required, but are recommended. They often catch otherwise mysterious errors.


Listing 10.10  The Account.balance Method Rewritten Using the switch Statement
int balance(int pword, int which) {
     int retval;                    // 2; local variable for return
     if ( pword != password )     // 3; incorrect password
          return( -1 );           // 4; return bogus balance
     switch ( which ) {        // 5; switch on the value of "which"
          case Account.CHECKING:  // 6; which == Account.CHECKING
               retval = ivegot;   // 7; checking balance
               break;             // 8; done with checking case
          case Account.SAVINGS:   // 9; which == Account.SAVINGS
               retval = ivegotsav;  // 10; savings balance
               break;               // 11; done with savings case
          default:               // 12; which has any other value
               retval = (-2);    // 13; return code indicates an error
               break;            // 14; done with the default case
          }                      // 15; end of switch statement
     return(retval);             // 16; return the return code
}                              

This version of the balance method performs the usual password test, and then immediately enters a switch, in statement 5. The numerical value being tested is which, which is an int. If the value of which is Account.CHECKING, then the case Account.CHECKING: statement at line 6 matches, and statement 7 is executed:

case Account.CHECKING:      // 6; which == Account.CHECKING
       retval = ivegot;     // 7; return code is checking balance
       break;               // 8; done with checking case

This assigns the checking account balance ivegot to the local variable retval. The break statement at line 8 is then executed. Like any good break statement, it directs the flow of control to the first statement after the switch, namely statement 16, which returns retval.

If which has the other valid value Account.SAVINGS, a similar block of code is executed, which gives retval the value of the savings account balance ivegotsav instead (lines 10 and 11). If which has any value other than Account.CHECKING or Account.SAVINGS, then the default case, at line 12, matches and statements 13 and 14 execute, as follows:

default:               // 12; which has any other value
    retval = (-2);     // 13; return code indicates an error
    break;             // 14; done with the default case

In any case, the code ends up at line 16 with retval having one of the two valid values, ivegot or ivegotsav, or the error value -2. In a situation such as this, where there are only three possible alternatives, the amount of code saved by using a switch statement versus multiple if...else statements is minimal. If there had been a few more alternatives, the savings would have been dramatic, however.

Troubleshooting
I have a very simple switch statement that examines an integer variable i. Based on the value of i, it sets a local variable j. For some reason, the two cases i==1 and i==2 always give the same result, even though they have different code in their case blocks. What is wrong? The code looks like this:
switch ( i ) {
     case 1:
          j = 2*i;
     case 2:
          j = 3*i;
          break;
     ...
}
You have made the most common error in using a switch statement. There is no break statement to conclude case 1. When i is equal to 2, the statement j = 3*i is executed, and j gets the value 6, as it should. However, when i is equal to 1, the statement j = 2*i is executed, and then the statement j = 3*i is also executed, so that j has the incorrect value 3 rather than the correct value 2.
The switch statement is more than happy to execute multiple blocks of code. The only way it knows to stop is when it encounters a break statement. The presence of another case statement, as you have included, won't even slow it down. This is known as "falling through" a case statement. Sometimes this is desirable, but usually it is just an error.

The Labeled break and continue Statements. With the if, while, for, and the new switch statement, Java has a rich collection of techniques for controlling statement execution. Java also has one more trick up its sleeve, which can prove very valuable in cases where there are many nested conditionals. It might seem like overkill to add more and more new control structures, since this often leads to confusion. There is a school of thought that says everything can, and should, be reduced to just a single type control, such as while. This may be accurate in a purely theoretical sense, but it often is impractical.

On the other hand, it is also true that multiple control structures, particularly nested ones, can be hard to manage. If you have a for inside an if inside a while, and you say break, where do you go? You certainly know by now that the correct answer is that the break sends you to the first statement after the while block, wherever that is. This may be the correct answer, but it is often not the answer you want. If some kind of error or exceptional condition occurs, or if you have finally completed a calculation, you might want just to exit completely from the for, if, and while blocks. This is a situation in which many long for a goto statement.

Java does not have a goto statement. It does have a mechanism for going to an arbitrary location when a break or continue statement is executed. This is known as the labeled break or labeled continue statement, because the keyword is followed by a label that indicates the desired destination. Listing 10.11 shows a very peculiar set of Java code that illustrates the labeled break.


Listing 10.11  Using the Labeled break in Java
int i, j, k, w;
outtahere:                              // 2; label
for(i=0;i<200;i++) {
     if ( i%3 == 0 ) {
          j = 7*i; k = 0;
          while ( k++ < j ) {
               if ( k == 29 )        // eureka!
                    break outtahere; // 8; this gets us out of here
          }                          // end of while
     }                               // end of if
}                                    // end of for
w = j;                // 12; this is where you will actually end up

Note that the label outtahere must come before the outermost loop, at statement 2. When the labeled break of statement 8 is executed, control actually flows to the first statement after the outermost (for) block, at statement 12 (which is w = j; in this example). This counterintuitive structure is necessary since the label must occur before any statement that uses it. Note also that the label must end with a colon (:).

Think of the label outtahere as a name for the next statement, which is the entire mass of the for statement in this case. A labeled break goes to the first statement after the labeled statement, while a labeled continue goes back to the labeled statement. If statement 8 had said continue outtahere, then the mathematical madness of Listing 10.11 would be started all over again.

Developing Java Applets

We have now learned a considerable amount about the Java language itself. The next topic to consider is how it can be used on a Web page. The answer is surprisingly different from the JScript approach. Writing JScript is almost like writing HTML. You fire up your favorite text editor or HTML Wizard, create JScript event handlers and utility functions, link them to events on a Web page, and you are done. When you load the page, the JScript is executed when events arrive.

Java is fundamentally different. JScript is (almost) always interpreted, meaning that the Web browser analyzes the text content of the JScript code on-the-fly, as it is needed. Java, on the other hand, is a compiled language. Java source is never included directly m®a Web page. Instead, a special APPLET tag is used to reference Java code in a special binary format.

The Java Development Cycle

Java is actually both compiled and interpreted, as contradictory as that seems. To understand how this is possible, we must examine the process used to develop Java code. The first step, of course, is to write Java source code. We have already seen a substantial amount of Java source in the various listings in this chapter. If we were writing JScript, we would now be almost done, because we could embed the code directly on a Web page. With Java, we must first convert the source in a binary format, known as Java bytecodes.

One of the fundamental principles of Java is that it is architecture neutral: It can run on any type of machine with a Java-capable Web browser. This goal could not be met if Java were compiled into Intel 486 binaries, or Sparc-5 binaries, or any specific machine's binary format. Instead, Java is compiled into the binary format for an abstract (or virtual) machine. For quite a while, this virtual machine did not have a physical counterpart-it was simply an abstract instruction set. In March 1996, however, Sun Microsystems announced that it would begin construction on a set of "Java microprocessors," which will actually run the Java instruction set directly. Every other machine must still translate the Java instructions into its own native instructions, however.

When we write Java, we must therefore perform three steps, as follows:

The second step of this process requires that we use a Java compiler to create Java binary code. There are several compilers available; the simplest, and one of the most widely used, is part of a set of tools from Sun known as the Java Development Kit (JDK). The third step makes use of the APPLET HTML tag. These two steps are discussed in the next two sections. First, the question of why Java is both interpreted and compiled is still open.

The answer is that we, the Java programmers, compile Java into its abstract binary format, but the Web browsers must then interpret that format. When a Web browser accesses a page that contains an APPLET tag specifying Java code, the Web browser fetches the binary version of that code (not the Java source). The Web browser must then interpret those abstract instructions to do real work on a real machine. After all, if you have Internet Explorer running under Windows 95 on a Pentium, and IE tries to hand the Java bytecodes to the Pentium chip, the Pentium chip will spurn them.

Java Compilers and the JDK

The Java Development Kit, or JDK, is a simple set of command-line-driven tools for manipulating Java source and binary files. The JDK was the first such set of tools, but is not the only such set. In fact, there are now many sophisticated graphical development environments for Java. Because the JDK is the simplest and still one of the most widely used Java development environments, this section describes it in some detail.

It is also important to realize that there are several different versions of the JDK. The Macintosh version of the JDK has no command-line interface, for example. It is beyond the scope of this book to provide a comprehensive description of all the tools in the JDK, or to discuss the differences between the various versions. However, we will at least mention all its major components, which are as follows:

If you use the JDK, the appletviewer and javac tools are the two you will use the most often, at least at the beginning of your Java career. The appletviewer is an application that can be used to view Java applets outside of any Web browser. Usually, you write a Java applet, compile it using the Java compiler javac, and then test it using the appletviewer. The appletviewer frees you from having to debug both your HTML and your Java code at the same time. It is also useful in tracking down browser-dependent bugs, since appletviewer is not itself a browser. The appletviewer and the Java compiler javac are available on all platforms supported by the JDK.

The JDK can be downloaded free from Sun Microsystems' site at http://www.javasoft.com. The JDK is available for many popular platforms, including Windows 95, Windows NT, Solaris 2.4 and 2.5, Linux and several other versions of UNIX, and the Macintosh. This list will no doubt continue to grow, so you are advised to check the javasoft Web site regularly for the latest information.

Components of the JDK. The unfortunately named java application is a Java interpreter. If you give the java application a Java binary file, it executes the contents of that file. This application is not really of interest to us, since it is primarily used to test and execute stand-alone Java applications rather than applets. Java is a large enough language that it is possible to write full-blown applications in Java. java is then used to execute them.

The javadoc application automatically generates HTML documentation from Java source code. It looks for specially formatted comments with the source, and uses those to construct the corresponding documentation. We will see a few simple examples of such comments in the next chapter.

The javah application is used when you want to mix Java code with C or C++ code. javah generates .h include files that allow Java, C, and C++ to interoperate. At the moment, Java applets are forbidden from using modules written in any language other than Java (known as native methods), so javah is not of interest to us. Java enforces this prohibition for security reasons.

javap is the Java profiler. It allows you to instrument Java code to discover which portions of it are taking the most time. jdb is the Java debugger. It permits symbolic debugging of Java binaries. Once you are a bit further along the Java learning curve, you may well want to explore these tools further.

The Java Compiler. The javac tool is the Java compiler. It is invoked by giving it the name of one or more Java source files. If the files contain valid Java, they will be converted to the binary format of the Java instruction set. Let us take the source code of Listing 10.8, contained in the file ex10_8.java on the CD-ROM, and make a very tiny change-modify the class declaration to say public class Account instead of class Account. If we do this and then attempt to compile it using the following statement:

javac ex10_8.java

the Java compiler complains, with a message saying that the public class Account must be defined in a file called 'Account.java'. Well, if it must, then it must. If we oblige and rename the file to Account.java (which can also be found on the CD-ROM), and then try:

javac Account.java

It succeeds, and the file Account.class is created. Files with the suffix .class are Java binary files. This seemingly peculiar restriction on the file name of the source code for a public class is something that must simply be tolerated in this revision of the JDK. In addition, we must make the Account class be a public class if we wish to refer to it in other files. Finally, there is no flexibility in the name of the binary output file, either. The compiled version of the public Account class must be contained in a file named Account.class. The underlying reasons for these file name restrictions are complex, and cannot really be explained without a long and painful discussion of Java internals. For our purposes, we will simply accept these rules, which are summarized in the Note that follows.

Note
Public classes in Java should follow these rules:
  • Put only one public class definition in a Java source file.
  • The name of the source file must match the name of the public class.
  • Do not rename the compiled output file. It must be the name of the public class, followed by the suffix .class.

Other Java Development Environments. For a long time, the JDK was the only game in town. Because Java was developed by Sun, it is only natural to expect that Sun's development environment would be the first and also the most comprehensive. Because of Java's explosive popularity, though, a number of other environments have been created. Some are free, like the JDK, while others are commercial products.

One effect of Java's overwhelming growth rate is that any list or description of Java tools would be hopelessly out of date before it could be printed. No attempt will be made to present such a list in this book. Instead, the best way to learn about such tools is on the Web itself. There are two resources that can be used to obtain the most up-to-date information.

The Gamelan repository, at http://www.gamelan.com, contains a very large collection of information about Java, JScript, and many other Web-related topics. The Gamelan site boasts several hundred Java entries. Some are simple applet demonstrations, while others are full-blown development tools. Both commercial offerings and public domain code are represented. The Java page is well worth visiting.

After some initial reluctance, Microsoft (http://www.microsoft.com) has also entered the Java arena. Its Java development environment is intended to be fully integrated with the Microsoft philosophy toward software products. This means that it has a visual development environment, similar to Visual Basic and Visual C++. It is also designed to interface smoothly with Microsoft's object system (known as COM and DCOM).

One of the most interesting features that Microsoft supports is the ability to compile Java directly to native machine code, in addition to producing standard .class output files. Of course, the native code will not be platform-independent, but significant performance improvements are obtained. If you will be developing Java on any of the Windows platforms, you should plan on regular visits to Microsoft's Web page for the latest information.

The APPLET Tag

Now that we have a compiled Java file, we are at last approaching the point at which we can actually create a fully functional Java applet. Since Java applets are binary files, there is no way we can literally include them in HTML, as we did using the <SCRIPT>...
</SCRIPT>
block for JScript. Instead, we must use a new HTML tag, the APPLET tag, to reference the Java binaries for our applet.

An APPLET block consists of the following four parts:

An example showing the basic HTML syntax for an APPLET block is shown in Listing 10.12.


Listing 10.12  Example of an APPLET Block in HTML
<APPLET CODE="Something.class" WIDTH=100 HEIGHT=50>
<PARAM NAME="var1" VALUE="5">
<PARAM NAME="othervar" VALUE="somestring">
This alternate text is displayed on Java-impaired browsers
</APPLET>

Mandatory Attributes. The example in Listing 10.12 attempts to load and execute the Java binary code from a file named Something.class given as the value of the mandatory CODE attribute. By default, a Java-capable browser searches for files referenced by CODE relative to the HTML document's BASE, although this search strategy can be changed by the optional attribute CODEBASE, described in the next section.

The mandatory WIDTH and HEIGHT describe the size of the box that is allocated for this applet. The applet may later attempt to change this size itself. The values of the WIDTH and HEIGHT attributes are in pixels. On a Java-enabled browser such as Internet Explorer, the example of Listing 10.12 is drawn inside a box of 100¥50 pixels. Other browsers display the alternative text instead. This alternative text is displayed by Java-impaired browsers. The alignment of the applet's bounding box may be influenced by the optional ALIGN attribute.

Tip
APPLET tags may be enclosed in a heading (<Hn>), paragraph (<P>), or division (<DIV>) block, or some other block delimiter.

Optional Attributes. The APPLET tag also accepts the following optional attributes:

The ALIGN attribute is used to specify the alignment of the applet's bounding box with respect to other adjacent text and graphics. The values of the ALIGN attribute include BOTTOM, MIDDLE, and TOP, much like the IMG tag. They also include an additional set including ABSBOTTOM, ABSMIDDLE, BASELINE, LEFT, RIGHT, and TEXTTOP for more precise control.

The CODEBASE attribute is used to specify an alternative location at which to find the Java binary specified in the CODE attribute. If the value of the CODEBASE attribute is an absolute path, then that path is searched for the Java code. If CODEBASE is specified as a relative path, such as java\classes, then that path is appended to the document's BASE, and the code is sought in that relative location. This is often useful if you want to keep your HTML in one place, and your java binaries in another.

HSPACE and VSPACE are used to define the amount of horizontal and vertical space that should be created as a border for the applet. Both specify a numerical value in pixels. The NAME attribute is used to give the applet a name, which may be completely unrelated to any of the names of the classes it uses. Applet NAMEs are used for applet-to-applet communication, and also reserve a place for the applet in the JScript HTML hierarchy.

Note
The APPLET tag does not currently accept an ALT attribute to specify alternate text for Java-impaired browsers. Such text must be embedded in the <APPLET>...</APPLET> block itself.

The PARAM Tag. The <APPLET>...</APPLET> block may contain any number of PARAM tags. Each PARAM tag takes two attributes: NAME and VALUE. The value of each of these attributes is an uninterpreted string. This is the standard mechanism for passing in initialization parameters from the Web page to a Java applet. Java applets have a special method, called getParameter(), to retrieve such values from their environment. Note that each PARAM tag specifies exactly one parameter.

A Simple Applet

We are now ready to construct a simple Java applet. This applet doesn't do much. In fact, all it does is display a string in color. We will arrange to pass in a string to be displayed using a PARAM tag. This applet shows us most of the fundamental components of Java applet design. The HTML code for a page containing the applet is shown in Listing 10.13, while the code for the applet itself is shown in Listing 10.14. These files are ex10_13.htm and pstr.java, respectively, on the CD-ROM.


Listing 10.13  ex10_13.htm-A Web Page Containing a Simple Applet
<HTML>
<HEAD>
<TITLE>Displaying a String in Java</TITLE>
</HEAD>
<BODY>
<P>
<HR>
<APPLET CODE="PStr.class" WIDTH=400 HEIGHT=40 ALIGN="CENTER">
<PARAM NAME="mystring" VALUE="coconuts">
You will see this text if your browser does not understand Java.
</APPLET>
<HR>
The <A HREF="PStr.java">source</A>
</P>
</BODY>
</HTML>


Listing 10.14  PStr.java-A Java Applet that Displays a String
import java.lang.* ;                // 1; get Java language package
import java.awt.* ;                 // 2; get Java AWT package

public class PStr extends java.applet.Applet { // 3; define applet type
     String userstring = null;               // 4; instance variable

     public void init() {     // 5; called when applet is loaded
// get value of PARAM NAME="mystring"
          userstring = getParameter("mystring");     // 6;
     }
// override built-in paint()
     public void paint( Graphics g ) {       // 8;
          String outstr;
// string concatentation
          outstr = "I've got a lovely bunch of " + userstring;       // 10;
          g.setColor(Color.red);   // 11; set output color to red
// draw the string offset from the corner
          g.drawString(outstr, 10, 10);      // 12;
     }

}

The code in Listing 10.13 should be self-explanatory. An APPLET is declared to be implemented by the CODE at URL PStr.class, relative to the document's BASE. Its dimensions are 100¥40 pixels, and its alignment is CENTER. Some alternative text has been provided after the single PARAM tag, which gives the parameter mystring the value coconuts. A pointer is given to the source PStr.java in an HREF at the end of the <BODY>.

To run this applet, we must create the file PStr.class from the file PStr.java, which is shown in Listing 10.14. This is done using the javac tool, with the command:

javac PStr.java

This command creates the java binary PStr.class. We can now view the results by pointing our favorite Java-capable browser at the file EX10_13.HTML, or by invoking the appletviewer on it using the command appletviewer ex10_13.html. The results of viewing this HTML in Internet Explorer are shown in Figure 10.1.

Figure 10.1 : Java applets allow you to create text and graphics on-the-fly.

Anatomy of an Applet

Just how does the PStr applet work? The code in Listing 10.14 contains a number of new concepts that we describe next. The PStr applet begins with two new statements using the import directive, as follows:

import java.lang.*;
import java.awt.*;

This directive is used to inform the Java compiler that externally defined classes may be needed. Statement 1 says to import java.lang.* ;, where the * is a wildcard indicating all the classes within the package java.lang. A package is a related collection of classes.

Of course, this applet does not use all the classes in the java.lang package, but it does not hurt to overspecify when using an import statement. Only those elements that are actually needed are used. Statement 2 makes a similar request for the java.awt package. The AWT is Java's Abstract Windowing Toolkit, a collection of graphic utilities.

Chapter 11, "More About Java," describes the class in the AWT and shows how several of them are used to load and manage images.

Statement 3 declares the applet's class PStr. As indicated previously, this class name should be the same as the name of the file in which it is found. Rather than being a simple class declaration, however, statement 3 introduces one more new keyword, extends, as follows:

public class PStr extends java.applet.Applet {

Java supports the object-oriented notion of inheritance. This means that classes may be built on other classes, and inherit some of their properties and methods. In this case, the built-in applet class java.applet.Applet is being used as the base class (or superclass), and our customization PStr is the derived class (or subclass). This frees us from having to write a lot of code, which would only duplicate the standard behavior of java.applet.Applet. All applets begin with a declaration of the form:

public class Myclass extents java.applet.Applet { 

The PStr class contains a single instance variable, userstring, declared in statement 4. This variable is of type String, the Java string class. It also contains two methods, init(),and paint(). The init()method is one of four standard methods that are called during the life of an applet. The init method is called when an applet is first loaded, and should be used to perform any one-time initialization. The start method is called when an applet begins running, generally right after init completes. The  stop and destroy methods are called when an applet is stopped (when another page is visited, for example), and when the browser is completely finished with an applet (when it falls off the end of the browser's cache, for example).

This particular applet does not need to do anything when it is started, stopped, or destroyed, so these methods are not provided. In fact, the default java.applet.Applet class provides implementations of all of these methods, so that an applet need not actually provide any of them. The PStr class overrides the init method of its parent java.applet.Applet. A method is overridden when a subclass implements a method that is also implemented in its superclass. When this happens, the method in the subclass is used. Thus, the PStr class uses the superclass implementations of start, stop, and destroy and its own implementation of init.

When the PStr.class file is loaded, the first thing that happens is that the init method is called. The init method executes a single statement (at line 6), as follows:

userstring = getParameter("mystring");

which uses the Java function getParameter(). This function is used to retrieve the value of a PARAM tag whose name is given as an argument. Therefore, if there is a PARAM whose NAME attribute is mystring, the getParameter() call in statement 6 returns the VALUE of that PARAM. If not, it returns null. In our HTML code of Listing 10.13, there is such a parameter and its VALUE is the string coconuts.

Note
PARAM values are always interpreted as strings in Java.

The initialization is now complete, and the method function start from the applet superclass is called next. This method performs a variety of actions which need not concern us here. The most important thing it does from our perspective is that it will eventually arrange to call the paint method, which forces the entire drawing area of the applet to be redrawn. In particular, it forces a call to our paint() method, which this PStr has also overridden. Unlike the init method, which has a void signature, the paint method accepts a single argument, g, which is an instance of the Graphics class. The methods of the Graphics class are used actually to do graphics. The paint method looks like the following:

String outstr;
outstr = "I've got a lovely bunch of " + userstring;  // 10g.setColor(Color.red);                             // 11
g.drawString(outstr, 10, 10);     // 12

Statement 10 constructs the output string outstr by concatenating a constant string with the value of userstring. Note that if userstring had been null, the value of outstr would be the string I've got a lovely bunch of null, since the quantity null is converted to the string null. Statement 11 sets the drawing color to red by using the red (static, final) class variable of the Color class. Finally, statement 12 draws the string outstr in that color. We place the string at relative coordinates (10,10), meaning that the string is offset 10 pixels from the top edge and 10 pixels from the left side of the applet's bounding box.

Even though this applet is extremely simple, it does illustrate all the major aspects of applet design. The more complex applet described in the next section has the same basic components, as do the applets in Chapter 11, "More About Java."

An Accounting Applet in Java

In this section, we examine a slightly more sophisticated Java applet. This applet exercises the Account class that we have meticulously built up in the previous sections of this chapter. Our Java applet uses the PARAM tag mechanism to process a set of transactions. When it is done, it displays an account status in its applet window.

The PARAM mechanism we use is extremely simple. We specify the number of transactions using a PARAM whose NAME is ntrans. The VALUE of this parameter is the total number of transaction parameters to follow. Each one of those PARAMs has a name of the form trans# followed by a number. Thus, the first transaction has PARAM NAME="trans#", the second NAME="trans#2", and so forth. The VALUEs of these transaction parameters encode what we want. If the value is of the form deposit:100, that indicates a deposit of 100, while if it is of the form withdraw:150, that indicates a withdrawal of 150. The Java source for this applet is shown in Listing 10.15. The source code for this applet can be found in the CD-ROM file Acex.java.


Listing 10.15  Acex.java-A Java Applet that Processes Account Transactions
import java.lang.* ;
import java.awt.* ;

public class Acex extends java.applet.Applet {      // 3; class 
     int ntrans = 0;             // 4; number of transactions requested
     int ntransdone = 0;         // 5; number of transactions done
     int ndeposits = 0;          // 6; number of deposits done
     int nwithdrawals = 0;       // 7; number of withdrawals done
     int noverdrafts = 0;             // 8; number of overdrafts
     private Account myacct = null;   // 9; Account instance itself
     private static final int MyPass = 1492;      // 10; secret password

// private method to do 1 transaction
     private void do1trans(String thetrans) {      // 11;
          String numpart;        // 12; numerical part of a transaction
          int wherecolon;        // 13; location of colon separator
          int valu;              // 14; transaction' value
          int len;               // 15; length of string
          boolean ok;            // 16; withdrew ok?

          wherecolon = thetrans.indexOf(":");  // 17; find the sep
          if ( wherecolon <= 0 ) return;    // 18; bad transaction
          len = thetrans.length();          // 19; overall length
// get numerical part
          numpart = thetrans.substring(wherecolon+1, len);     // 20;
          valu = Integer.parseInt(numpart); // 21; convert to int
          if ( valu <= 0 ) return;          // 22; bad transaction
          switch ( thetrans.charAt(0) ) {   // 23; trans type?
// deposit ( 100 = numerical value of "d" )
               case 100:               // 24;
                    myacct.deposit(valu, Account.CHECKING);  // 25;
                    ndeposits++;         // 26; update counters
                    ntransdone++;
                    break;
               case 119:               // 29; withdrawal ( 119 = "w" )
                    ok = myacct.withdraw(MyPass, valu);    // 30;
                    if ( ok == true ) {     // 31; success
                         nwithdrawals++, ntransdone++;     // 32;
} else {               // 33; failure
                         noverdrafts++;     // 34; overdraft
                    }
                    break;
          }                              // 37; end of 
switch
     }                                   // 38; end of do1trans() 
method

     public void init() {                // 39; init method
          String tmp;
          String onetrans;
          int i;

          myacct = new Account(1000, 100, MyPass);     // 43;
          tmp = getParameter("ntrans");  // 44; get # of trans
// if not null then convert to integer and set ntrans
          if ( tmp != null )                    // 45;
               ntrans = Integer.parseInt(tmp);  // 46;
for(i=1;i<=ntrans;i++) {  // 47; for all trans
// try to find the parameter
               onetrans = getParameter("trans#" + i);     // 48;
               if ( onetrans != null )          // 49; if found then..
                    do1trans(onetrans);         // 50; do it
          }
}                                   // 52; end of init()

     public void paint( Graphics g ) {     // 53; paint method
          String msg1, msg2, msg3, msg4;   // 54; temp strings for messages
          int thebalance;                  // 55; final balance
          int loc = 15;                    // 56; drawing location

          thebalance = myacct.balance(MyPass, Account.CHECKING);
// msg1 contains a report on number of transactions requested and performed
          msg1 = "Transactions requested: " + ntrans;
          msg1 += "; transactions performed: " + ntransdone;
// msg2 contains a report on number of deposits and withdrawals done
          msg2 = "Deposits: " + ndeposits;
          msg2 += "; withdrawals: " + nwithdrawals;
          g.setColor(Color.black);            // 62; draw it in black
          g.drawString(msg1, 10, loc);        // 63; first message
          loc += 15;                          // 64; update y
          g.drawString(msg2, 10, loc);        // 65; second message
          loc += 15;                          // 66; update y again
          if ( noverdrafts > 0 ) {  // 67; oops, overdrafts...
               msg3 = "Overdrafts: " + noverdrafts;     // 68; 
               g.setColor(Color.red);    // 69; draw it in panicky red
               g.drawString(10, loc);    // 70; overdraft message
               loc += 15;                // 71; update y
               }
          msg4 = "Balance: " + thebalance;   // 73; balance message
// If the balance is nonzero then draw it in green, otherwise red
          g.setColor(thebalance > 0 ? Color.green: Color.red);
          g.drawString(msg4, 10, loc);       // 75; balance message
     }                                   // 76; end of paint
}                                        // 77; end of 
Acex

The init Method

To understand how this applet works, let us approach it from a functional point of view. We know that the first thing in this applet that is executed is its init() method, which begins on line 39. The following extract shows the first part of the init() method:

String tmp;
String onetrans;
int i;
myacct = new Account(1000, 100, MyPass);     // 43; fire up account
tmp = getParameter("ntrans");   // 44; get # of transactions
// if not null then convert to integer and set ntrans
if ( tmp != null )                           // 45;
      ntrans = Integer.parseInt(tmp);        // 46;

The first thing the init method does is to initialize our Account instance, myacct, with starting balances of 1000 in checking and 100 in savings. It also sets the account password to the private variable MyPass.

This illustrates one very important point about Java. The Account class is referenced indirectly, through its Account constructor. It is not necessary for us to include the Account class code. When the Acex applet is loaded and the init method is called, the Java interpreter within the browser detects that there is a reference to an external class on line 43. It knows that the name of that class must be the same as the name of the constructor. This tells it that it must load the file Account.class actually to call the Account constructor. This works, however, only now that we have made the Account class be public.

This is the reason that we may not put the binary Java code for the Account class in a file named kickme.class, or in any file other than Account.class. If we do, the Java interpreter will not be able to find the class code. Even though the Java language has static binding, it also has dynamic loading. This keeps Java binary files as small as possible, since external classes are loaded only when they are needed. This is very desirable, since those binary files are being accessed across a potentially very slow network.

After the Account class code has been implicitly loaded and the constructor called, the init method then calls the getParameter() function to retrieve the number of transactions, from the parameter "ntrans". If it can find such a parameter, it then attempts to convert that String value into an integer, on line 44. It uses the parseInt method of the Integer class, which has exactly the same purpose as JScript's built-in function of the same name.

Once the init method has completed the initialization of the new Account instance and gotten the number of transactions, it then executes a for loop, beginning on line 47. This code is as follows:

for(i=1;i<=ntrans;i++) {            // 47; for all transactions
// try to find the parameter
    onetrans = getParameter("trans#" + i);     // 48;
    if ( onetrans != null )                    // 49; if found then..
        do1trans(onetrans);                    // 50; do it
    }

It iterates for the number of transactions requested. For each iteration, an attempt is made to find a parameter whose NAME begins with trans#. These parameters contain the transaction requests as their VALUEs. If a parameter of this type is found, the init method makes a call to the private method do1trans() to actually process the transaction.

The do1trans Method

The do1trans method is the workhorse for transaction processing. It accepts a String argument that contains the requested transaction in the form request:amount. To process such a request, it must separate the request type (deposit or withdraw), which occurs before the colon (:), from the request amount, which occurs after the colon. Let's examine exactly how this works on a request such as "deposit:400." The first few lines of the do1trans() method handle this type of parsing, as follows:

wherecolon = thetrans.indexOf(":");   // 17; find the separator
if ( wherecolon <= 0 ) return;        // 18; bad transaction
len = thetrans.length();              // 19; overall length of string
// get numerical part
numpart = thetrans.substring(wherecolon+1, len);     // 20;
valu = Integer.parseInt(numpart);     // 21; convert it to an int
if ( valu <= 0 ) return;              // 22; bad transaction

In line 17, a call is made to the String method indexOf. This call attempts to find the character index of the colon separator. In our case, that separator is the eighth character, so this method call returns 7 (since character indexing is zero-based). Line 20 uses the String method substring to extract the portion of the transaction string beginning at character index 8 to the end of the string. This is just the string 400 in our case, which, of course, corresponds to the numerical part of the transaction. The result is saved in the local String variable numpart. Line 21 uses the parseInt method again to convert this value from a String to an integer. The next block of code in the do1trans() method is used actually to process the transaction, as follows:

switch ( thetrans.charAt(0) ) {  // 23; type of transaction?
// deposit ( 100 = numerical value of "d" )
     case 100:                   // 24;
          myacct.deposit(valu, Account.CHECKING);     // 25; do it
               ndeposits++;        // 26; update counters
          ntransdone++;
          break;
        case 119:                  // 29; withdrawal ( 119 = "w" )
               ok = myacct.withdraw(MyPass, valu);    // 30;
               if ( ok == true ) { // 31; success; update counters
                    nwithdrawals++, ntransdone++;     // 32;
               } else {               // 33; failure
                    noverdrafts++;    // 34; flag an overdraft
               }
               break;
          }                           // 37; end of switch

The switch statement on line 23 now examines the first character of the transaction string thetrans using the String method charAt. This method returns numerical values, so that we must use the numerical codes for the characters "d" and "w" in the case statements. If the first character is "d" (line 24), then this must be a deposit transaction. Line 25 carries out the transaction, and lines 26 and 27 update the counting variables ndeposits and ntransdone, which record the number of deposits and successful transactions, respectively.

If the first character is "w" (line 29), then this is a withdrawal. We know that withdrawals may fail, so we record the result of calling the withdraw method of the Account class in the local variable ok on line 31. If the withdrawal succeeds, we again update counting variables (line 32). If it fails, we update a different counting variable, noverdrafts, which records the number of attempted overdrafts.

Note that the do1trans method ignores any invalid input. If the input string was deposit:xxx or gag:45, both would be silently rejected. The former would fail the test on line 22, since xxx cannot be successfully parsed as an integer. The latter would simply fall off the end of the switch statement, since the first letter "g" matches neither "d" nor "w."

Note also that the do1trans() also accepts a string of the form deltatron:200 as a deposit request (in the amount of 200), since it examines only the first character of the input. Most of the real syntax checking on deposits and withdrawals that you would find in a genuine accounting package has been eliminated from this example. This was done because the goal of this chapter is to introduce you to Java, not teach you about string parsing or bring you up to date on modern accounting practices. A fully robust version of the do1trans() method would have been many times longer, without any significant new Java content.

The paint Method

Once the init method has been executed, the applet's start method will be called. Once again, the Acex class does not provide its own start method, so that the default applet start method is called. This default start method will attempt to repaint the applet's drawing area, which will ultimately call our paint method. The paint method draws a series of strings in various colors summarizing the transactions. The following is the body of the paint method:

thebalance = myacct.balance(MyPass, Account.CHECKING);  // 57;
msg1 = "Transactions requested: " + ntrans;
msg1 += "; transactions performed: " + ntransdone;
msg2 = "Deposits: " + ndeposits;
msg2 += "; withdrawals: " + nwithdrawals;
g.setColor(Color.black);            // 62; draw it in neutral black
g.drawString(msg1, 10, loc);        // 63; first message
loc += 15;                          // 64; update y coordinate
g.drawString(msg2, 10, loc);        // 65; second message
loc += 15;                          // 66; update y again
if ( noverdrafts > 0 ) {            // 67; oops, overdrafts...
     msg3 = "Overdrafts: " + noverdrafts;     // 68; report how many
       g.setColor(Color.red);       // 69; draw it in panicky red
       g.drawString(10, loc);       // 70; overdraft message
       loc += 15;                   // 71; update y
       }
msg4 = "Balance: " + thebalance;    // 73; balance message
g.setColor(thebalance > 0 ? Color.green: Color.red);  // 74
g.drawString(msg4, 10, loc);        // 75; balance message

It gets the current account balance (line 57), and then constructs two strings recording the number of transactions requested, the number actually processed, and the total number of deposits and withdrawals (lines 58 to 61). It displays these strings in basic black (lines 62 to 66). Note that the x-coordinate of the strings is the same-it is always 10-while the y-coordinate, stored in the variable loc, is incremented after each call to drawString. This ensures that the strings are not drawn on top of one another.

Having displayed this basic information, it next checks to see whether any overdrafts occurred, on line 67. If they did, it constructs a message indicating how many (line 68), sets the drawing color to red (line 69), and then draws that string (line 70). It also
updates the y-coordinate for the next draw on line 71. Finally, the current balance is
displayed. The color this string uses is determined by comparing the balance to 0. If the balance is greater than 0, green is used, while if it is 0, red is used (line 74). The final balance string is drawn in line 75.

Executing the Account Example Applet

To execute this Java applet, we must do two things: We must compile it and place the code in the appropriate directory, and we must also create some appropriate HTML that invokes it. The applet is compiled using the command:

javac Acex.java

which creates the binary file Acex.class. This must be placed in the same directory with the binary Account.class file, because that file needs to be loaded to resolve the various references to methods in the Account class. Finally, we must have a small piece of HTML that issues some transactions. This is shown in Listing 10.16 (the CD-ROM file is ex10_16.html). The result of browsing this tiny Web page is shown in Figure 10.2.


Listing 10.16  ex10_16.html-Executing the Accounting Applet on a Web Page
<HTML>
<HEAD>
<TITLE>Using the Accounting Applet</TITLE>
</HEAD>
<BODY>
<P>
<HR>
<APPLET CODE="Acex.class" WIDTH=400 HEIGHT=400 ALIGN="CENTER">
<PARAM NAME="ntrans" VALUE="5">
<PARAM NAME="trans#1" VALUE="withdraw:400">
<PARAM NAME="trans#2" VALUE="deposit:10">
<PARAM NAME="trans#3" VALUE="withdraw:900">
<PARAM NAME="trans#4" VALUE="withdraw:330">
<PARAM NAME="trans#5" VALUE="deposit:250">
You will see this text if your browser does not understand Java.
</APPLET>
<HR>
The Example <A HREF="Acex.java">source</A>.
<BR>
The <A HREF="Account.java">Account</A> base class.
</P>
</BODY>
</HTML>

Figure 10.2 : The Java Accounting applet processes transactions in vivid color.