D. Methods: A Deeper Look

Objectives

In this appendix you’ll learn:

• How static methods and fields are associated with classes rather than objects.

• How the method call/return mechanism is supported by the method-call stack.

• How packages group related classes.

• To use random-number generation to implement game-playing applications.

• How the visibility of declarations is limited to specific regions of programs.

• What method overloading is and how to create overloaded methods.

D.1 Introduction

D.2 Program Modules in Java

D.3 static Methods, static Fields and Class Math

D.4 Declaring Methods with Multiple Parameters

D.5 Notes on Declaring and Using Methods

D.6 Method-Call Stack and Activation Records

D.7 Argument Promotion and Casting

D.8 Java API Packages

D.9 Introduction to Random-Number Generation

D.9.1 Scaling and Shifting of Random Numbers

D.9.2 Random-Number Repeatability for Testing and Debugging

D.10 Case Study: A Game of Chance; Introducing Enumerations

D.11 Scope of Declarations

D.12 Method Overloading

D.13 Wrap-Up

Self-Review Exercises | Answers to Self-Review Exercises | Exercises

D.1. Introduction

In this appendix, we study methods in more depth. You’ll see that it’s possible to call certain methods, called static methods, without the need for an object of the class to exist. You’ll learn how to declare a method with more than one parameter. You’ll also learn how Java keeps track of which method is currently executing, how local variables of methods are maintained in memory and how a method knows where to return after it completes execution.

We’ll take a brief diversion into simulation techniques with random-number generation and develop a version of the casino dice game called craps that uses most of the programming techniques you’ve used to this point in the book. In addition, you’ll learn how to declare values that cannot change (i.e., constants) in your programs.

Many of the classes you’ll use or create while developing applications will have more than one method of the same name. This technique, called overloading, is used to implement methods that perform similar tasks for arguments of different types or for different numbers of arguments.

D.2. Program Modules in Java

You write Java programs by combining new methods and classes with predefined ones available in the Java Application Programming Interface (also referred to as the Java API or Java class library) and in various other class libraries. Related classes are typically grouped into packages so that they can be imported into programs and reused. You’ll learn how to group your own classes into packages in Appendix F. The Java API provides a rich collection of predefined classes that contain methods for performing common mathematical calculations, string manipulations, character manipulations, input/output operations, database operations, networking operations, file processing, error checking and many other useful tasks.


Image Software Engineering Observation D.1

Familiarize yourself with the rich collection of classes and methods provided by the Java API (download.oracle.com/javase/6/docs/api/) and reuse them when possible. This reduces program development time and avoids introducing programming errors.


Methods (called functions or procedures in some languages) help you modularize a program by separating its tasks into self-contained units. You’ve declared methods in every program you’ve written. The statements in the method bodies are written only once, are hidden from other methods and can be reused from several locations in a program.

One motivation for modularizing a program into methods is the divide-and-conquer approach, which makes program development more manageable by constructing programs from small, simple pieces. Another is software reusability—using existing methods as building blocks to create new programs. Often, you can create programs mostly from standardized methods rather than by building customized code. For example, in earlier programs, we did not define how to read data from the keyboard—Java provides these capabilities in the methods of class Scanner. A third motivation is to avoid repeating code. Dividing a program into meaningful methods makes the program easier to debug and maintain.

D.3. static Methods, static Fields and Class Math

Although most methods execute in response to method calls on specific objects, this is not always the case. Sometimes a method performs a task that does not depend on the contents of any object. Such a method applies to the class in which it’s declared as a whole and is known as a static method or a class method. It’s common for classes to contain convenient static methods to perform common tasks. For example, recall that we used static method pow of class Math to raise a value to a power in Fig. C.15. To declare a method as static, place the keyword static before the return type in the method’s declaration. For any class imported into your program, you can call the class’s static methods by specifying the name of the class in which the method is declared, followed by a dot (.) and the method name, as in

ClassName.methodName( arguments )

We use various Math class methods here to present the concept of static methods. Class Math provides a collection of methods that enable you to perform common mathematical calculations. For example, you can calculate the square root of 900.0 with the static method call

Math.sqrt( 900.0 )

The preceding expression evaluates to 30.0. Method sqrt takes an argument of type double and returns a result of type double. To output the value of the preceding method call in the command window, you might write the statement

System.out.println( Math.sqrt( 900.0 ) );

In this statement, the value that sqrt returns becomes the argument to method println. There was no need to create a Math object before calling method sqrt. Also all Math class methods are static—therefore, each is called by preceding its name with the class name Math and the dot (.) separator.


Image Software Engineering Observation D.2

Class Math is part of the java.lang package, which is implicitly imported by the compiler, so it’s not necessary to import class Math to use its methods.


Method arguments may be constants, variables or expressions. Figure D.1 summarizes several Math class methods. In the figure, x and y are of type double.

Image

Fig. D.1. Math class methods.

Math Class Constants PI and E

Class Math declares two fields that represent commonly used mathematical constants—Math.PI and Math.E. Math.PI (3.141592653589793) is the ratio of a circle’s circumference to its diameter. Math.E (2.718281828459045) is the base value for natural logarithms (calculated with static Math method log). These fields are declared in class Math with the modifiers public, final and static. Making them public allows you to use these fields in your own classes. Any field declared with keyword final is constant—its value cannot change after the field is initialized. PI and E are declared final because their values never change. Making these fields static allows them to be accessed via the class name Math and a dot (.) separator, just like class Math’s methods. Recall from Section B.4 that when each object of a class maintains its own copy of an attribute, the field that represents the attribute is also known as an instance variable—each object (instance) of the class has a separate instance of the variable in memory. There are fields for which each object of a class does not have a separate instance of the field. That’s the case with static fields, which are also known as class variables. When objects of a class containing static fields are created, all the objects of that class share one copy of the class’s static fields. Together the class variables (i.e., static variables) and instance variables represent the fields of a class. You’ll learn more about static fields in Section F.10.

Why Is Method main Declared static?

When you execute the Java Virtual Machine (JVM) with the java command, the JVM attempts to invoke the main method of the class you specify—when no objects of the class have been created. Declaring main as static allows the JVM to invoke main without creating an instance of the class. When you execute your application, you specify its class name as an argument to the command java, as in

java ClassName argument1 argument2 ...

The JVM loads the class specified by ClassName and uses that class name to invoke method main. In the preceding command, ClassName is a command-line argument to the JVM that tells it which class to execute. Following the ClassName, you can also specify a list of Strings (separated by spaces) as command-line arguments that the JVM will pass to your application. Such arguments might be used to specify options (e.g., a file name) to run the application. As you’ll learn in Appendix E, your application can access those command-line arguments and use them to customize the application.

D.4. Declaring Methods with Multiple Parameters

We now consider how to write your own methods with multiple parameters. Figure D.2 uses a method called maximum to determine and return the largest of three double values. In main, lines 14–18 prompt the user to enter three double values, then read them from the user. Line 21 calls method maximum (declared in lines 28–41) to determine the largest of the three values it receives as arguments. When method maximum returns the result to line 21, the program assigns maximum’s return value to local variable result. Then line 24 outputs the maximum value. At the end of this section, we’ll discuss the use of operator + in line 24.


 1   // Fig. D.2: MaximumFinder.java
 2   // Programmer-declared method maximum with three double parameters.
 3   import java.util.Scanner;
 4
 5   public class MaximumFinder
 6   {
 7      // obtain three floating-point values and locate the maximum value
 8      public static void main( String[] args )
 9      {
10         // create Scanner for input from command window
11         Scanner input = new Scanner( System.in );
12
13         // prompt for and input three floating-point values
14         System.out.print(
15            "Enter three floating-point values separated by spaces: " );
16         double number1 = input.nextDouble(); // read first double
17         double number2 = input.nextDouble(); // read second double
18         double number3 = input.nextDouble(); // read third double
19
20         // determine the maximum value
21         double result = maximum( number1, number2, number3 );
22
23         // display maximum value
24         System.out.println( "Maximum is: " + result );
25      } // end main
26
27      // returns the maximum of its three double parameters          
28      public static double maximum( double x, double y, double z )   
29      {                                                              
30         double maximumValue = x; // assume x is the largest to start
31                                                                     
32         // determine whether y is greater than maximumValue         
33         if ( y > maximumValue )                                     
34            maximumValue = y;                                        
35                                                                     
36         // determine whether z is greater than maximumValue         
37         if ( z > maximumValue )                                     
38            maximumValue = z;                                        
39                                                                     
40         return maximumValue;                                        
41      } // end method maximum                                        
42   } // end class MaximumFinder


