Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

AhmadLang / Java, How To Program, 2004

.pdf
Скачиваний:
630
Добавлен:
31.05.2015
Размер:
51.82 Mб
Скачать

Common Programming Error 6.6

Placing a semicolon after the right parenthesis enclosing the parameter list of a method declaration is a syntax error.

[Page 241]

Common Programming Error 6.7

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

Common Programming Error 6.8

Forgetting to return a value from a method that should return a value is a compilation error. If a return value type other than void is specified, the method must contain a return statement that returns a value consistent with the method's return-value-type. Returning a value from a method whose return type has been declared void is a compilation error.

[Page 241 (continued)]

6.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. Students can think of a stack as analogous to a pile of dishes. When a dish is placed on the pile, it is normally placed at the top (referred to as pushing the dish onto the stack). Similarly, when a dish is removed from the pile, it is always removed from the top (referred to as popping the dish off the stack). Stacks are known as last-in, first-out (LIFO) data structuresthe 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, 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'll discuss garbage collection in Section 8.10.

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

[Page 241 (continued)]

6.7. Argument Promotion and Casting

Another important feature of method calls is argument promotionconverting an argument's value to the type that the method expects to receive in its corresponding parameter. For example, a program can call Math method sqrt with an integer argument even though the method expects to receive a double argument (but, as we will soon see, not vice versa). The statement

[Page 242]

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 sqrt. Attempting these conversions may lead to compilation errors if Java's promotion rules are not satisfied. The promotion rules specify which conversions are allowed, that is, which conversions 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 valuethus, part of the value is lost. Converting large integer types to small integer types (e.g., long to int) 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 valuethe types of the original values remain unchanged.) Figure 6.5 lists the primitive types and the types to which each can be promoted. Note that 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.

 

Figure 6.5. Promotions allowed for primitive types.

Type

Valid promotions

 

 

double

None

float

double

long

float or double

int

long, float or double

char

int, long, float or double

short

int, long, float or double (but not char)

byte

short, int, long, float or double (but not char)

boolean

None (boolean values are not considered to be numbers in Java)

 

 

Converting values to types lower in the table of Fig. 6.5 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 the programmer to use a cast operator (introduced in Section 4.9) to explicitly force the conversion to occurotherwise a compilation error occurs. This enables the programmer to "take control" from the compiler. The programmer essentially says, "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) the value of doubleValue 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.

[Page 243]

Common Programming Error 6.9

Converting a primitive-type value to another primitive type may change the value if the new type is not a valid promotion. For example, converting a floating-point value to an integral value may introduce truncation errors (loss of the fractional part) into the result.

[Page 243 (continued)]

6.8. Java API Packages

As we have seen, Java contains many predefined classes that are grouped into categories of related classes called packages. Together, we refer to these packages as the Java Application Programming Interface (Java API), or the Java class library.

Throughout the text, import declarations specify the classes required to compile a Java program. For example, a program includes the declaration

import java.util.Scanner;

to specify that the program uses class Scanner from the java.util package. This allows programmers to use the simple class name Scanner, rather than the fully qualified class name java.util.Scanner, in the code. A great strength of Java is the large number of classes in the packages of the Java API. Some key Java API packages are described in Fig. 6.6, which represents only a small portion of the reusable components in the Java API. When learning Java, spend a portion of your time browsing the packages and classes in the Java API documentation (java.sun.com/j2se/5.0/docs/api/index.html).

Figure 6.6. Java API packages (a subset).

 

[Page 244]

Package

Description

 

 

java.applet

The Java Applet Package contains a class and several interfaces required

 

to create Java appletsprograms that execute in Web browsers. (Applets

 

are discussed in Chapter 20, Introduction to Java Applets; interfaces are

 

discussed in Chapter 10, Object-Oriented Programming: Polymorphism.)

java.awt

The Java Abstract Window Toolkit Package contains the classes and

 

interfaces required to create and manipulate GUIs in Java 1.0 and 1.1. In

 

current versions of Java, the Swing GUI components of the javax.swing

 

packages are often used instead. (Some elements of the java.awt

 

package are discussed in Chapter 11, GUI Components: Part 1, Chapter

 

12, Graphics and Java2D, and Chapter 22, GUI Components: Part 2.)

java.awt.event

The Java Abstract Window Toolkit Event Package contains classes and

 

interfaces that enable event handling for GUI components in both the

 

java.awt and javax.swing packages. (You will learn more about this

 

package in Chapter 11, GUI Components: Part 1 and Chapter 22, GUI

 

Components: Part 2.)

java.io

The Java Input/Output Package contains classes and interfaces that

 

enable programs to input and output data. (You will learn more about this

 

package in Chapter 14, Files and Streams.)

java.lang

The Java Language Package contains classes and interfaces (discussed

 

throughout this text) that are required by many Java programs. This

 

