Chapter 11

A Java Tutorial


CONTENTS

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

The difference between JavaScript 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 JavaScript is the lathe.) JavaScript 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 with JavaScript. The basic constructs of Java applets are explored, and some simple examples given.

The Java Language

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

The way in which the two languages handle objects is fundamental to how each is 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 JavaScript. 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 JavaScript are very different under the hood.

Java and JavaScript Compared

In part II of this book, "JavaScript Objects," we take a very close look at objects in JavaScript. JavaScript objects are used to access the built-in mathematical, string, and date functions. JavaScript objects are also used to access and manipulate HTML elements inside JavaScript 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 JavaScript 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 JavaScript the focus is on responding to events. A user action produces an event that triggers a JavaScript 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 JavaScript 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. JavaScript code is more like a Dynamically Loaded Library (DLL) which is activated in response to something.

Finally, we know that JavaScript takes a very relaxed attitude towards 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 only be converted to one another under very well defined conditions, and only by using explicit type conversion functions. Java also enforces static name binding, instead of JavaScript's dynamic binding. It is impossible (so they say) to reference an undefined function.

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 JavaScript. 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 JavaScript counterparts. Every Java statement must end in a semicolon, however. N

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 JavaScript 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 JavaScript myvar is a complete mystery until it is given some value.

There are several differences between the object models of Java and JavaScript, as well as their terminologies. Note that Java refers to its objects as classes, unlike JavaScript. 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 even reflected in the differences in terminology with JavaScript.

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 JavaScript 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 JavaScript

CAUTION
What you see is not necessarily what you get with Unicode. Many browsers and most display devices are not able to properly handle 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 JavaScript variables seem to behave in the same way. Because Java is a strongly typed language, unlike JavaScript, 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 JavaScript. In order to convert between different data types you must use explicit conversion routines. We will 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 which are built up from smaller components. These are classes in Java. They are very similar to JavaScript 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 12, "More About Java." In this section, we discuss the basic concept of a class, and show how they are defined and used.

The Java concept of a class is quite close to the JavaScript 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 to dynamically extend a Java instance, as it is in JavaScript.

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 11.1 shows a very simple Java class definition.


Listing 11.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;
     }
     int balance( ) {          // method for determining how much is
                                    left
          return(ivegot);
     }
     boolean withdraw( int n ) {     // method for attempting to  withdraw money
          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 11.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 JavaScript-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 than 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 11.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 11.2.


Listing 11.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 11.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 itself is 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, then it must declare what type of quantity it is returning in its return type. If the method does not return anything then 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 JavaScript, 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 11.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 11.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 11.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 
}
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
     System.out.println("Insufficient funds");          // 16; print
                                                 
     System.out.println("Balance: " + myacct.balance()); // 17; print
                                                          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 sub-object out of the system object System, and prints a message somehow.

NOTE
The dot operator (.) works the same way in Java and JavaScript. 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 11.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
     System.out.println("Insufficient funds");          // 16; print

     System.out.println("Balance: " + myacct.balance()); // 17; print
                                                          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 non-strings 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. Figure 11.1 displays a time history of the code in listing 11.3.

Figure 11.1 : Java instance variables keep their value throughout the life of an instance.

This example probably raises several questions. Based on your experience with JavaScript 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 11.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 JavaScript. 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 11.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 11.4 shows a revised definition of the Account class which does this. This file is ex11_4.java on the CD-ROM.