Enter three floating-point values separated by spaces: 9.35 2.74 5.1
Maximum is: 9.35


Enter three floating-point values separated by spaces: 5.8 12.45 8.32
Maximum is: 12.45


Enter three floating-point values separated by spaces: 6.46 4.12 10.54
Maximum is: 10.54


Fig. D.2. Programmer-declared method maximum with three double parameters.

The public and static Keywords

Method maximum’s declaration begins with keyword public to indicate that the method is “available to the public”—it can be called from methods of other classes. The keyword static enables the main method (another static method) to call maximum as shown in line 21 without qualifying the method name with the class name MaximumFinderstatic methods in the same class can call each other directly. Any other class that uses maximum must fully qualify the method name with the class name.

Method maximum

In maximum’s declaration (lines 28–41), line 28 indicates that it returns a double value, that the its name is maximum and that it requires three double parameters (x, y and z) to accomplish its task. Multiple parameters are specified as a comma-separated list. When maximum is called (line 21), the parameters x, y and z are initialized with the values of arguments number1, number2 and number3, respectively. There must be one argument in the method call for each parameter in the method declaration. Also, each argument must be consistent with the type of the corresponding parameter. For example, a double parameter can receive values like 7.35, 22 or –0.03456, but not Strings like "hello" nor the boolean values true or false.

To determine the maximum value, we begin with the assumption that parameter x contains the largest value, so line 30 declares local variable maximumValue and initializes it with the value of parameter x. Of course, it’s possible that parameter y or z contains the actual largest value, so we must compare each of these values with maximumValue. The if statement at lines 33–34 determines whether y is greater than maximumValue. If so, line 34 assigns y to maximumValue. The if statement at lines 37–38 determines whether z is greater than maximumValue. If so, line 38 assigns z to maximumValue. At this point the largest of the three values resides in maximumValue, so line 40 returns that value to line 21. When program control returns to the point in the program where maximum was called, maximum’s parameters x, y and z no longer exist in memory.


Image Software Engineering Observation D.3

Variables should be declared as fields only if they’re required for use in more than one method of the class or if the program should save their values between calls to the class’s methods.


Implementing Method maximum by Reusing Method Math.max

The entire body of our maximum method could also be implemented with two calls to Math.max, as follows:

return Math.max( x, Math.max( y, z ) );

The first call to Math.max specifies arguments x and Math.max( y, z ). Before any method can be called, its arguments must be evaluated to determine their values. If an argument is a method call, the method call must be performed to determine its return value. So, in the preceding statement, Math.max( y, z ) is evaluated to determine the maximum of y and z. Then the result is passed as the second argument to the other call to Math.max, which returns the larger of its two arguments.

Assembling Strings with String Concatenation

Java allows you to assemble String objects into larger strings by using operators + or +=. This is known as string concatenation. When both operands of operator + are String objects, operator + creates a new String object in which the characters of the right operand are placed at the end of those in the left operand—e.g., the expression "hello " + "there" creates the String "hello there".

In line 24 of Fig. D.2, the expression "Maximum is: " + result uses operator + with operands of types String and double. Every primitive value and object in Java has a String representation. When one of the + operator’s operands is a String, the other is converted to a String, then the two are concatenated. In line 24, the double value is converted to its String representation and placed at the end of the String "Maximum is: ". If there are any trailing zeros in a double value, these will be discarded when the number is converted to a String—for example 9.3500 would be represented as 9.35.

Primitive values used in String concatenation are converted to Strings. A boolean concatenated with a String is converted to the String "true" or "false". All objects have a toString method that returns a String representation of the object. When an object is concatenated with a String, the object’s toString method is implicitly called to obtain the String representation of the object. ToString can be called explicitly.


Image Common Programming Error D.1

It’s a syntax error to break a String literal across lines. If necessary, you can split a String into several smaller Strings and use concatenation to form the desired String.



Image Common Programming Error D.2

Confusing the + operator used for string concatenation with the + operator used for addition can lead to strange results. Java evaluates the operands of an operator from left to right. For example, if integer variable y has the value 5, the expression "y + 2 = " + y + 2 results in the string "y + 2 = 52", not "y + 2 = 7", because first the value of y (5) is concatenated to the string "y + 2 = ", then the value 2 is concatenated to the new larger string "y + 2 = 5". The expression "y + 2 = " + (y + 2) produces the desired result "y + 2 = 7".


D.5. Notes on Declaring and Using Methods

There are three ways to call a method:

1. Using a method name by itself to call another method of the same class—such as maximum(number1, number2, number3) in line 21 of Fig. D.2.

2. Using a variable that contains a reference to an object, followed by a dot (.) and the method name to call a non-static method of the referenced object—such as the method call in line 13 of Fig. C.3, myGradeBook.displayMessage(), which calls a method of class GradeBook from the main method of GradeBookTest.

3. Using the class name and a dot (.) to call a static method of a class—such as Math.sqrt(900.0) in Section D.3.

A static method can call only other static methods of the same class directly (i.e., using the method name by itself) and can manipulate only static variables in the same class directly. To access the class’s non-static members, a static method must use a reference to an object of the class. Many objects of a class, each with its own copies of the instance variables, may exist at the same time. Suppose a static method were to invoke a non-static method directly. How would the method know which object’s instance variables to manipulate? What would happen if no objects of the class existed at the time the non-static method was invoked? Thus, Java does not allow a static method to access non-static members of the same class directly.

There are three ways to return control to the statement that calls a method. If the method does not return a result, control returns when the program flow reaches the method-ending right brace or when the statement

return;

is executed. If the method returns a result, the statement

return expression;

evaluates the expression, then returns the result to the caller.


Image Common Programming Error D.3

Declaring a method outside the body of a class declaration or inside the body of another method is a syntax error.



Image Common Programming Error D.4

Redeclaring a parameter as a local variable in the method’s body is a compilation error.


D.6. Method-Call Stack and Activation Records

To understand how Java performs method calls, we first need to consider a data structure (i.e., collection of related data items) known as a stack. You can think of a stack as analogous to a pile of dishes. When a dish is placed on the pile, it’s normally placed at the top (referred to as pushing the dish onto the stack). Similarly, when a dish is removed from the pile, it’s always removed from the top (referred to as popping the dish off the stack). Stacks are known as last-in, first-out (LIFO) data structures—the last item pushed (inserted) on the stack is the first item popped (removed) from the stack.

When a program calls a method, the called method must know how to return to its caller, so the return address of the calling method is pushed onto the program-execution stack (sometimes referred to as the method-call stack). If a series of method calls occurs, the successive return addresses are pushed onto the stack in last-in, first-out order so that each method can return to its caller.

