Skip to main content

Section 3.2 Passing Information to an Object

Subsection 3.2.1 Accessor and Mutator Methods

In object-oriented programming, class definitions usually provide public methods to set and get the values 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.

Figure 3.2.2. Set/Get methods

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.

Subsection 3.2.2 Defining and Invoking a Method

There are two steps to using a method. First, you must define the method, writing a method definition, such as

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.

Once a method has been defined, you can invoke or call the method by writing a method call statement, such as

SimpleClass object = new SimpleClass();
object.printStr("HelloWorld");

This statement calls an object's printStr() method and passes it the string “HelloWorld”.

Activity 3.2.1.

Try this out in the active code below. Try changing the string in the main method and run it again.

Subsection 3.2.3 Parameters

Let's turn back to our Nim game. In the OneRowNim class, we defined three mutator methods named takeOne(), takeTwo(), and takeThree in the previous chapter. All three of these method change the values of the instance variables nSticks and player and have very similar code. The definition of the takeOne() is:

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

The only difference in the code 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.

Consider the following definition for a takeSticks() method:

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

In the following figure, you can see how a call to takeSticks(2) saves the value 2 in the parameter variable num which is used in the method. 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 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.

Figure 3.2.4. Argument to Parameter Mapping

Activity 3.2.2.

Run the following code to see player 1 take 1 stick and player 2 take 2 sticks. Scroll down to the main method and call the takeSticks method with the argument 3 to take 3 sticks and call report. What would happen if you took more sticks than are left? Try it and see. Our program needs to add some error-checking!

Another example of a mutator method is one in which define 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 sets the values of an objects' instance variables.

If a method uses more than one parameter, use a comma to separate the individual parameter declarations in the method header. 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:

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

Subsection 3.2.4 Local vs. Class Scope

The bodies of the mutator methods in the previous section make use of both instance variables like nSticks and parameter variables like num. It is important to note that there is a 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.

A parameter's scope is limited to the body of the method in which it is declared. Variables that are declared in the body of a method have scope which 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 which are declared in the parameter list of a method's header and which 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.

By contrast, instance variables, class variables, and all methods have scope that extends throughout the entire class, that is, class scope. They can be used in the body of any method and in the expressions that assign initial values to class level variables.

Figure 3.2.7. Argument to Parameter Mapping

There are two restrictions to remember. First, instance variables and instance methods cannot be used in the body of a class static method, 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 that we defined in the previous chapter is an example of such a class method. In that case, to test the instance methods of OneRowNim we first created an instance of OneRowNim and used it to call its instance methods:

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

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.

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().

Subsection 3.2.5 Arguments and Parameters

The new class definition for OneRowNim is given in Listing 3.2.10.

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
Listing 3.2.10. The OneRowNim class definition with takeSticks() method.

Note that 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 the previous chapter, 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 didn't use a parameter and we wanted to be able to take away four sticks, or five, or more. If we didn't have parameters, we'd have to write a separate method for each case, which is clearly a bad idea. Using parameters in this way leads to a more general useful method and thus is an example of the generality principle.

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 3 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);

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 was 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 is not an int value

The value that is 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 the term parameter to refer to the formal parameter—the variable used to pass data to a method—that occurs in the method definition. We use the term argument to refer to the actual value that is supplied when the method is invoked.

Subsection 3.2.6 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 Listing 3.2.12. 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.

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()
Listing 3.2.12. A main() method to test the takeSticks() method.

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

Figure 3.2.13. 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.3(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). Notice that the value of nSticks has been reduced to 4.

Activity 3.2.3.

Click on the Show CodeLens button below and then scroll down to click on the Next button to step through the Nim code.

Subsection 3.2.7 Passing keyboard input to takeSticks()

To complete this section, let's modify our main() method in Listing 3.2.12 so that it prompts the user to input an integer from the keyboard and then uses a Scanner object, introduced in the previous chapter, 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.2.14.

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()
Listing 3.2.14. A main() method with keyboard input for OneRowNim.

If we now run this program, the following output will be generated in the console window before waiting for keyboard input:

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

If the user then inputs a 2 from the keyboard, that input will be read and the takeSticks() method will remove 2 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

Activity 3.2.4.

You can try this version of Nim in action below. Look at files at OneRowNim.java on repl to see the OneRowNim class code. Run the following code multiple times and enter 1, 2, or 3.

Exercises 3.2.8 Self-Study Exercises

1. Fill-In Scope.

A parameter variable has scope.

2. Matching Method Vocabulary.

3. setNames().

Modify the OneRowNim class of Figure 3.2.14:

  1. Add two instance variables of type String to store names of the two players. Choose names for the instance variables that would be appropriate for storing names for player one and player two.

  2. Write a method named setNames() with two string parameters which assigns the first parameter to the instance variable that you created for the name of player one. The second parameter should be assigned to the other new instance variable.

  3. Write a statement in the main method that calls the setNames() method of the previous exercise and sets the name of player one of game to “Xena” and sets the name of player two to “Yogi”.

You have attempted of activities on this page.