Listing 11.4  ex11_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 variable for account  password
     boolean isopen = false;     // 4; account actually has money

     void deposit(int n) {          // 5; any one can deposit
          if ( n > 0 )          // 6; cannot deposit negative money
               ivegot += n;     // 7; do the deposit
/*
   Check account and make sure it is open
*/
          isopen = ( ivegot > 0 ? true : false );     // 8; update  isopen
     }                         // end of deposit method

     int balance(int pword) {     // 10; password protected balance  method
          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

     boolean withdraw(int pword, int n) {  // 16; password protection   here too
          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 the class's 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 then the actual balance is returned via the statement return(ivegot) on line 12. If they do not match then -1 is returned in statement 14. Note that since 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, since 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) then the local variable ok is set to false. If ok remains true then 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 only be accessed within the body of the method in which they are declared. N

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 can also deposit as much money as he likes.

We still do not have any way of simulating the real life experience of opening an account, since 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 JavaScript, this would seem to be the natural approach. In JavaScript, you call new on a function, and pass it rguments 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 11.5 shows the code for a constructor for Account which performs these two operations.


Listing 11.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, since 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 11.6 shows a modified version of the Account constructor, which checks the initial deposit and makes sure that it is at least 100.


Listing 11.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 then the same three initialization statements of listing 11.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 then 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 then 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 11.6 to perform that operation. We now need another constructor that will open both a checking and a savings account. Listing 11.7 shows this new constructor. Note that it references a new private instance variable named ivegotsav, which holds the savings account balance.


Listing 11.7  An Alternate Constructor for the Account Class

Account(int initdep, int initsdep, int newpword) { // 3 argument  constructor
     if ( initdep >= 100 && initsdep >= 1 ) {  // minimum 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 11.6 and 11.7 can both be used. Java tells them apart by virtue of the fact that their argument lists are different. The constructor of listing 11.6 takes two int arguments, while that of listing 11.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 methods. n

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 accounts. 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 11.8 which shows our final version of the Account class. This file is ex11_8.java on the CD-ROM.


Listing 11.8  ex11_8.java  A Fully Functional Version of the

Account Class

class Account {               // Account Class
     private int ivegot = 0;     // 2; amount on deposit in checking   account
     private int ivegotsav = 0;     // 3; amount on deposit in savings  account
     private int password = 29;     // 4; account password
     public boolean isopen = false;   // 5; account actually 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; minimum deposit  requirement met
               ivegot = initdep;          // 11; initialize checking  acct
               password = newpword;          // 12; set acct password isopen = true;
			                         // 13; the acct is open for  business
               }
          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 minima; don't open  account
     }                              // 27; end of 3 arg constructor
// deposit method: any one can deposit anywhere ( no password )
     void deposit(int n, int which) {          // 28;
          if ( n <= 0 ) return;          // 29; negative deposit  forbidden
          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
     }                              // 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 value for  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
          isopen = ( (ivegot+ivegotsav) > 0 ? true : false ); // 51;  open?
          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 11.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 JavaScript, in the Date object.

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 then 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 then 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 only permitted to withdraw 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 JavaScript arrays end 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 which is not really yours is to declare an array, say int i[10], and then look at elements like 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 JavaScript.

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 represent 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 in each of the previous listings that Java statements greatly resemble JavaScript statements. Java has a few extra rules, and also a few new statement types that are not supported in JavaScript. There are also some JavaScript constructions that cannot be done, or can only be done very awkwardly, in Java. The reader is strongly encouraged to review chapter 2, "JavaScript: The Language," particularly the section on "Control Structures" and the discussion of "Operator Precedence."

Since Java follows almost the same set of rules as JavaScript 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 JavaScript, 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 JavaScript. Java has three more very interesting control structures which are not present in JavaScript: the do...while statement, the switch statement, and a variant on the break and continue statements which take a label. In compensation, Java does not have the for...in statement of JavaScript. 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 JavaScript 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 the case that 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, since the while clause must occur after the closing brace.

The switch Statement  The switch 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 case there are many possibilities. The format of the switch statement is shown in listing 11.9.


Listing 11.9  The Java switch Statement

switch ( numberthing ) {
     case firstval:
          statements;
          break;
     case secondval:
          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 the numerical values in the case statements. Note that each case statement ends with a colon (:). This is mandatory. If it finds a match then it executes the statements after the case statement but before the first break statement. If none of the case clauses provides a match then 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 11.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 11.10.

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


Listing 11.10  The Account.balance Method Rewritten Using

the switch Statement

int balance(int pword, int which) {         // password protected  balance method
     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; return code is checking  balance
               break;               // 8; done with checking case
          case Account.SAVINGS:          // 9; which == Account.SAVINGS
               retval = ivegotsav;     // 10; return code is 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
}                              // 17; end of the balance method

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 then 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 just want 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, since the keyword is followed by a label that indicates the desired destination. Listing 11.11 shows a very peculiar set of Java code which illustrates the labeled break.


Listing 11.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 state-ment 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 which 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 11.11 would have 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 JavaScript approach. Writing JavaScript is almost like writing HTML. You fire up your favorite text editor, create JavaScript event handlers and utility functions, link them to events on a Web page, and you are done. When you load the page, the JavaScript is executed when events arrive.

Java is fundamentally different. JavaScript is (almost) always interpreted, meaning that the Web browser analyzes the text content of the JavaScript code on-the-fly, as it is needed. Java, on the other hand, is a compiled language. Java source is never included directly on 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 JavaScript we would now be almost done, since 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 in 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 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 Netscape running under Windows 95 on a Pentium, and Netscape 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 set of tools for manipulating Java source and binary files. The JDK was the first such set of tools, but is not the only set. Since the JDK is still the most widely used Java development environment, this section describes it in some detail. Other Java compilation environments are discussed at the end of this section.

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, and does not support the same set of capabilities as the Solaris version, 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 how each has been customized for various platforms. However, we will at least mention all its major components, which are as follows:

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 http://www.javasoft.com.Currently, the JDK is available for 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 javasoft's 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 files that allow Java, C, and C++ to interoperate. At the moment Java applets are forbidden to use 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 will certainly 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 then they will be converted to the binary format of the Java instruction set. Let us take the source code of listing 11.8, contained in the file ex11_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 ex11_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 filename 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. n

Other Java Development Environments  For a long time the JDK was the only game in town. Since Java was developed by Sun it is only natural to expect that its development environment would be the first, and also the most comprehensive. Because of Java's explosive popularity, 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 which 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, JavaScript, and many other Web-related topics. Their 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. Their Java page is well worth visiting.

After some initial reluctance Microsoft (http://www.microsoft.com) has also entered the Java arena. Their Java development environment is known as Jakarta. It is intended to be fully integrated with the Microsoft philosophy towards software products. This means that it will have 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).

One of the most interesting features that Microsoft has announced 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 can be expected. 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 JavaScript. 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 11.12.


Listing 11.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  This example in listing 11.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 the example of listing 11.12 is drawn inside a box of 100 ¥ 50 pixels. Other browsers instead display the alternate text This alternate text is displayed by Java-impaired browsers. The alignment of the applet's bounding box may be influenced by the optional ALIGN attribute.

TIP
The APPLET tag is not an HTML block attribute. APPLET tags should be enclosed in a heading (<Hn>), paragraph (<P>), 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 alternate 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 wish 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 JavaScript HTML hierarchy. This point is explored further in chapter 12, "More About Java," in the section on "JavaScript to Java Communication."

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. N

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 11.13, while the code for the applet itself is shown in listing 11.14. These files are ex11_13.html and PStr.java, respectively, on the CD-ROM.


Listing 11.13  ex11_13.html  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="cocoanuts">
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 11.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 our 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;
     }
// called when applet starts
     public void start() {                    // 8;
          Dimension d = preferredSize();     // 9; get preferred size
          resize(d);                    // 10; make applet that size
          repaint();           // 11; redraw the screen - calls paint()
     }
// override built-in paint()
     public void paint( Graphics g ) {          // 13;
          String outstr;
// string concatentation
          outstr = "I've got a lovely bunch of " + userstring;       // 15;
          g.setColor(Color.green);          // 16; get output color to 		 green
// draw the string offset from the corner
          g.drawString(outstr, 10, 10);          // 17;
     }
}

The code in listing 11.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 alternate text has been provided after the single PARAM tag, which gives the parameter mystring the value cocoanuts. 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 Cstr.class from the file PStr.java, which is shown in listing 11.14. This is done using the javac tools, 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 browswer at the file ex11_13.html, or by invoking the appletviewer on it using the command "appletviewer ex11_13.html." The results of viewing this HTML in Netscape are shown in figure 11.2.

Figure 11.2 : 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 11.14 contains a number of new concepts which 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 wild card 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.

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 three methods, init(), start(), and paint(). The init() and start() methods are two 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. There are two other complementary methods, stop and destroy, which 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 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 and start methods 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 stop and destroy and its own implementations of init and start.

When the PStr.class file is loaded the first thing that happens is 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 11.13 there is such a parameter, and its VALUE is the string "cocoanuts."

NOTE
PARAM values are always interpreted as strings in Java. N

The initialization is now complete, and the method function start is called next. This function performs three actions, as follows:

Dimension d = preferredSize();     // 9
resize(d);                         // 10
repaint();                         // 11

In statement 9 it gets the preferred size of the applet's drawing area using the Java function preferredSize(). This returns the WIDTH and HEIGHT as specified in the applet tag in the form of an instance d of the class Dimension. This value is immediately passed to the Java function resize() which attempts to ensure that the applet's drawing area is that size. These two statements are not strictly necessary, but are good examples of defensive programming.

The final statement of the start method is statement 11. This statement calls the Java function repaint(), which forces the entire drawing area of the applet to be redrawn. In particular, it forces a call to the paint() method, which this PStr has also overridden. Unlike the init and start methods, which both have void signatures, the paint method accepts a single argument, g, which is an instance of the Graphics class. The methods of the Graphics class are used to actually do graphics. The paint method looks like the following:

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

Statement 15 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 16 sets the drawing color to red by using the red (static, final) class variable of the Color class. Finally, statement 17 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 we describe in the next section has the same basic components, as do the applets of chapter 12.

An Accounting Applet in Java

In this section we examine a slightly more sophisticated Java applet. This applet exercises the Account class which 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#1", 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 it is of the form "withdraw:150", that indicates a withdrawal of 150. The Java source for this applet is shown in listing 11.15. The source code for this applet can be found in the CD-ROM file Acex.java.


Listing 11.15  Acex.java  A Java Applet That Processes Account Transactions

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

public class Acex extends java.applet.Applet {      // 3; declaration of  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  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
          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;  try it
                    if ( ok == true ) {     // 31; success; update  counters
                         nwithdrawals++, ntransdone++;     // 32;
} else {               // 33; failure
                         noverdrafts++;          // 34; flag an  overdraft
                    }
                    break;
          }                              // 37; end of switch
     }                                   // 38; end of do1trans() method
     public void init() {                         // 39; init method
          String tmp;
          myacct = new Account(1000, 100, MyPass);     // 41; fire up  account
          tmp = getParameter("ntrans");        // 42; get # of  transactions
// if not null then convert to integer and set ntrans
          if ( tmp != null )                    // 43;
               ntrans = Integer.parseInt(tmp);     // 44;
     }                                   // 45; end of init()
     public void start() {                         // 46; start method
          String onetrans;                    // 47; will hold one  transaction
          int i;
          for(i=1;i<=ntrans;i++) {               // 49; for all  transactions
// try to find the parameter
               onetrans = getParameter("trans#" + i);     // 50;
               if ( onetrans != null )          // 51; if found then..
                    do1trans(onetrans);          // 52; do it
          }
          resize(preferredSize());               // 54; request  preferred size
          repaint();                         // 55; force repaint
     }                                   // 56; end of start()

     public void paint( Graphics g ) {               // 57; paint method
          String msg1, msg2, msg3, msg4;   // 58; temp strings for  messages
          int thebalance;                    // 59; final balance
          int loc = 15;                         // 60; 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);            // 66; draw it in neutral  black
          g.drawString(msg1, 10, loc);               // 67; first  message
          loc += 15;                         // 68; update y coordinate
          g.drawString(msg2, 10, loc);               // 69; second  message
          loc += 15;                         // 70; update y again 
		  if ( noverdrafts > 0 ) {               // 71; oops,  overdrafts...
               msg3 = "Overdrafts: " + noverdrafts;     // 72; report  how many
               g.setColor(Color.red);          // 73; draw it in panicky  red
               g.drawString(10, loc);          // 74; overdraft message
               loc += 15;                    // 75; update y
               }
          msg4 = "Balance: " + thebalance;          // 77; 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);               // 79; balance  message
     }                                   // 80; end of paint
}                                        // 81; 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 body of the init() method:

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

The first thing the init method does is 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 41. 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 over the network to actually call the Account constructor. This only works, however, 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 only loaded 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 JavaScript's built-in function of the same name.

TIP
Many Java methods are the same in JavaScript

The start Method

Once the init method completes the start method is called. The start method executes a for loop, beginning on line 49. The body of the start method is as follows:

String onetrans;                    // 47; will hold one transaction
int i;
for(i=1;i<=ntrans;i++) {            // 49; for all transactions
// try to find the parameter
    onetrans = getParameter("trans#" + i);     // 50;
    if ( onetrans != null )                    // 51; if found then..
        do1trans(onetrans);                    // 52; do it
    }
resize(preferredSize());           // 54; request preferred size
repaint();                         // 55; force repaint

It iterates for the number of transactions requested. If the init method did not set the ntrans value, it will have its default value of 0 (given in the instance variable section of the class definition, on line 4). 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 start method makes a call to the private method do1trans() to actually process the transaction. When all transactions are complete the start method requests that the applet's drawing area be resized to its preferred size (line 54) and then forces a repaint (line 55).

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 to actually 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; try  it
               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 only examines 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

After the start method has finished calling do1trans, it forces the paint method to be called by invoking repaint. 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);  // 61;
msg1 = "Transactions requested: " + ntrans;
msg1 += "; transactions performed: " + ntransdone;
msg2 = "Deposits: " + ndeposits;
msg2 += "; withdrawals: " + nwithdrawals;
g.setColor(Color.black);            // 66; draw it in neutral black
g.drawString(msg1, 10, loc);        // 67; first message
loc += 15;                          // 68; update y coordinate
g.drawString(msg2, 10, loc);        // 69; second message
loc += 15;                          // 70; update y again
if ( noverdrafts > 0 ) {            // 71; oops, overdrafts...
     msg3 = "Overdrafts: " + noverdrafts;     // 72; report how many
       g.setColor(Color.red);       // 73; draw it in panicky red
       g.drawString(10, loc);       // 74; overdraft message
       loc += 15;                   // 75; update y
       }
msg4 = "Balance: " + thebalance;    // 77; balance message
g.setColor(thebalance > 0 ? Color.green : Color.red);  // 78
g.drawString(msg4, 10, loc);        // 79; balance message

It gets the current account balance (line 61), and then constructs two strings recording the number of transactions requested, the number actually processed, and the total number of deposits and withdrawals (lines 62 to 65). It displays these strings in basic black (lines 66 to 70). 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 if any overdrafts occurred on line 71. If they did it constructs a message indicating how many (line 72), sets the drawing color to red (line 73), and then draws that string (line 74). It also updates the y coordinate for the next draw on line 75. 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 then green is used, while if it is 0, red is used (line 78). The final balance string is drawn in line 79.

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, since 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 11.16 (the CD-ROM file ex11_16.html). The result of browsing this tiny Web page is shown in figure 11.3.

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


Listing 11.16  ex11_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>