The program-execution stack also contains the memory for the local variables used in each invocation of a method during a program’s execution. This data, stored as a portion of the program-execution stack, is known as the activation record or stack frame of the method call. When a method call is made, the activation record for that method call is pushed onto the program-execution stack. When the method returns to its caller, the activation record for this method call is popped off the stack and those local variables are no longer known to the program. If a local variable holding a reference to an object is the only variable in the program with a reference to that object, then, when the activation record containing that local variable is popped off the stack, the object can no longer be accessed by the program and will eventually be deleted from memory by the JVM during “garbage collection.” We discuss garbage collection in Section F.9.

Of course, a computer’s memory is finite, so only a certain amount can be used to store activation records on the program-execution stack. If more method calls occur than can have their activation records stored, an error known as a stack overflow occurs.

D.7. Argument Promotion and Casting

Another important feature of method calls is argument promotion—converting an argument’s value, if possible, to the type that the method expects to receive in its corresponding parameter. For example, a program can call Math method sqrt with an int argument even though a double argument is expected. The statement

System.out.println( Math.sqrt( 4 ) );

correctly evaluates Math.sqrt(4) and prints the value 2.0. The method declaration’s parameter list causes Java to convert the int value 4 to the double value 4.0 before passing the value to method sqrt. Such conversions may lead to compilation errors if Java’s promotion rules are not satisfied. These rules specify which conversions are allowed—that is, which ones can be performed without losing data. In the sqrt example above, an int is converted to a double without changing its value. However, converting a double to an int truncates the fractional part of the double value—thus, part of the value is lost. Converting large integer types to small integer types (e.g., long to int, or int to short) may also result in changed values.

The promotion rules apply to expressions containing values of two or more primitive types and to primitive-type values passed as arguments to methods. Each value is promoted to the “highest” type in the expression. Actually, the expression uses a temporary copy of each value—the types of the original values remain unchanged. Figure D.3 lists the primitive types and the types to which each can be promoted. The valid promotions for a given type are always to a type higher in the table. For example, an int can be promoted to the higher types long, float and double.

Image

Fig. D.3. Promotions allowed for primitive types.

Converting values to types lower in the table of Fig. D.3 will result in different values if the lower type cannot represent the value of the higher type (e.g., the int value 2000000 cannot be represented as a short, and any floating-point number with digits after its decimal point cannot be represented in an integer type such as long, int or short). Therefore, in cases where information may be lost due to conversion, the Java compiler requires you to use a cast operator (introduced in Section C.9) to explicitly force the conversion to occur—otherwise a compilation error occurs. This enables you to “take control” from the compiler. You essentially say, “I know this conversion might cause loss of information, but for my purposes here, that’s fine.” Suppose method square calculates the square of an integer and thus requires an int argument. To call square with a double argument named doubleValue, we would be required to write the method call as

square( (int) doubleValue )

This method call explicitly casts (converts) a copy of variable doubleValue’s value to an integer for use in method square. Thus, if doubleValue’s value is 4.5, the method receives the value 4 and returns 16, not 20.25.

D.8. Java API Packages

As you’ve seen, Java contains many predefined classes that are grouped into categories of related classes called packages. Together, these are known as the Java Application Programming Interface (Java API), or the Java class library. A great strength of Java is the Java API’s thousands of classes. Some key Java API packages used in this book’s appendices are described in Fig. D.4, which represents only a small portion of the reusable components in the Java API.

Image

Fig. D.4. Java API packages (a subset).

The set of packages available in Java is quite large. In addition to those summarized in Fig. D.4, Java includes packages for complex graphics, advanced graphical user interfaces, printing, advanced networking, security, database processing, multimedia, accessibility (for people with disabilities), concurrent programming, cryptography, XML processing and many other capabilities. Many other packages are also available for download at java.sun.com.

You can locate additional information about a predefined Java class’s methods in the Java API documentation at download.oracle.com/javase/6/docs/api/. When you visit this site, click the Index link to see an alphabetical listing of all the classes and methods in the Java API. Locate the class name and click its link to see the online description of the class. Click the METHOD link to see a table of the class’s methods. Each static method will be listed with the word “static” preceding its return type.

D.9. Introduction to Random-Number Generation

We now take a brief diversion into a popular type of programming application—simulation and game playing. In this and the next section, we develop a nicely structured game-playing program with multiple methods. The program uses most of the control statements presented thus far in the appendices and introduces several new programming concepts.

Random numbers can be introduced in a program via an object of class Random (package java.util) or via the static method random of class Math. A Random object can produce random boolean, byte, float, double, int, long and Gaussian values, whereas Math method random can produce only double values in the range 0.0x < 1.0, where x is the value returned by method random. In the next several examples, we use objects of class Random to produce random values. We discuss only random int values here. For more information on the Random class, see download.oracle.com/javase/6/docs/api/java/util/Random.html.

A new random-number generator object can be created as follows:

Random randomNumbers = new Random();

Consider the following statement:

int randomValue = randomNumbers.nextInt();

Random method nextInt generates a random int value in the range –2,147,483,648 to +2,147,483,647, inclusive. If it truly produces values at random, then every value in the range should have an equal chance (or probability) of being chosen each time nextInt is called. The numbers are actually pseudorandom numbers—a sequence of values produced by a complex mathematical calculation. The calculation uses the current time of day (which, of course, changes constantly) to seed the random-number generator such that each execution of a program yields a different sequence of random values.

The range of values produced directly by method nextInt generally differs from the range of values required in a particular Java application. For example, a program that simulates coin tossing might require only 0 for “heads” and 1 for “tails.” A program that simulates the rolling of a six-sided die might require random integers in the range 1–6. A program that randomly predicts the next type of spaceship (out of four possibilities) that will fly across the horizon in a video game might require random integers in the range 1–4. For cases like these, class Random provides another version of method nextInt that receives an int argument and returns a value from 0 up to, but not including, the argument’s value. For example, for coin tossing, the following statement returns 0 or 1.

int randomValue = randomNumbers.nextInt( 2 );

D.9.1. Scaling and Shifting of Random Numbers

To demonstrate random numbers, let’s show to simulate rolling a six-sided die. We begin by using nextInt to produce random values in the range 0–5, as follows:

face = randomNumbers.nextInt( 6 );

The argument 6—called the scaling factor—represents the number of unique values that nextInt should produce (in this case six—0, 1, 2, 3, 4 and 5). This manipulation is called scaling the range of values produced by Random method nextInt.

A six-sided die has the numbers 1–6 on its faces, not 0–5. So we shift the range of numbers produced by adding a shifting value—in this case 1—to our previous result, as in

face = 1 + randomNumbers.nextInt( 6 );

The shifting value (1) specifies the first value in the desired range of random integers. The preceding statement assigns face a random integer in the range 1–6. The numbers produced by nextInt occur with approximately equal likelihood.

Generalizing the Random Number Calculations

The preceding statement always assigns to variable face an integer in the range 1face6. The width of this range (i.e., the number of consecutive integers in the range) is 6, and the starting number in the range is 1. The width of the range is determined by the number 6 that’s passed as an argument to Random method nextInt, and the starting number of the range is the number 1 that’s added to the result of calling nextInt. We can generalize this result as

number = shiftingValue + randomNumbers.nextInt( scalingFactor );

where shiftingValue specifies the first number in the desired range of consecutive integers and scalingFactor specifies how many numbers are in the range.

It’s also possible to choose integers at random from sets of values other than ranges of consecutive integers. For example, to obtain a random value from the sequence 2, 5, 8, 11 and 14, you could use the statement

number = 2 + 3 * randomNumbers.nextInt( 5 );

In this case, randomNumbers.nextInt(5) produces values in the range 0–4. Each value produced is multiplied by 3 to produce a number in the sequence 0, 3, 6, 9 and 12. We add 2 to that value to shift the range of values and obtain a value from the sequence 2, 5, 8, 11 and 14. We can generalize this result as

