Section 3.2. Passing Information to an Object


[Page 104 (continued)]

3.2. Passing Information to an Object

One convention of object-oriented programming is to provide public methods to set and get the values of some of its private instance variables. Methods that set or modify an object's instance variables are called mutator methods. Methods that get or retrieve the value of an instance variable are called accessor methods.

Effective Design: Accessor and Mutator Methods

An accessor method is a public method used to get the value of an object's instance variable. Such methods are often named getVarName(), where VarName is the name of the variable being accessed. A mutator method is a public method used to modify the value of one or more instance variables. The special type of mutator method that sets, or assigns, a variable a specified value is often called setVarName().


It is up to the designer of the class to determine which private variables require accessor and mutator methods. If you were designing a BankAccount class, you might want a public getAccountNumber() method, so that clients could retrieve information about their bank accounts, but you would probably not want a public getAccountPassword() method or a public setAccountBalance() method.

In the remainder of this section, we will be concerned with mutator methods. We defined three mutator methods named takeOne(), takeTwo(), and takeThree as part of the OneRowNim class in the preceding chapter. All three of these methods change the values of the instance variables nSticks and player. All three methods have very similar bodies. The definition of the takeOne() is:

public void takeOne() {  nSticks = nSticks - 1;    player = 3 - player; } 



[Page 105]

The only difference in the bodies of the other two methods is that they subtract 2 and 3 from nSticks instead of 1. Instead of having three virtually identical methods, it would be a more efficient design to define a single method where the number to be subtracted from nSticks would be supplied as an argument when the method is called. In order to be able to handle such an argument, we must design a new method that uses a parameter to handle the argument.

A formal parameter, or more simply a parameter, is a variable used to pass information into a method when the method is invoked. The type and variable name of the formal parameter must appear in the formal parameter list that follows the method's name in the method header. The formal parameter is used to hold a value that it is passed while the method is executing.

Formal parameter


Java Language Rule: Formal Parameter

A formal parameter is a variable that serves as a storage location for information passed to a method. To specify a formal parameter, you must provide a type identifier followed by a variable identifier, and you must place this declaration inside the parentheses that follow the method's name.


Consider the following definition for a takeSticks() method:

public void takeSticks(int num) {  nSticks = nSticks - num;    player = 3 - player; } 


Note that executing the body of takeSticks() when the parameter num stores the value 1 accomplishes precisely the same task as executing takeOne(). If, instead, a value of 2 or 3 is stored in num, then calling the method acts either like takeTwo() or takeThree() respectively. Thus, using parameters enables us to design methods that are more general in what they do, which is an important principle of good program design.

Another example of a mutator method is one that defines a set method to allow the starting number of sticks to be set for an instance of OneRowNim. For this, we could define:

public void setSticks(int sticks) {    nSticks = sticks; } // setSticks() 


As we will see in Section 3.3, we can also define a constructor method that can be used when the game is created to set the initial value of nSticks. It is often desirable to have more than one method that can set the values of an object's instance variables.

If a method uses more than one parameter, separate the individual parameter declarations in the method header with commas. For example, if we wanted a method for OneRowNim that specified both the number of sticks for the start of a game and which player takes a turn first, it could be defined as:

public void setGame(int sticks, int starter) {   nSticks = sticks;     player = starter; } // setGame() 



[Page 106]

The Scope of Parameters, Variables, and Methods

The bodies of the mutator methods in the preceding section make use of both instance variables and parameters. There is an important difference in where these two types of variables can be used. The scope of a variable or method refers to where it can be used in a program.

Scope


A parameter's scope is limited to the body of the method in which it is declared. Variables declared in the body of a method have scope that extends from the point where they are declared to the end of the block of code in which they are declared. Parameters are local variables declared in the parameter list of a method's header. They have initial values specified by the arguments in a method call. The scope of a parameter is the same as the scope of a variable declared at the very beginning of the body of a method. Once the flow of execution leaves a method, its parameters and other local variables cease to exist. The scope of local variables is referred to as local scope.

Local scope


Java Language Rule: Scope

Local variables, that is, parameters and variables declared in the body of a method, have local scope that extends from the point where they are defined to the end of the block of code in which they are defined. In particular, the scope of a parameter is the entire body of the method in which it is declared.


