introducing the players


Theater Computer
   
actors objects
roles classes
props variables
actor names reference values
character names reference variables
lines messages
stage directions statements
scenes methods
scripts programs
audience program users
playwright and director programmer
stage manager and producer java interpreter

The only way to learn how to build Java programs is to build a Java program. So let's get to it.

Before we can create actors we have to describe their behavior and their state, and to do that we must write a class. To write a class we first have to give it a name. That name could be RomeoAndJuliet, Hamlet, TheCherryOrchard, or TheImportanceOfBeingEarnest, but we're not aspiring to art here, just simple engineering. So let's just call it FredsScript.

The names of Java classes look a little odd because all the words are capitalized and joined together. We have to remove all the spaces and punctuation to make the Java interpreter's job easier, but we also want to remember what we meant when we first wrote the script. So to name a class it's usual to describe it (briefly) then run all the words together.

Once we name our class, we then specify the state and behavior of the objects that will obey the class by listing a sequence of statements, or requests to the Java interpreter, all inside braces.
 
Defining a Class

We're ready for our first script. Here it is:


class FredsScript
   {
   }

Not too impressive, true. Right now our script is empty, but this is perfectly legal Java. It will work just fine. Of course, it also won't do anything since we haven't added any statements yet.

So let's put in a few props for any actors following FredsScript to fiddle with.
 
Creating Variables


class FredsScript
   {
   int numberOfApples;
   double applePortions;
   boolean finishedProcessing;
   }

This is another perfectly legal Java class. First, all statements must end with a semicolon. Second, all the statements inside the class definition are indented. Third, variable names look just like class names except that they start with a lower-case letter. The case of a letter matters to the Java interpreter, so FredsScript, Fredsscript, fredsScript, and fredsscript are four different names.

The class now declares three props: one int variable, one double variable, and one boolean variable. These three declaration statements ask the stage manager to give each actor following this script its own copies the above three props.

So far, though, the script doesn't specify anything for actors to do using their copies of those three props. So let's add some behavior:
 
Defining Methods


class FredsScript
   {
   int numberOfApples;
   double applePortions;
   boolean finishedProcessing;

   double divideApplesAmongPeople()
      {
      int numberOfPeople;

      numberOfApples = 6;
      numberOfPeople = 2;
      applePortions = numberOfApples / numberOfPeople;
      finishedProcessing = true;

      return applePortions;
      }
   }

We've now defined a method---a named sequence of actions---that all actors following FredsScript will know how to perform.

When asked to, an object enters a method defined for its class and executes the method (that is, follows the actions that the statements within the method specify) then exits, or "returns from", the method when we ask it to exit with a return statement.

This method, like most other entities that we must describe to the Java interpreter, must have a name and a type.

First, its name is divideApplesAmongPeople, which looks just like a variable name. To distinguish method names from variable names, method names will appear with trailing parenthese, like this: divideApplesAmongPeople(), to show that they're methods and not variables.

Second, its type is double, just like the variable applePortions. There is a difference though; a variable's type specifies what values it can accept, but a method's type specifies what values it can produce. Here, the type of the value that an actor returns when exiting the method will be double. Thus, all the values an actor can produce after executing this method will each belong to the set of double values. So we can put any of those values into a double variable.
 
Specifying the Scope of a Variable

We can declare variables inside methods just as we can declare them inside classes. For example, FredsScript's first variable, numberOfApples, appears at the beginning of FredsScript, but the numberOfPeople variable appears at the beginning of divideApplesAmongPeople(). No matter where we declare a variable though (that is, no matter where we ask the stage manager to produce a variable of that name and type) we can't use it until that point.

If we declare a variable inside a method we can only use it inside the method. The method is the variable's scope. The method divideApplesAmongPeople(), for instance, is numberOfPeople's scope. The scope of the other variables (numberOfApples, applePortions, and finishedProcessing), which we declared outside divideApplesAmongPeople() but inside the class, is the entire class, namely, FredsScript.