number = shiftingValue +
   differenceBetweenValues * randomNumbers.nextInt( scalingFactor );

where shiftingValue specifies the first number in the desired range of values, differenceBetweenValues represents the constant difference between consecutive numbers in the sequence and scalingFactor specifies how many numbers are in the range.

D.9.2. Random-Number Repeatability for Testing and Debugging

Class Random’s methods actually generate pseudorandom numbers based on complex mathematical calculations—the sequence of numbers appears to be random. The calculation that produces the numbers uses the time of day as a seed value to change the sequence’s starting point. Each new Random object seeds itself with a value based on the computer system’s clock at the time the object is created, enabling each execution of a program to produce a different sequence of random numbers.

When debugging an application, it’s often useful to repeat the exact same sequence of pseudorandom numbers during each execution of the program. This repeatability enables you to prove that your application is working for a specific sequence of random numbers before you test it with different sequences of random numbers. When repeatability is important, you can create a Random object as follows:

Random randomNumbers = new Random( seedValue );

The seedValue argument (of type long) seeds the random-number calculation. If the same seedValue is used every time, the Random object produces the same sequence of numbers. You can set a Random object’s seed at any time during program execution by calling the object’s set method, as in

randomNumbers.set( seedValue );


Image Error-Prevention Tip D.1

While developing a program, create the Random object with a specific seed value to produce a repeatable sequence of numbers each time the program executes. If a logic error occurs, fix the error and test the program again with the same seed value—this allows you to reconstruct the same sequence of numbers that caused the error. Once the logic errors have been removed, create the Random object without using a seed value, causing the Random object to generate a new sequence of random numbers each time the program executes.


D.10. Case Study: A Game of Chance; Introducing Enumerations

A popular game of chance is a dice game known as craps, which is played in casinos and back alleys throughout the world. The rules of the game are straightforward:

You roll two dice. Each die has six faces, which contain one, two, three, four, five and six spots, respectively. After the dice have come to rest, the sum of the spots on the two upward faces is calculated. If the sum is 7 or 11 on the first throw, you win. If the sum is 2, 3 or 12 on the first throw (called “craps”), you lose (i.e., the “house” wins). If the sum is 4, 5, 6, 8, 9 or 10 on the first throw, that sum becomes your “point.” To win, you must continue rolling the dice until you “make your point” (i.e., roll that same point value). You lose by rolling a 7 before making your point.

Figure D.5 simulates the game of craps, using methods to implement the game’s logic. The main method (lines 21–65) calls the rollDice method (lines 68–81) as necessary to roll the dice and compute their sum. The sample outputs show winning and losing on the first roll, and winning and losing on a subsequent roll.


 1   // Fig. D.5: Craps.java
 2   // Craps class simulates the dice game craps.
 3   import java.util.Random;
 4
 5   public class Craps
 6   {
 7      // create random number generator for use in method rollDice
 8      private static final Random randomNumbers = new Random();
 9
10      // enumeration with constants that represent the game status
11      private enum Status { CONTINUE, WON, LOST };                
12
13      // constants that represent common rolls of the dice
14      private static final int SNAKE_EYES = 2;
15      private static final int TREY = 3;      
16      private static final int SEVEN = 7;     
17      private static final int YO_LEVEN = 11
18      private static final int BOX_CARS = 12
19
20      // plays one game of craps
21      public static void main( String[] args )
22      {
23         int myPoint = 0; // point if no win or loss on first roll
24         Status gameStatus; // can contain CONTINUE, WON or LOST
25
26         int sumOfDice = rollDice(); // first roll of the dice
27
28         // determine game status and point based on first roll
29         switch ( sumOfDice )
30         {
31            case SEVEN: // win with 7 on first roll    
32            case YO_LEVEN: // win with 11 on first roll
33               gameStatus = Status.WON;
34               break;
35            case SNAKE_EYES: // lose with 2 on first roll
36            case TREY: // lose with 3 on first roll      
37            case BOX_CARS: // lose with 12 on first roll 
38               gameStatus = Status.LOST;
39               break;
40            default: // did not win or lose, so remember point
41               gameStatus = Status.CONTINUE; // game is not over
42               myPoint = sumOfDice; // remember the point
43               System.out.printf( "Point is %d ", myPoint );
44               break; // optional at end of switch
45         } // end switch
46
47         // while game is not complete
48         while ( gameStatus == Status.CONTINUE ) // not WON or LOST
49         {
50            sumOfDice = rollDice(); // roll dice again
51
52            // determine game status
53            if ( sumOfDice == myPoint ) // win by making point
54               gameStatus = Status.WON;
55            else
56               if ( sumOfDice == SEVEN ) // lose by rolling 7 before point
57                  gameStatus = Status.LOST;
58         } // end while
59
60         // display won or lost message
61         if ( gameStatus == Status.WON )
62            System.out.println( "Player wins" );
63         else
64            System.out.println( "Player loses" );
65      } // end main
66
67      // roll dice, calculate sum and display results
68      public static int rollDice()
69      {
70         // pick random die values
71         int die1 = 1 + randomNumbers.nextInt( 6 ); // first die roll
72         int die2 = 1 + randomNumbers.nextInt( 6 ); // second die roll
73
74         int sum = die1 + die2; // sum of die values
75
76         // display results of this roll
77         System.out.printf( "Player rolled %d + %d = %d ",
78            die1, die2, sum );
79
80         return sum; // return sum of dice
81      } // end method rollDice
82   } // end class Craps


Player rolled 5 + 6 = 11
Player wins


Player rolled 5 + 4 = 9
Point is 9
Player rolled 4 + 2 = 6
Player rolled 3 + 6 = 9
Player wins


Player rolled 1 + 2 = 3
Player loses


Player rolled 2 + 6 = 8
Point is 8
Player rolled 5 + 1 = 6
Player rolled 2 + 1 = 3
Player rolled 1 + 6 = 7
Player loses


Fig. D.5. Craps class simulates the dice game craps.

Method rollDice

In the rules of the game, the player must roll two dice on the first roll and must do the same on all subsequent rolls. We declare method rollDice (Fig. D.5, lines 68–81) to roll the dice and compute and print their sum. Method rollDice is declared once, but it’s called from two places (lines 26 and 50) in main, which contains the logic for one complete game of craps. Method rollDice takes no arguments, so it has an empty parameter list. Each time it’s called, rollDice returns the sum of the dice, so the return type int is indicated in the method header (line 68). Although lines 71 and 72 look the same (except for the die names), they do not necessarily produce the same result. Each of these statements produces a random value in the range 1–6. Variable randomNumbers (used in lines 71–72) is not declared in the method. Instead it’s declared as a private static final variable of the class and initialized in line 8. This enables us to create one Random object that’s reused in each call to rollDice. If there were a program that contained multiple instances of class Craps, they’d all share this one Random object.

Method main’s Local Variables

The game is reasonably involved. The player may win or lose on the first roll, or may win or lose on any subsequent roll. Method main (lines 21–65) uses local variable myPoint (line 23) to store the “point” if the player does not win or lose on the first roll, local variable gameStatus (line 24) to keep track of the overall game status and local variable sumOfDice (line 26) to hold the sum of the dice for the most recent roll. Variable myPoint is initialized to 0 to ensure that the application will compile. If you do not initialize myPoint, the compiler issues an error, because myPoint is not assigned a value in every case of the switch statement, and thus the program could try to use myPoint before it’s assigned a value. By contrast, gameStatus is assigned a value in every case of the switch statement—thus, it’s guaranteed to be initialized before it’s used and does not need to be initialized.

enum Type Status