package is imported by the compiler into all programs, so the programmer

 

does not need to do so.

java.net

The Java Networking Package contains classes and interfaces that

 

enable programs to communicate via computer networks like the Internet.

 

(You will learn more about this in Chapter 24, Networking.)

java.text

The Java Text Package contains classes and interfaces that enable

 

programs to manipulate numbers, dates, characters and strings. The

 

package provides internationalization capabilities that enable a program to

 

be customized to a specific locale (e.g., a program may display strings in

 

different languages, based on the user's country).

java.util

The Java Utilities Package contains utility classes and interfaces that

 

enable such actions as date and time manipulations, random-number

 

processing (class Random), the storing and processing of large amounts of

 

data and the breaking of strings into smaller pieces called tokens (class

 

StringTokenizer). (You will learn more about the features of this

 

package in Chapter 19, Collections.)

javax.swing

The Java Swing GUI Components Package contains classes and

 

interfaces for Java's Swing GUI components that provide support for

 

portable GUIs. (You will learn more about this package in Chapter 11, GUI

 

Components: Part 1 and Chapter 22, GUI Components: Part 2.)

javax.swing.event

The Java Swing Event Package contains classes and interfaces that

 

enable event handling (e.g., responding to button clicks) for GUI

 

components in package javax.swing. (You will learn more about this

 

package in Chapter 11, GUI Components: Part 1 and Chapter 22, GUI

 

Components: Part 2.)

 

 

The set of packages available in the J2SE Development Kit (JDK) is quite large. In addition to the packages summarized in Fig. 6.6, the JDK includes packages for complex graphics, advanced graphical user interfaces, printing, advanced networking, security, database processing, multimedia, accessibility (for people with disabilities) and many other capabilities. For an overview of the packages in the JDK 5.0, visit

java.sun.com/j2se/5.0/docs/api/overview-summary.html

Many other packages are also available for download at java.sun.com.

[Page 244]

You can locate additional information about a predefined Java class's methods in the Java API documentation at java.sun.com/j2se/5.0/docs/api/index.html. 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 the method's return type. For a more detailed overview of navigating the Java API documentation, see Appendix G, Using the Java API Documentation.

[Page 245]

Good Programming Practice 6.2

The online Java API documentation is easy to search and provides many details about each class. As you learn a class in this book, you should get in the habit of looking at the class in the online documentation for additional information.

[Page 245 (continued)]

6.9. Case Study: Random-Number Generation

We now take a brief and, hopefully, entertaining diversion into a popular type of programming applicationsimulation 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 book and introduces several new programming concepts.

There is something in the air of a casino that invigorates peoplefrom the high rollers at the plush mahogany-and-felt craps tables to the quarter poppers at the one-armed bandits. It is the element of chance, the possibility that luck will convert a pocketful of money into a mountain of wealth. The element of chance can be introduced in a program via an object of class Random (package java.util) or via the static method random of class Math. Objects of class Random 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.0 < x < 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.

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

Random randomNumbers = new Random();

The random-number generator object can then be used to generate random boolean, byte, float, double, int, long and Gaussian valueswe discuss only random int values here. For more information on the Random class, see java.sun.com/j2se/5.0/docs/api/java/util/Random.html.

Consider the following statement:

int randomValue = randomNumbers.nextInt();

Method nextInt of class Random generates a random int value in the range 2,147,483,648 to +2,147,483,647. If the nextInt method truly produces values at random, then every value in that range should have an equal chance (or probability) of being chosen each time method nextInt is called. The values returned by nextInt are actually pseudorandom numbersa 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 often 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 16. 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 14. 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, to simulate coin tossing, you might use the statement

[Page 246]

int randomValue = randomNumbers.nextInt( 2 );

which returns 0 or 1.

Rolling a Six-Sided Die

To demonstrate random numbers, let us develop a program that simulates 20 rolls of a six-sided die

and displays the value of each roll. We begin by using nextInt to produce random values in the range

05, as follows:

face = randomNumbers.nextInt( 6 );

The argument 6called the scaling factorrepresents the number of unique values that nextInt should produce (in this case six0, 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 16 on its faces, not 05. So we shift the range of numbers produced by adding a shifting valuein this case 1to our previous result, as in

face = 1 + randomNumbers.nextInt( 6 );

The shifting value (1) specifies the first value in the desired set of random integers. The preceding statement assigns face a random integer in the range 16.

Figure 6.7 shows two sample outputs which confirm that the results of the preceding calculation are integers in the range 16, and that each run of the program can produce a different sequence of random numbers. Line 3 imports class Random from the java.util package. Line 9 creates the Random object randomNumbers to produce random values. Line 16 executes 20 times in a loop to roll the die. The if statement (lines 2122) in the loop starts a new line of output after every five numbers, so the results can be presented on multiple lines.

Figure 6.7. Shifted and scaled random integers.

(This item is displayed on page 247 in the print version)

1

//

Fig. 6.

7: RandomIntegers.java

2

//

Shifted

and scaled random integers.

3

import java.util.Random; // program uses class Random

4

 

 

 

5public class RandomIntegers

6{

7public static void main( String args[] )

8{

9Random randomNumbers = new Random(); // random number generator

10int face; // stores each random integer generated

11

12 // loop 20 times

13 for ( int counter = 1; counter <= 20; counter++ )

14{

15// pick random integer from 1 to 6

16face = 1 + randomNumbers.nextInt( 6 );

18

System.out.printf( "%d

",

face

); //

display

generated value

19

 

 

 

 

 

 

 

 

 

 

20

//

if

counter

is

divisible

by 5,

start

a new

line of output

21

if

(

counter

% 5

== 0

)

 

 

 

 

22

 

System.out

.println();

 

 

 

 

23} // end for

24} // end main

25} // end class RandomIntegers

1

5

3

6

2

5

2

6

5

2

4

4

4

2

6

3

1

6

2

2

 

 

 

 

 

6

5

4

2

6

1

2

5

1

3

6

3

2

2

1

6

4

2

6

4

 

 

 

 

 

Rolling a Six-Sided Die 6000 Times

To show that the numbers produced by nextInt occur with approximately equal likelihood, let us simulate 6000 rolls of a die with the application in Fig. 6.8. Each integer from 1 to 6 should appear approximately 1000 times.

Figure 6.8. Rolling a six-sided die 6000 times.

(This item is displayed on pages 247 - 249 in the print version)

1

//

Fig. 6.8: RollDie.java

2

//

Roll a six-sided die 6000 times.

3

import java.util.Random;

4

 

 

5public class RollDie

6{

7public static void main( String args[] )

8{

9Random randomNumbers = new Random(); // random number generator

11int frequency1 = 0; // maintains count of 1s rolled

12int frequency2 = 0; // count of 2s rolled

13int frequency3 = 0; // count of 3s rolled

14int frequency4 = 0; // count of 4s rolled

15int frequency5 = 0; // count of 5s rolled

16int frequency6 = 0; // count of 6s rolled

18int face; // stores most recently rolled value

20// summarize results of 6000 rolls of a die

21

for ( int

roll

= 1; roll <= 6000; roll++

)

22

{

 

 

 

23

face =

1 +

randomNumbers.nextInt( 6 );

// number from 1 to 6

24

 

 

 

 

25// determine roll value 1-6 and increment appropriate counter

26switch ( face )

27{

28

case

1:

29

++frequency1; // increment the 1s counter

30

break;

31

case

2:

32

++frequency2; // increment the 2s counter

33

break;

34

case

3:

35

++frequency3; // increment the 3s counter

36

break;

37

case

4:

38

++frequency4; // increment the 4s counter

39

break;

40

case

5:

41

++frequency5; // increment the 5s counter

42

break;

43

case

6:

44

++frequency6; // increment the 6s counter

45

break; // optional at end of switch

46} // end switch

47} // end for

48

49System.out.println( "Face\tFrequency" ); // output headers

50System.out.printf( "1\t%d\n2\t%d\n3\t%d\n4\t%d\n5\t%d\n6\t%d\n",

51frequency1, frequency2, frequency3, frequency4,

52frequency5, frequency6 );

53} // end main

54} // end class RollDie

Face Frequency

1982

21001

31015

41005

51009

6988

Face Frequency

11029

2994

31017

41007

5972

6981

As the two sample outputs show, scaling and shifting the values produced by method nextInt enables the program to realistically simulate rolling a six-sided die. The application uses nested control statements (the switch is nested inside the for) to determine the number of times each side of the die occurred. The for statement (lines 2147) iterates 6000 times. During each iteration, line 23 produces a random value from 1 to 6. That value is then used as the controlling expression (line 26) of the switch statement (lines 2646). Based on the face value, the switch statement increments one of the six counter variables during each iteration of the loop. (When we study arrays in Chapter 7, we will show an elegant way to replace the entire switch statement in this program with a single statement!) Note that the switch statement has no default case because we have a case for every possible die value that the expression in line 23 could produce. Run the program several times, and observe the results. As you will see, every time you execute this program, it produces different results.

[Page 249]

6.9.1. Generalized Scaling and Shifting of Random Numbers

Previously, we demonstrated the statement

face = 1 + randomNumbers.nextInt( 6 );

which simulates the rolling of a six-sided die. This statement always assigns to variable face an integer in the range 1 < face < 6. 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. Referring to the preceding statement, we see that the width of the range is determined by the number 6 that is passed as an argument to Random