In theater terms, each method in a class is like a scene in a play. In that scene an actor may have special props (like numberOfPeople) as well as its usual props; outside that scene it only has its usual props. The props we define inside a scene are local to that particular scene; those we define inside the script as a whole are global to all the script's scenes. A method's local props appear when an actor starts executing the method and vanish when the actor finishes executing that method. An actor's global props exist for as long as the actor exists.

Let's say we're writing a script called MobyDick. An actor following this script, let's call it Ishmael, will always have its own copy of all the global props---say, a sword, a snuff-box, and a wallet. Our prop declarations ask the stage manager to give Ishmael, along with every other actor following the script, its own copy of each of those props. Within a particular method, though, Ishmael is acting specially (perhaps it is method acting?) and so may need special props---say, a boat, a white whale, and a harpoon. Ishmael will always have its (global) sword, snuff-box, and wallet, but for the duration of its time in the particular method it will also have a (local) boat, white whale, and harpoon. Those local props vanish once the actor exits the method.
 
Using Assignments and Operators

To understand divideApplesAmongPeople() fully we also need to know that we can copy the contents of one variable x to another variable y by saying:


   y = x;

This is an assignment statement; it asks the stage manager (the Java interpreter) to copy the value that's inside the box labelled with the name on the right-hand side of the statement then put that copy into the box labelled with the name on the left-hand side. The effect is to copy (or assign) the value currently in variable x (that is, the value in the box named x) to the variable y (the value in the box named y). This wipes out whatever value was previously in y but leaves x's value intact.

Besides copying the values of variables into other variables, we can also put values into variables directly, which is the effect of an assignment statement like:


   numberOfApples = 6;

This puts the value 6, which is of type int since it's a whole number and it lies well within the range minus two billion to plus two billion, into the variable named numberOfApples, whose type is int.

We can also use various operators to compute new values given two or more variables (or operands) and put the result in yet another variable, which is the effect of the statement:


   applePortions = numberOfApples / numberOfPeople;

This statement asks the stage manager to divide the value in the int variable numberOfApples by the value in the int variable numberOfPeople and put the result in the double variable applePortions.

No matter what's on the right-hand side, though, the left-hand side of every assignment statement must be the name of a variable (that is, a box) since the Java interpreter must have somewhere to put the result of the right-hand side.
 
Creating an Actor

Although FredsScript now specifies some state (variables) and behavior (methods), it still does nothing. It looks like it's storing the value 6 in the int variable numberOfApples, the value 2 in the int variable numberOfPeople, dividing the two of them, storing the result in the double variable applePortions, then setting the boolean variable finishedProcessing to true. Then it's somehow returning the result of the division to somebody. In fact, though, nothing at all happens because we don't yet have an actor to ask to do anything.

So let's create an actor that can follow the script FredsScript. This isn't easy, however, because at the beginning of the play there are no actors at all, so we don't yet have an object that we can ask to create another object. We get around this by adding a specially named method that the stage manager responds to. In it we ask the stage manager to create an actor for us and so start the play.


class FredsScript
   {
   int numberOfApples;
   double applePortions;
   boolean finishedProcessing;

   double divideApplesAmongPeople()
      {
      int numberOfPeople;

      numberOfApples = 6;
      numberOfPeople = 2;
      applePortions = numberOfApples / numberOfPeople;
      finishedProcessing = true;

      return applePortions;
      }

   public static void main(String[] parameters)
      {
      FredsScript fred;

      fred = new FredsScript();
      }
   }

The strangely declared main() method is special because it tells the stage manager where the play begins; it's like Act I, Scene I of a script. The stage manager will automatically execute the main() method of any script if we declare it exactly as above.