Local variable gameStatus (line 24) is declared to be of a new type called Status (declared at line 11). Type Status is a private member of class Craps, because Status will be used only in that class. Status is a type called an enumeration, which, in its simplest form, declares a set of constants represented by identifiers. An enumeration is a special kind of class that’s introduced by the keyword enum and a type name (in this case, Status). As with classes, braces delimit an enum declaration’s body. Inside the braces is a comma-separated list of enumeration constants, each representing a unique value. The identifiers in an enum must be unique. You’ll learn more about enumerations in Appendix F.


Image Good Programming Practice D.1

It’s a convention to use only uppercase letters in the names of enumeration constants. This makes them stand out and reminds you that they are not variables.


Variables of type Status can be assigned only the three constants declared in the enumeration (line 11) or a compilation error will occur. When the game is won, the program sets local variable gameStatus to Status.WON (lines 33 and 54). When the game is lost, the program sets local variable gameStatus to Status.LOST (lines 38 and 57). Otherwise, the program sets local variable gameStatus to Status.CONTINUE (line 41) to indicate that the game is not over and the dice must be rolled again.


Image Good Programming Practice D.2

Using enumeration constants (like Status.WON, Status.LOST and Status.CONTINUE) rather than literal values (such as 0, 1 and 2) makes programs easier to read and maintain.


Logic of the main Method

Line 26 in main calls rollDice, which picks two random values from 1 to 6, displays the values of the first die, the second die and their sum, and returns the sum. Method main next enters the switch statement (lines 29–45), which uses the sumOfDice value from line 26 to determine whether the game has been won or lost, or should continue with another roll. The values that result in a win or loss on the first roll are declared as public static final int constants in lines 14–18. The identifier names use casino parlance for these sums. These constants, like enum constants, are declared by convention with all capital letters, to make them stand out in the program. Lines 31–34 determine whether the player won on the first roll with SEVEN (7) or YO_LEVEN (11). Lines 35–39 determine whether the player lost on the first roll with SNAKE_EYES (2), TREY (3), or BOX_CARS (12). After the first roll, if the game is not over, the default case (lines 40–44) sets gameStatus to Status.CONTINUE, saves sumOfDice in myPoint and displays the point.

If we’re still trying to “make our point” (i.e., the game is continuing from a prior roll), lines 48–58 execute. Line 50 rolls the dice again. If sumOfDice matches myPoint (line 53), line 54 sets gameStatus to Status.WON, then the loop terminates because the game is complete. If sumOfDice is SEVEN (line 56), line 57 sets gameStatus to Status.LOST, and the loop terminates because the game is complete. When the game completes, lines 61–64 display a message indicating whether the player won or lost, and the program terminates.

The program uses the various program-control mechanisms we’ve discussed. The Craps class uses two methods—main and rollDice (called twice from main)—and the switch, while, if...else and nested if control statements. Note also the use of multiple case labels in the switch statement to execute the same statements for sums of SEVEN and YO_LEVEN (lines 31–32) and for sums of SNAKE_EYES, TREY and BOX_CARS (lines 35–37).

Why Some Constants Are Not Defined as enum Constants

You might be wondering why we declared the sums of the dice as public final static int constants rather than as enum constants. The reason is that the program must compare the int variable sumOfDice (line 26) to these constants to determine the outcome of each roll. Suppose we declared enum Sum containing constants (e.g., Sum.SNAKE_EYES) representing the five sums used in the game, then used these constants in the switch statement (lines 29–45). Doing so would prevent us from using sumOfDice as the switch statement’s controlling expression, because Java does not allow an int to be compared to an enumeration constant. To achieve the same functionality as the current program, we would have to use a variable currentSum of type Sum as the switch’s controlling expression. Unfortunately, Java does not provide an easy way to convert an int value to a particular enum constant. This could be done with a separate switch statement. Clearly this would be cumbersome and not improve the program’s readability (thus defeating the purpose of using an enum).

D.11. Scope of Declarations

You’ve seen declarations of various Java entities, such as classes, methods, variables and parameters. Declarations introduce names that can be used to refer to such Java entities. The scope of a declaration is the portion of the program that can refer to the declared entity by its name. Such an entity is said to be “in scope” for that portion of the program. This section introduces several important scope issues.

The basic scope rules are as follows:

1. The scope of a parameter declaration is the body of the method in which the declaration appears.

2. The scope of a local-variable declaration is from the point at which the declaration appears to the end of that block.

3. The scope of a local-variable declaration that appears in the initialization section of a for statement’s header is the body of the for statement and the other expressions in the header.

4. A method or field’s scope is the entire body of the class. This enables non-static methods of a class to use the fields and other methods of the class.

Any block may contain variable declarations. If a local variable or parameter in a method has the same name as a field of the class, the field is “hidden” until the block terminates execution—this is called shadowing. In Appendix F, we discuss how to access shadowed fields.


Image Error-Prevention Tip D.2

Use different names for fields and local variables to help prevent subtle logic errors that occur when a method is called and a local variable of the method shadows a field in the class.


Figure D.6 demonstrates scoping issues with fields and local variables. Line 7 declares and initializes the field x to 1. This field is shadowed (hidden) in any block (or method) that declares a local variable named x. Method main (lines 11–23) declares a local variable x (line 13) and initializes it to 5. This local variable’s value is output to show that the field x (whose value is 1) is shadowed in main. The program declares two other methods—useLocalVariable (lines 26–35) and useField (lines 38–45)—that each take no arguments and return no results. Method main calls each method twice (lines 17–20). Method useLocalVariable declares local variable x (line 28). When useLocalVariable is first called (line 17), it creates local variable x and initializes it to 25 (line 28), outputs the value of x (lines 30–31), increments x (line 32) and outputs the value of x again (lines 33–34). When uselLocalVariable is called a second time (line 19), it recreates local variable x and reinitializes it to 25, so the output of each useLocalVariable call is identical.


 1   // Fig. D.6: Scope.java
 2   // Scope class demonstrates field and local variable scopes.
 3
 4   public class Scope
 5   {
 6      // field that is accessible to all methods of this class
 7      private static int x = 1;                               
 8
 9      // method main creates and initializes local variable x
10      // and calls methods useLocalVariable and useField
11      public static void main( String[] args )
12      {
13         int x = 5; // method's local variable x shadows field x
14
15         System.out.printf( "local x in main is %d ", x );
16
17         useLocalVariable(); // useLocalVariable has local x
18         useField(); // useField uses class Scope's field x
19         useLocalVariable(); // useLocalVariable reinitializes local x
20         useField(); // class Scope's field x retains its value
21
22         System.out.printf( " local x in main is %d ", x );
23      } // end main
24
25      // create and initialize local variable x during each call
26      public static void useLocalVariable()
27      {
28         int x = 25; // initialized each time useLocalVariable is called
29
30         System.out.printf(
31            " local x on entering method useLocalVariable is %d ", x );
32         ++x; // modifies this method's local variable x
33         System.out.printf(
34            "local x before exiting method useLocalVariable is %d ", x );
35      } // end method useLocalVariable
36
37      // modify class Scope's field x during each call
38      public static void useField()
39      {
40         System.out.printf(
41            " field x on entering method useField is %d ", x );
42         x *= 10; // modifies class Scope's field x
43         System.out.printf(
44            "field x before exiting method useField is %d ", x );
45      } // end method useField
46   } // end class Scope


local x in main is 5

local x on entering method useLocalVariable is 25
local x before exiting method useLocalVariable is 26

field x on entering method useField is 1
field x before exiting method useField is 10

local x on entering method useLocalVariable is 25
local x before exiting method useLocalVariable is 26

field x on entering method useField is 10
field x before exiting method useField is 100

local x in main is 5


Fig. D.6. Scope class demonstrates field and local variable scopes.