By contrast, instance variables, class variables, and all methods have scope that extends throughout the entire class. This is known as class scope. They can be used in the body of any method and in expressions that assign initial values to class-level variables. There are two restrictions to remember. First, instance variables and instance methods cannot be used in the body of a class method, one modified with static, unless an instance of the class is created there, and then the dot notation of qualified names must be used to refer to the variable or method. This is because class methods are called without reference to a particular instance of the class. The main() method of the OneRowNim class defined in Chapter 2 is an example of such a class method. In that case, we tested the instance methods of OneRowNim by creating an instance of OneRowNim and using it to call its instance methods:

OneRowNim game = new OneRowNim();  // Create instance game.report();                     // Call an instance method 


Class scope


The second restriction involved in class scope is that one class-level variable can be used in the expression that initializes a second class-level variable only if the first is declared before the second. There is no similar restriction on methods.

Java Language Rule: Scope

Class-level variables, that is, instance variables and class variables, have class scope, which extends throughout the class. Methods also have class scope.


Except for the restrictions noted above, methods and class-level variables can be referred to within the same class by their simple names, with just the method (or variable) name itself, rather than by their qualified names, with the dot operator. Thus, in OneRowNim, we can refer to nSticks and report() in the bodies of other instance methods. In a class method, such as main(), we would have to create an instance of OneRowNim with a name like game and refer to game.report().

Simple vs. qualified names



[Page 107]

Java Language Rule: Qualified Names

Within the same class, references to class methods or class variables can be made in terms of simple names. Within the bodies of instance methods, references to instance variables and references to other instance methods can also be made in terms of simple names. However, within the bodies of class methods, qualified names, or dot notation, must be used to refer to instance methods or instance variables just as they are referred to in other classes.


Debugging Tip: Scope Error

It would be a syntax error to refer to a method's parameters or other local variables from outside the method.


3.2.1. Arguments and Parameters

The new class definition for OneRowNim is given in Figure 3.1. Now that we have a single method, takeSticks(), that can be used to take away a variable number of sticks, we have removed the three methods we wrote in Chapter 2, takeOne(), takeTwo(), and takeThree(), from OneRowNim. Using a single method, with a parameter, is clearly a better design. To see this, just imagine what we would have to do if we did not use a parameter and we wanted to take away four sticks, or five, or more. If we did not have parameters, we would have to write a separate method for each case, which is clearly a bad idea. Using parameters in this way leads to a more generally useful method and thus is an example of the generality principle.

Figure 3.1. The OneRowNim class definition with takeSticks() method.