Although the method is short, a lot has happened on this last step, not all of which is important just this minute. For now, just take away this lesson: in any script, we can talk to the stage manager directly by declaring a main() method exactly as above. Inside that method we can ask the stage manager to create actors using the "new" operator. Think of new as short for createAnActorThatWillObeyTheFollowingScript. We follow the new operator with the name of the script we want the newly created actor to obey.

When the stage manager sees a new operator, which we must follow with some script's name followed by parentheses, it will create an actor for us. Then, it will give that actor a copy of the script we name. Finally, it will create copies of each of the props the script specifies and give them to the actor. The new actor will then have props (variables) to remember its state and actions (methods) to determine its behavior.
 
Naming the Actor

While creating an actor, we must also name it if we're going to refer to it in future, which is the purpose of the left-hand side of the assignment statement:


   fred = new FredsScript();

Here we're calling the new actor fred. Or, more precisely, we're telling the stage manager that we'll be referring to the newly created actor, who will be following FredsScript for the rest of its life, by the reference variable fred. Or, even more precisely, we're asking the stage manager to put a copy of the name of the new actor (which we're simultaneously asking the stage manager to create) into the reference variable named fred.

In theater terms, there's a difference between the name of the character that an actor plays---in this case, the character's name is fred---and that actor's true name. We, the playwright/directors, don't know---and could care less about---any actor's true name; all we need is the name of the character that actor plays. When we say, for instance, "Romeo kisses Juliet", we don't have to care that the real name of the actor playing the Romeo part is Leo DeCaprio. Later on we'll see that we needn't even give an actor a character name. Like extras in a crowd scene, some actors can play nameless roles.

Finally, just as with all the other variables declared earlier (numberOfApples, numberOfPeople, applePortions, and finishedProcessing) we must declare the name and type of the new variable (fred) to the Java interpreter. We do that as follows:


   FredsScript fred;

This declaration tells the Java interpreter that the new variable is a reference variable (since it will contain a reference value, that is a reference to an object), and that its type is FredsScript. Further, since we declare it in main() we can't use it in, say, divideApplesAmongPeople(). It's scope is main(), so that's the only method we can use it in.
 
Sending Messages To the Actor

At last it looks like we finally have a working Java program. Alas, our program still does almost nothing.

To recap, here's what we've done so far:

* We've asked the stage manager to create a new actor and to reference it with variable fred in Scene I of Act I (the main() method).
 
* We've given any such actor some behavior (dividing two values and storing some values) in a divideApplesAmongPeople() method.
 
* And we've even given any such actor some props to play with (three global ones right at the beginning of the script, and two local ones, one inside each of the two methods).
This isn't quite enough, however. Although the object pointed to by reference variable fred exists, and has some props, and knows how to divideApplesAmongPeople(), we haven't sent it a message asking it to divideApplesAmongPeople(). It knows how to behave, but we haven't asked it to behave. So let's do that next:

class FredsScript
   {
   int numberOfApples;
   double applePortions;
   boolean finishedProcessing;

   double divideApplesAmongPeople()
      {
      int numberOfPeople;

      numberOfApples = 6;
      numberOfPeople = 2;
      applePortions = numberOfApples / numberOfPeople;
      finishedProcessing = true;

      return applePortions;
      }

   public static void main(String[] parameters)
      {
      FredsScript fred;

      fred = new FredsScript();

      double portionsPerPerson;

      portionsPerPerson = fred.divideApplesAmongPeople();
      }
   }

In this version of the script, after creating and naming an actor, we send it a message asking it to execute its divideApplesAmongPeople() scene (which, remember, is a method, not a variable, even though it has a type---double, in this case). The actor, following its divideApplesAmongPeople() method, divides the number of apples by the number of people, saves the result, assigns a value to a boolean variable, then returns the portions per person. Then we ask the stage manager to save a copy of that double value in a new local variable, portionsPerPerson.

We can ask any actor to execute any of its methods with the dot operator, as in the statement:


   [actor's name].[actor's method's name];

This statement sends the actor the message: "please execute your such-and-so method." We can ask any actor to send such a message to any other actor, or even to itself, or, as in the main() method of FredsScript, we can ask the stage manager to send a message to an actor.

In this particular case, the actor's true name (which is a reference value) is hidden inside the reference variable named fred, and we wish that actor to execute its divideApplesAmongPeople() method. So the message from the stage manager to fred is:


   fred.divideApplesAmongPeople();

An actor executes its methods only when asked to by another actor (or by itself, or by the stage manager). There is no such thing as an actorless action in Java.
 
Parameterizing Methods

Our program so far is fine as far as it goes, but it's pretty limited because if we want to change the number of people we're dividing apples among we'd have to go in and change the value 2 in the line:


   numberOfPeople = 2;

Instead, the stage manager gives us the option of passing in numberOfPeople to the method as a parameter---something that can vary in value while the method itself remains the same. After all, within the method it doesn't much matter what the number of people are, as long as it's an int.

The method declaration would then become:


   double divideApplesAmongPeople(int numberOfPeople)

This has the same effect as declaring numberOfPeople inside the method as we've been doing so far. The variable numberOfPeople is still an int and it is still local to the method divideApplesAmongPeople().

Parameterizing the method, however, makes it much more flexible since the number of people is no longer fixed at two. If we wanted fred to divide apples among 15 people instead of two, say, we would send it the message:


   fred.divideApplesAmongPeople(15);

Since we declared numberOfPeople as an int in the method declaration we can't ask fred to execute its method with a non-int value like 52.34 or true. The type of the value we send and the type of the variable we declare as a parameter must be the same. The Java interpreter will check that the types match.
 
Adding Multiple Parameters

We can declare any method (except the special version of main()) as taking any number and type of parameters. In particular, we should give fred's method at least one more parameter---the number of apples. That would make it yet more general and would also avoid us from having to go in all the time and make changes to the method directly.

We tell the stage manager that a method takes multiple parameters by listing the parameters separated by commas in the method declaration. As always, we must still declare the name and type of the parameters.

The method would then become:


   double divideApplesAmongPeople(int numberOfApples,
      int numberOfPeople)
      {
      applePortions = numberOfApples / numberOfPeople;
      finishedProcessing = true;

      return applePortions;
      }

Here the declaration of divideApplesAmongPeople() spreads over two lines to keep each line's width down. The Java interpreter doesn't care about lines---it cares about statements. We can continue any statement across any number of lines we wish, so we could just as easily say:


   double
   divideApplesAmongPeople(
   int numberOfApples,
   int numberOfPeople)

and it would have exactly the same effect.

With the new parameter, we could ask fred to divide six apples among two people from within the main() method, by sending fred the message:


   fred.divideApplesAmongPeople(6, 2);

By freeing the method to handle any pair of int values we can now have any actor ask an actor of this class to execute the method with any pair of int values as parameters. The method is no longer specific to the class we originally wrote it for.
 
Returning from Methods

Just as with the original divideApplesAmongPeople() method that accepted no parameters, methods may also return no values. We tell the stage manager that with the word void. An actor executing a void method will never return any values. It will still return of course, but the method it's executing will have no statement like:


   return [variable name];

We can still force an actor executing a void method to return (but with no returned value) by issuing a bare


   return;

statement, with no variable name attached.

Also, since a void method never returns a value, an actor executing it can return for itself once it runs out of statements to execute. This can't happen in a non-void method since we must always tell the stage manager which value the actor must return. So we must always specify a return explicitly once the method isn't void.

The main() method, as now written, is an example of a method that an object exits when there are no more statements for the object to execute rather than when we explicitly ask it to.

This clears up a little of the mystery of the declaration:


   public static void main(String[] parameters)

This statement declares a method named main() that accepts one parameter and returns no values at all. Its sole parameter is passed in to the method from somewhere---from where exactly is still a mystery---and the parameter's type, String[], is also still a mystery.
 
Adding Conditional Behavior

Our program now works fine, but by parameterizing divideApplesAmongPeople() we've laid ourselves open to a problem we couldn't have had before: namely, some actor might misuse the method by asking fred to try to divide some apples by zero or fewer people.

To prevent this we need some way for fred to test the value of numberOfPeople and avoid the division if that value is zero or less. If it's zero or less, fred should refuse to do anything at all and simply return with a value of zero for the method. We can do that with an if statement, as follows:


   double divideApplesAmongPeople(int numberOfApples,
      int numberOfPeople)
      {
      finishedProcessing = false;

      if (numberOfPeople <= 0)
         return 0;

      applePortions = numberOfApples / numberOfPeople;
      finishedProcessing = true;

      return applePortions;
      }

The symbol sequence "<=" is the "less than or equal to" operator, so the statement:


   if (numberOfPeople <= 0)

asks whether the value currently in the variable numberOfPeople is zero or less. If that's true, then fred executes the return statement the if statement encloses, and, thus returns from the method right away. If, on the other hand, numberOfPeople's value is one or more, then fred jumps past the return statement, executes the next statement in sequence (which is the division), and continues on from there as before.

Consequently, whenever the value of numberOfPeople is less than one, fred does nothing when asked to divideApplesAmongPeople(), simply returning zero. Whenever its value is one or more, though, fred obligingly does the division and returns the result.

Because we declare the method as returning a double, every time we ask an actor executing the method to return from the method, we must also specify which double value to return. An actor could never simply return from a method that has a declared return type; it can only do so if the method is void.
 
Printing Output

We're still not quite done. We haven't yet asked anyone, neither the stage manager nor fred, to tell us the result of the computation. So let's modify the main() method as follows to ask the stage manager to print something to the screen:


   public static void main(String[] parameters)
      {
      FredsScript fred;

      fred = new FredsScript();

      double portionsPerPerson;

      portionsPerPerson = fred.divideApplesAmongPeople(6, 2);

      System.out.println("Number of portions per person is: " +
         portionsPerPerson);
      }
   }

Without going into exactly how the last statement works, it's enough to know for now that it asks the stage manager to print the number of portions per person. Also, this statement covers two lines, just as the declaration of divideApplesAmongPeople(). We can stretch any statement across as many lines as we wish. It's wise, however, to indent any continuation lines to make it clear that they're all part of one statement.
 
Accessing Variables

Just as we can send messages to objects asking them to execute their methods, we can also send messages asking them to access their variables. For example, the message:


   fred.finishedProcessing;

asks fred to let us access its copy of its finishedProcessing variable. We can use this capability to improve our program's output.

Recall that if the value of numberOfPeople were zero or less, then after requesting fred to execute its method, the computation would have been unsuccessful and fred's copy of finishedProcessing would have the value false. If, however, the computation were successful, it would have the value true.

Thus we can tell whether our request to fred to divide some apples among some people completed successfully or not by testing fred's copy of the finishedProcessing variable as follows:


   public static void main(String[] parameters)
      {
      FredsScript fred;

      fred = new FredsScript();

      double portionsPerPerson;

      portionsPerPerson = fred.divideApplesAmongPeople(6, 2);

      if (fred.finishedProcessing == false)
         return;

      System.out.println("Number of portions per person is: " +
         portionsPerPerson);
      }
   }