Method useField does not declare any local variables. Therefore, when it refers to x, field x (line 7) of the class is used. When method useField is first called (line 18), it outputs the value (1) of field x (lines 40–41), multiplies the field x by 10 (line 42) and outputs the value (10) of field x again (lines 43–44) before returning. The next time method useField is called (line 20), the field has its modified value (10), so the method outputs 10, then 100. Finally, in method main, the program outputs the value of local variable x again (line 22) to show that none of the method calls modified main’s local variable x, because the methods all referred to variables named x in other scopes.

D.12. Method Overloading

Methods of the same name can be declared in the same class, as long as they have different sets of parameters (determined by the number, types and order of the parameters)—this is called method overloading. When an overloaded method is called, the compiler selects the appropriate method by examining the number, types and order of the arguments in the call. Method overloading is commonly used to create several methods with the same name that perform the same or similar tasks, but on different types or different numbers of arguments. For example, Math methods abs, min and max (summarized in Section D.3) are overloaded with four versions each:

1. One with two double parameters.

2. One with two float parameters.

3. One with two int parameters.

4. One with two long parameters.

Our next example demonstrates declaring and invoking overloaded methods. We demonstrate overloaded constructors in Appendix F.

Declaring Overloaded Methods

Class MethodOverload (Fig. D.7) includes two overloaded versions of method square—one that calculates the square of an int (and returns an int) and one that calculates the square of a double (and returns a double). Although these methods have the same name and similar parameter lists and bodies, think of them simply as different methods. It may help to think of the method names as “square of int” and “square of double,” respectively.


 1   // Fig. D.7: MethodOverload.java
 2   // Overloaded method declarations.
 3
 4   public class MethodOverload
 5   {
 6      // test overloaded square methods
 7      public static void main( String[] args )
 8      {
 9         System.out.printf( "Square of integer 7 is %d ", square( 7 ) );
10         System.out.printf( "Square of double 7.5 is %f ", square( 7.5 ) );
11      } // end main
12
13      // square method with int argument                              
14      public static int square( int intValue )                        
15      {                                                               
16         System.out.printf( " Called square with int argument: %d ",
17            intValue );                                               
18         return intValue * intValue;                                  
19      } // end method square with int argument                        
20
21      // square method with double argument                              
22      public static double square( double doubleValue )                  
23      {                                                                  
24         System.out.printf( " Called square with double argument: %f ",
25            doubleValue );                                               
26         return doubleValue * doubleValue;                               
27      } // end method square with double argument                        
28   } // end class MethodOverload


Called square with int argument: 7
Square of integer 7 is 49

Called square with double argument: 7.500000
Square of double 7.5 is 56.250000


Fig. D.7. Overloaded method declarations.

Line 9 invokes method square with the argument 7. Literal integer values are treated as type int, so the method call in line 9 invokes the version of square at lines 14–19 that specifies an int parameter. Similarly, line 10 invokes method square with the argument 7.5. Literal floating-point values are treated as type double, so the method call in line 10 invokes the version of square at lines 22–27 that specifies a double parameter. Each method first outputs a line of text to prove that the proper method was called in each case. The values in lines 10 and 24 are displayed with the format specifier %f. We did not specify a precision in either case. By default, floating-point values are displayed with six digits of precision if the precision is not specified in the format specifier.

Distinguishing Between Overloaded Methods

The compiler distinguishes overloaded methods by their signature—a combination of the method’s name and the number, types and order of its parameters. If the compiler looked only at method names during compilation, the code in Fig. D.7 would be ambiguous—the compiler would not know how to distinguish between the two square methods (lines 14–19 and 22–27). Internally, the compiler uses longer method names that include the original method name, the types of each parameter and the exact order of the parameters to determine whether the methods in a class are unique in that class.

For example, in Fig. D.7, the compiler might use the logical name “square of int” for the square method that specifies an int parameter and “square of double” for the square method that specifies a double parameter (the actual names the compiler uses are messier). If method1’s declaration begins as

void method1( int a, float b )

then the compiler might use the logical name “method1 of int and float.” If the parameters are specified as

void method1( float a, int b )

then the compiler might use the logical name “method1 of float and int.” The order of the parameter types is important—the compiler considers the preceding two method1 headers to be distinct.

Return Types of Overloaded Methods

In discussing the logical names of methods used by the compiler, we did not mention the return types of the methods. Method calls cannot be distinguished by return type. If you had overloaded methods that differed only by their return types and you called one of the methods in a standalone statement as in:

square( 2 );

the compiler would not be able to determine the version of the method to call, because the return value is ignored. When two methods have the same signature and different return types, the compiler issues an error message indicating that the method is already defined in the class. Overloaded methods can have different return types if the methods have different parameter lists. Also, overloaded methods need not have the same number of parameters.


Image Common Programming Error D.5

Declaring overloaded methods with identical parameter lists is a compilation error regardless of whether the return types are different.


D.13. Wrap-Up

In this appendix, you learned more about method declarations. You also learned the difference between non-static and static methods and how to call static methods by preceding the method name with the name of the class in which it appears and the dot (.) separator. You learned how to use operators + and += to perform string concatenations. We discussed how the method-call stack and activation records keep track of the methods that have been called and where each method must return to when it completes its task. We also discussed Java’s promotion rules for converting implicitly between primitive types and how to perform explicit conversions with cast operators. Next, you learned about some of the commonly used packages in the Java API.

You saw how to declare named constants using both enum types and public static final variables. You used class Random to generate random numbers for simulations. You also learned about the scope of fields and local variables in a class. Finally, you learned that multiple methods in one class can be overloaded by providing methods with the same name and different signatures. Such methods can be used to perform the same or similar tasks using different types or different numbers of parameters.

In Appendix E, you’ll learn how to maintain lists and tables of data in arrays. You’ll see a more elegant implementation of the application that rolls a die 6,000,000 times and two enhanced versions of our GradeBook case study that you studied in Appendices BC. You’ll also learn how to access an application’s command-line arguments that are passed to method main when an application begins execution.

Self-Review Exercises

D.1 Fill in the blanks in each of the following statements:

a. A method is invoked with a(n) __________.

b. A variable known only within the method in which it’s declared is called a(n) __________.

c. The __________ statement in a called method can be used to pass the value of an expression back to the calling method.

d. The keyword __________ indicates that a method does not return a value.

e. Data can be added or removed only from the __________ of a stack.

f. Stacks are known __________ as data structures; the last item pushed (inserted) on the stack is the first item popped (removed) from the stack.

g. The three ways to return control from a called method to a caller are __________, __________ and __________.

h. An object of class __________ produces random numbers.

i. The program-execution stack contains the memory for local variables on each invocation of a method during a program’s execution. This data, stored as a portion of the program-execution stack, is known as the __________ or __________ of the method call.

j. If there are more method calls than can be stored on the program-execution stack, an error known as a(n) __________ occurs.

k. The __________ of a declaration is the portion of a program that can refer to the entity in the declaration by name.

l. It’s possible to have several methods with the same name that each operate on different types or numbers of arguments. This feature is called method __________.

m. The program-execution stack is also referred to as the __________ stack.

D.2 For the class Craps in Fig. D.5, state the scope of each of the following entities:

a. the variable randomNumbers.

b. the variable die1.

c. the method rollDice.

d. the method main.

e. the variable sumOfDice.

D.3 Write an application that tests whether the examples of the Math class method calls shown in Fig. D.1 actually produce the indicated results.

D.4 Give the method header for each of the following methods:

a. Method hypotenuse, which takes two double-precision, floating-point arguments side1 and side2 and returns a double-precision, floating-point result.

b. Method smallest, which takes three integers x, y and z and returns an integer.