public class OneRowNim { private int nSticks = 7;             // Start with 7 sticks    private int player = 1;             // Player 1 plays first    public void takeSticks(int num)    { nSticks = nSticks - num;      player = 3 - player;    } // takeSticks()    public void report()    { System.out.println("Number of sticks left: " + nSticks);      System.out.println("Next turn by player " + player);    } // report() } // OneRowNim1 class 

Now let's consider how we would create a OneRowNim instance and use the new method in the main() method or in a different class. If we want to have an instance of OneRowNim object to remove three sticks on the first move by using the takeSticks() method, we need to pass the int value 3 to the method. In order to effect this action, we would use the following statements:

OneRowNim game = new OneRowNim(); game.takeSticks(3); 



[Page 108]

Because the definition of takeSticks() includes a single int parameter, we must supply a single int value (such as 3) when we invoke it. When the method is invoked, its formal parameter (num) will be set to the value we supply (3). The value we supply does not have to be a literal int value. We can supply any expression or variable that evaluates to an int value. For example:

int val = 7 - 5; game.takeSticks(val); 


In this case, the value being passed to takeSticks() is 2, the value that val has at the time the method call is made.

It would be an error to try to pass a value that is not a int to takeSticks(). For example, each of the following invocations of takeSticks() results in a syntax error:

game.takeSticks();     // no argument is supplied game.takeSticks("3");  // "3" is a String, not an int game.takeSticks(int);  // int not is an int value 


As you will recall from Chapter 0, the value passed to a method when it is invoked is called an argument. Even though the terms argument and parameter are sometimes used interchangeably, it will be useful to observe a distinction. We will use parameter to refer to the formal parameter in the method definitionthe variable used to pass data to a method. We use argument to refer to the actual value supplied when the method is invoked.

Parameter vs. argument


Debugging Tip: Type Error

It would be a syntax error to use an argument whose type does not match the type of its corresponding parameter.


The distinction between parameter and argument is related to the difference between defining a method and invoking a method. Defining a method is a matter of writing a method definition, such as

Defining vs. calling a method


public void printStr(String s) {   System.out.println(s); } 


This definition defines a method that takes a single String parameter, s, and simply prints the value of its parameter. On the other hand, invoking a method is a matter of writing a method call statement, such as

Invoking a method


printStr("HelloWorld"); 


This statement calls the printStr() method and passes it the string "HelloWorld." This notation assumes that the call to the instance method printStr() is made within the body of another instance method of the same class.


[Page 109]

3.2.2. Passing an int Value to a OneRowNim Method

To get a clearer picture of the interaction that takes place when we invoke takeSticks() and pass it an int value, let's write a main() method to test our new version of OneRowNim.

Our first version of main() is shown in Figure 3.2. We will use it to trace how the parameter of takeSticks() interacts with the instance variables nSticks and player. The statements in the main() program simply create an instance of OneRowNim that is referenced by game and invoke the setSticks() method with an argument of 3.

Figure 3.2. A main() method to test the takeSticks() method.

public static void main (String argv[]) {  OneRowNim game;                         // Declare a OneRowNim object     game = new OneRowNim();                // Instantiate the references     game.takeSticks(3);                    // remove 3 sticks } // main() 

To get a clearer understanding of how a parameter works, it will be instructive to trace through the code in main(). Figure 3.3 displays how the states of the instance variables of game and the parameter of takeSticks() interact.

Figure 3.3. Tracing the state of game (a) Just before calling takeSticks(3). (b) Just before executing the body of takeSticks(3). (c) Just after executing the body of takeSticks(3). (d) After flow of control leaves takeSticks().


Executing the first two statements of main() creates the instance game of OneRowNim. Figure 3.2(a) shows the initial state of game. When the takeSticks(3) method call is made, a parameter (which is a local variable) named num is created and the value 3 is stored in it. The state of the instance variables and the parameter are shown in (b). Then the body of takeSticks() is executed. The new state of game is shown in (c). After the flow of control leaves the body of takeSticks() and returns to main(), the memory location which stored the value of the parameter num is released for other uses. The state of game at this point is shown in (d). Note that the value of nSticks has been reduced to 4.

3.2.3. Passing Keyboard Input to takeSticks()

To complete this section, let's modify our main() method in Figure 3.2 so that it prompts the user to input an integer from the keyboard and then uses a Scanner object, introduced in Chapter 2, to read the integer. That integer will then be used as the argument in a call to takeSticks(). These modifications have been incorporated into the revised version of the main() method shown in Figure 3.4. If we now run this program, the following output will be generated in the console window before waiting for keyboard input:


[Page 110]

Number of sticks left: 7 Next turn by player 1 Input 1, 2, or 3 and hit enter: 


Figure 3.4. A main() method with keyboard input for OneRowNim.

import java.util.Scanner; public static void main (String argv[]) { Scanner sc;                             // Declare a Scanner variable   sc = Scanner.create(System.in);         // Instantiate it   OneRowNim game;                         // Declare a OneRowNim variable   game = new OneRowNim();                 // Instantiate it   game.report();                          // Report state of game   System.out.println("Input 1, 2, or 3 and hit enter:");   int num = sc.nextInt();                 // Read an int from keyboard   game.takeSticks(num);                   // Use the value read   game.report();                          // Report state of game } // main() 

If the user then inputs a 2 from the keyboard, that input will be read and the takeSticks() method will remove two sticks. The output in the console window will now look like:

Number of sticks left: 7 Next turn by player 1 Input 1, 2, or 3 and hit enter:2 Number of sticks left: 5 Next turn by player 2 


Self-Study Exercises

Exercise 3.1

Explain the difference between a method declaration and a method invocation.

Exercise 3.2

Explain the difference between a formal parameter and an argument.

Exercise 3.3

Modify the OneRowNim class of Figure 3.4 by adding two instance variables of type String to store the names of the two players. Choose names for the instance variables that would be appropriate for storing names for player 1 and player 2. Write a method named setNames() with two string parameters that assigns the first parameter to the instance variable you created for the name of player 1. The second parameter should be assigned to the other new instance variable.

Exercise 3.4

Write a statement that calls the setName() method of the preceding exercise and sets the name of player 1 of game to "Xena" and the name of player 2 to "Yogi."




Java, Java, Java(c) Object-Orienting Problem Solving
Java, Java, Java, Object-Oriented Problem Solving (3rd Edition)
ISBN: 0131474340
EAN: 2147483647
Year: 2005
Pages: 275

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net