Here we're asking the stage manager to ask fred to divide six apples among two people. Then we test the value of fred's finishedProcessing variable (which is a boolean) to see if it's equal to the boolean value false using the equals operator, the symbol sequence "==". If it's false then fred's computation failed, otherwise the computation succeeded.

If fred's computation were unsuccessful, the stage manager immediately returns from main() (which effectively ends the program). Otherwise the stage manager continues and prints the value of the division, then runs out of statements in main() to execute (which also effectively ends the program). Since main()'s return type is void, we don't return a value from it, so we can end it simply by running out of statements to execute.
 
Adding Comments

It's time to stop and take stock. Creating class FredsScript was a big bite all at once, so let's chew it over a bit before trying to digest it. The Java interpreter ignores everything following the symbol sequence "//" until the end of the line, and it ignores everything, including new lines, between the symbol sequences "/*" and "*/". So we can use those symbol sequences to comment to ourselves to help us remember something, or to explain to other programmers what we're doing.

Here's the entire script again, this time in slow motion replay with comments on each statement to help explain them.


/*
First, we tell the Java interpreter
that we're about to define a new class of objects.
*/

class FredsScript
   {
   /*
   Next we declare the names and types of some variables
   that all of those objects will have their own copies of.

   All three subsequent declarations end with semicolons;
   that's a Java rule: all statements must end in a semicolon
   except for braces, brackets, and parentheses since they
   always come in matched pairs, so the Java interpreter can
   figure out where they end for itself.
   */

   int numberOfApples;
   double applePortions;
   boolean finishedProcessing;

   //We can separate the declaration statements above
   //from the method definitions below with any number
   //of empty lines. We can also add as many comment lines
   //as we want. The Java interpreter will ignore them all.

   //Next comes the definition of the method
   //divideApplesAmongPeople(). To keep the line width down,
   //its declaration spans two lines.

   double divideApplesAmongPeople(int numberOfApples,
      int numberOfPeople)
      {
      /*
      Method definitions go inside braces,
      just like class definitions.

      The variables numberOfApples and numberOfPeople are
      parameters of this method; they are local to the method
      so we cannot use them outside it.

      These comments are indented along with the method
      definition they comment on. Everything inside a definition
      should have the same indentation. This isn't a Java rule
      but it's good style because it makes it easier to see
      the overall structure.
      */

      finishedProcessing = false;

      //If the value of numberOfPeople is impossible,
      //simply return a value of 0 without doing anything.

      if (numberOfPeople <= 0)
         return 0; //return 0 to whoever asked
                   //an actor to execute this method.

      //If we get to this point, the value of numberOfpeople
      //must be one or more, so do the division.

      applePortions = numberOfApples / numberOfPeople;
      finishedProcessing = true;

      //We should separate the following line
      //from the above lines because it's fundamentally
      //different. No assignment or computation is taking
      //place below, it's simply returning a value.
      //Again, this isn't a Java rule, but it's good style.

      return applePortions; //Return the value in applePortions
                            //to whoever asked an actor
                            //to execute this method.
      }

   //Next comes the definition of the (magic) main() method.

   public static void main(String[] parameters)
      {
      //Create a local reference variable and name it fred.

      FredsScript fred;

      //Create an actor and stick its (true) name
      //in variable fred.

      fred = new FredsScript();

      //Reference variable fred now contains a reference
      //value that points to the newly created actor
      //(whose true name we don't know).
      //Now we can send that actor messages using fred
      //as its name.

      //Create a local double variable
      //and name it portionsPerPerson.

      double portionsPerPerson;

      //Send a message to fred asking it to execute its
      //divideApplesAmongPeople() method to divide 6 apples
      //among 2 people and put the double result fred returns
      //into portionsPerPerson.

      portionsPerPerson = fred.divideApplesAmongPeople(6, 2);

      //If the computation was unsuccessful
      //(that is, if fred's copy of finishedProcessing
      //is false), simply end this method.

      if (fred.finishedProcessing == false)
         return;

      //Fred's computation must have completed successfully,
      //otherwise this main() method would have already
      //returned, so print the value of portionsPerPerson.

      //The following statement spans two lines
      //to keep the overall line width reasonable.

      System.out.println("Number of portions per person is: " +
         portionsPerPerson);

      //End the method by running out of statements to execute.
      }
   }


last | | contents | | next