c. Method instructions, which does not take any arguments and does not return a value. [Note: Such methods are commonly used to display instructions to a user.]

d. Method intToFloat, which takes integer argument number and returns a float.

D.5 Find the error in each of the following program segments. Explain how to correct the error.

a.

void g()
{
   System.out.println( "Inside method g" );

   void h()
   {
      System.out.println( "Inside method h" );
   }
}

b.

int sum( int x, int y )
{
   int result;
   result = x + y; }
}

c.

void f( float a );
{
   float a;
   System.out.println( a );
}

D.6 Write a complete Java application to prompt the user for the double radius of a sphere, and call method sphereVolume to calculate and display the volume of the sphere. Use the following statement to calculate the volume:

double volume = ( 4.0 / 3.0 ) * Math.PI * Math.pow( radius, 3 )

Answers to Self-Review Exercises

D.1

a. method call.

b. local variable.

c. return.

d. void.

e. top.

f. last-in, first-out (LIFO).

g. return; or return expression; or encountering the closing right brace of a method.

h. Random.

i. activation record, stack frame.

j. stack overflow.

k. scope.

l. method overloading.

m. method call.

D.2

a. class body.

b. block that defines method rollDice’s body.

c. class body.

d. class body.

e. block that defines method main’s body.

D.3 The following solution demonstrates the Math class methods in Fig. D.1:


 1   // Exercise D.3: MathTest.java
 2   // Testing the Math class methods.
 3
 4   public class MathTest
 5   {
 6      public static void main( String[] args )
 7      {
 8         System.out.printf( "Math.abs( 23.7 ) = %f ", Math.abs( 23.7 ) );
 9         System.out.printf( "Math.abs( 0.0 ) = %f ", Math.abs( 0.0 ) );
10         System.out.printf( "Math.abs( -23.7 ) = %f ", Math.abs( -23.7 ) );
11         System.out.printf( "Math.ceil( 9.2 ) = %f ", Math.ceil( 9.2 ) );
12         System.out.printf( "Math.ceil( -9.8 ) = %f ", Math.ceil( -9.8 ) );
13         System.out.printf( "Math.cos( 0.0 ) = %f ", Math.cos( 0.0 ) );
14         System.out.printf( "Math.exp( 1.0 ) = %f ", Math.exp( 1.0 ) );
15         System.out.printf( "Math.exp( 2.0 ) = %f ", Math.exp( 2.0 ) );
16         System.out.printf( "Math.floor( 9.2 ) = %f ", Math.floor( 9.2 ) );
17         System.out.printf( "Math.floor( -9.8 ) = %f ",
18            Math.floor( -9.8 ) );
19         System.out.printf( "Math.log( Math.E ) = %f ",
20            Math.log( Math.E ) );
21         System.out.printf( "Math.log( Math.E * Math.E ) = %f ",
22            Math.log( Math.E * Math.E ) );
23         System.out.printf( "Math.max( 2.3, 12.7 ) = %f ",
24            Math.max( 2.3, 12.7 ) );
25         System.out.printf( "Math.max( -2.3, -12.7 ) = %f ",
26            Math.max( -2.3, -12.7 ) );
27         System.out.printf( "Math.min( 2.3, 12.7 ) = %f ",
28            Math.min( 2.3, 12.7 ) );
29         System.out.printf( "Math.min( -2.3, -12.7 ) = %f ",
30            Math.min( -2.3, -12.7 ) );
31         System.out.printf( "Math.pow( 2.0, 7.0 ) = %f ",
32            Math.pow( 2.0, 7.0 ) );
33         System.out.printf( "Math.pow( 9.0, 0.5 ) = %f ",
34            Math.pow( 9.0, 0.5 ) );
35         System.out.printf( "Math.sin( 0.0 ) = %f ", Math.sin( 0.0 ) );
36         System.out.printf( "Math.sqrt( 900.0 ) = %f ",
37            Math.sqrt( 900.0 ) );
38         System.out.printf( "Math.tan( 0.0 ) = %f ", Math.tan( 0.0 ) );
39      } // end main
40   } // end class MathTest


Math.abs( 23.7 ) = 23.700000
Math.abs( 0.0 ) = 0.000000
Math.abs( -23.7 ) = 23.700000
Math.ceil( 9.2 ) = 10.000000
Math.ceil( -9.8 ) = -9.000000
Math.cos( 0.0 ) = 1.000000
Math.exp( 1.0 ) = 2.718282
Math.exp( 2.0 ) = 7.389056
Math.floor( 9.2 ) = 9.000000
Math.floor( -9.8 ) = -10.000000
Math.log( Math.E ) = 1.000000
Math.log( Math.E * Math.E ) = 2.000000
Math.max( 2.3, 12.7 ) = 12.700000
Math.max( -2.3, -12.7 ) = -2.300000
Math.min( 2.3, 12.7 ) = 2.300000
Math.min( -2.3, -12.7 ) = -12.700000
Math.pow( 2.0, 7.0 ) = 128.000000
Math.pow( 9.0, 0.5 ) = 3.000000
Math.sin( 0.0 ) = 0.000000
Math.sqrt( 900.0 ) = 30.000000
Math.tan( 0.0 ) = 0.000000


D.4

a. double hypotenuse( double side1, double side2 )

b. int smallest( int x, int y, int z )

c. void instructions()

d. float intToFloat( int number )

D.5

a. Error: Method h is declared within method g.

Correction: Move the declaration of h outside the declaration of g.

b. Error: The method is supposed to return an integer, but does not.

Correction: Delete the variable result, and place the statement

return x + y;

to the method, or add the following statement at the end of the method body:

return result;

c. Error: The semicolon after the right parenthesis of the parameter list is incorrect, and the parameter a should not be redeclared in the method.

Correction: Delete the semicolon after the right parenthesis of the parameter list, and delete the declaration float a;.

D.6 The following solution calculates the volume of a sphere, using the radius entered by the user:


1   // Exercise D.6: Sphere.java
2   // Calculate the volume of a sphere.
3   import java.util.Scanner;
4
5   public class Sphere
6   {
7      // obtain radius from user and display volume of sphere
8      public static void main( String[] args )
9      {
10        Scanner input = new Scanner( System.in );
11        System.out.print( "Enter radius of sphere: " );
12        double radius = input.nextDouble();
13        System.out.printf( "Volume is %f ", sphereVolume( radius ) );
14     } // end method determineSphereVolume
15
16     // calculate and return sphere volume
17     public static double sphereVolume( double radius )
18     {
19        double volume = ( 4.0 / 3.0 ) * Math.PI * Math.pow( radius, 3 );
20        return volume;
21     } // end method sphereVolume
22  } // end class Sphere


Enter radius of sphere: 4
Volume is 268.082573


Exercises

D.7 What is the value of x after each of the following statements is executed?

a. x = Math.abs( 7.5 );

b. x = Math.floor( 7.5 );

c. x = Math.abs( 0.0 );

d. x = Math.ceil( 0.0 );

e. x = Math.abs( -6.4 );

f. x = Math.ceil( -6.4 );

g. x = Math.ceil( -Math.abs( -8 + Math.floor( -5.5 ) ) );

D.8 (Parking Charges) A parking garage charges a $2.00 minimum fee to park for up to three hours. The garage charges an additional $0.50 per hour for each hour or part thereof in excess of three hours. The maximum charge for any given 24-hour period is $10.00. Assume that no car parks for longer than 24 hours at a time. Write an application that calculates and displays the parking charges for each customer who parked in the garage yesterday. You should enter the hours parked for each customer. The program should display the charge for the current customer and should calculate and display the running total of yesterday’s receipts. It should use the method calculateCharges to determine the charge for each customer.

D.9 (Rounding Numbers) Math.floor can be used to round values to the nearest integer—e.g.,

y = Math.floor( x + 0.5 );

will round the number x to the nearest integer and assign the result to y. Write an application that reads double values and uses the preceding statement to round each of the numbers to the nearest integer. For each number processed, display both the original number and the rounded number.

D.10 (Rounding Numbers) To round numbers to specific decimal places, use a statement like

y = Math.floor( x * 10 + 0.5 ) / 10;

which rounds x to the tenths position (i.e., the first position to the right of the decimal point), or

y = Math.floor( x * 100 + 0.5 ) / 100;

which rounds x to the hundredths position (i.e., the second position to the right of the decimal point). Write an application that defines four methods for rounding a number x in various ways:

a. roundToInteger( number )

b. roundToTenths( number )

c. roundToHundredths( number )

d. roundToThousandths( number )

For each value read, your program should display the original value, the number rounded to the nearest integer, the number rounded to the nearest tenth, the number rounded to the nearest hundredth and the number rounded to the nearest thousandth.

D.11 Answer each of the following questions:

a. What does it mean to choose numbers “at random”?

b. Why is the nextInt method of class Random useful for simulating games of chance?

c. Why is it often necessary to scale or shift the values produced by a Random object?

d. Why is computerized simulation of real-world situations a useful technique?

D.12 Write statements that assign random integers to the variable n in the following ranges:

a. 1 ≤n ≤ 2.

b. 1 ≤n ≤ 100.

c. 0 ≤n ≤ 9.

d. 1000 ≤n ≤ 1112.

e. –1 ≤n ≤ 1.

f. –3 ≤n ≤ 11.

D.13 Write statements that will display a random number from each of the following sets:

a. 2, 4, 6, 8, 10.

b. 3, 5, 7, 9, 11.

c. 6, 10, 14, 18, 22.

D.14 (Exponentiation) Write a method integerPower(base, exponent) that returns the value of baseexponent

For example, integerPower(3, 4) calculates 34 (or 3 * 3 * 3 * 3). Assume that exponent is a positive, nonzero integer and that base is an integer. Use a for or while statement to control the calculation. Do not use any Math class methods. Incorporate this method into an application that reads integer values for base and exponent and performs the calculation with the integerPower method.

D.15 (Multiples) Write a method isMultiple that determines, for a pair of integers, whether the second integer is a multiple of the first. The method should take two integer arguments and return true if the second is a multiple of the first and false otherwise. [Hint: Use the remainder operator.] Incorporate this method into an application that inputs a series of pairs of integers (one pair at a time) and determines whether the second value in each pair is a multiple of the first.

D.16 (Even or Odd) Write a method isEven that uses the remainder operator (%) to determine whether an integer is even. The method should take an integer argument and return true if the integer is even and false otherwise. Incorporate this method into an application that inputs a sequence of integers (one at a time) and determines whether each is even or odd.

D.17 (Circle Area) Write an application that prompts the user for the radius of a circle and uses a method called circleArea to calculate the area of the circle.

D.18 (Temperature Conversions) Implement the following integer methods:

a. Method celsius returns the Celsius equivalent of a Fahrenheit temperature, using the calculation

celsius = 5.0 / 9.0 * ( fahrenheit - 32 );

b. Method fahrenheit returns the Fahrenheit equivalent of a Celsius temperature, using the calculation

fahrenheit = 9.0 / 5.0 * celsius + 32;

c. Use the methods from parts (a) and (b) to write an application that enables the user either to enter a Fahrenheit temperature and display the Celsius equivalent or to enter a Celsius temperature and display the Fahrenheit equivalent.

D.19 (Find the Minimum) Write a method minimum3 that returns the smallest of three floatingpoint numbers. Use the Math.min method to implement minimum3. Incorporate the method into an application that reads three values from the user, determines the smallest value and displays the result.

D.20 (Greatest Common Divisor) The greatest common divisor (GCD) of two integers is the largest integer that evenly divides each of the two numbers. Write a method gcd that returns the greatest common divisor of two integers. [Hint: You might want to use Euclid’s algorithm. You can find information about it at en.wikipedia.org/wiki/Euclidean_algorithm.] Incorporate the method into an application that reads two values from the user and displays the result.

D.21 (Quality Points) Write a method qualityPoints that inputs a student’s average and returns 4 if it’s 90–100, 3 if 80–89, 2 if 70–79, 1 if 60–69 and 0 if lower than 60. Incorporate the method into an application that reads a value from the user and displays the result.

D.22 (Coin Tossing) Write an application that simulates coin tossing. Let the program toss a coin each time the user chooses the “Toss Coin” menu option. Count the number of times each side of the coin appears. Display the results. The program should call a separate method flip that takes no arguments and returns a value from a Coin enum (HEADS and TAILS). [Note: If the program realistically simulates coin tossing, each side of the coin should appear approximately half the time.]

D.23 (Guess the Number) Write an application that plays “guess the number” as follows: Your program chooses the number to be guessed by selecting a random integer in the range 1 to 1000. The application displays the prompt Guess a number between 1 and 1000. The player inputs a first guess. If the player’s guess is incorrect, your program should display "Too high. Try again." or "Too low. Try again." to help the player “zero in” on the correct answer. The program should prompt the user for the next guess. When the user enters the correct answer, display "Congratulations. You guessed the number!", and allow the user to choose whether to play again. The guessing technique employed in this problem is similar to a binary search.

D.24 (Craps Game Modification) Modify the craps program of Fig. D.5 to allow wagering. Initialize variable bankBalance to 1000 dollars. Prompt the player to enter a wager. Check that wager is less than or equal to bankBalance, and if it’s not, have the user reenter wager until a valid wager is entered. Then, run one game of craps. If the player wins, increase bankBalance by wager and display the new bankBalance. If the player loses, decrease bankBalance by wager, display the new bankBalance, check whether bankBalance has become zero and, if so, display the message "Sorry. You busted!" As the game progresses, display various messages to create some “chatter,” such as "Oh, you're going for broke, huh?" or "Aw c'mon, take a chance!" or "You're up big. Now’s the time to cash in your chips!". Implement the “chatter” as a separate method that randomly chooses the string to display.

D.25 (Computer-Assisted Instruction) The use of computers in education is referred to as computer-assisted instruction (CAI). Write a program that will help an elementary school student learn multiplication. Use a Random object to produce two positive one-digit integers. The program should then prompt the user with a question, such as

How much is 6 times 7?

The student then inputs the answer. Next, the program checks the student’s answer. If it’s correct, display the message "Very good!" and ask another multiplication question. If the answer is wrong, display the message "No. Please try again." and let the student try the same question repeatedly until the student finally gets it right. A separate method should be used to generate each new question. This method should be called once when the application begins execution and each time the user answers the question correctly.

D.26 (Computer-Assisted Instruction: Reducing Student Fatigue) One problem in CAI environments is student fatigue. This can be reduced by varying the computer’s responses to hold the student’s attention. Modify the program of Exercise D.25 so that various comments are displayed for each answer as follows:

Possible responses to a correct answer:

Very good!
Excellent!
Nice work!
Keep up the good work!

Possible responses to an incorrect answer:

No. Please try again.
Wrong. Try once more.
Don't give up!
No. Keep trying.

Use random-number generation to choose a number from 1 to 4 that will be used to select one of the four appropriate responses to each correct or incorrect answer. Use a switch statement to issue the responses.

D.27 (Computer-Assisted Instruction: Varying the Types of Problems) Modify the previous program to allow the user to pick a type of arithmetic problem to study. An option of 1 means addition problems only, 2 means subtraction problems only, 3 means multiplication problems only, 4 means division problems only and 5 means a random mixture of all these types.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.222.47