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

AhmadLang / Java, How To Program, 2004

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

switch statement, the behavior of various SML instructions is simulated as shown in

Fig. 7.38. We discuss branch instructions shortly and leave the others to you.

Figure 7.38. Behavior of several SML instructions in the Simpletron.

Instruction

Description

 

 

 

read:

Display the prompt "Enter an integer", then input the integer

 

and store it in location memory[ operand

].

load:

accumulator = memory[ operand ];

 

add:

accumulator += memory[ operand ];

 

halt:

This instruction displays the message

 

 

*** Simpletron execution terminated

***

 

 

 

When the SML program completes execution, the name and contents of each register as well as the complete contents of memory should be displayed. Such a printout is often called a computer dump (no, a computer dump is not a place where old computers go). To help you program your dump method, a sample dump format is shown in Fig. 7.39. Note that a dump after executing a Simpletron program would show the actual values of instructions and data values at the moment execution terminated.

[Page 355]

Figure 7.39. A sample dump.

REGISTERS:

 

 

 

 

 

 

 

 

accumulator

 

+0000

 

 

 

 

 

 

instructionCounter

00

 

 

 

 

 

 

instructionRegister

+0000

 

 

 

 

 

 

operationCode

 

00

 

 

 

 

 

 

operand

 

 

00

 

 

 

 

 

 

MEMORY:

 

 

 

 

 

 

 

 

 

 

0

1

2

3

4

5

6

7

8

9

0

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

10

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

20

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

30

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

40

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

50

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

60

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

70

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

80

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

90

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

+0000

 

 

 

 

 

 

 

 

 

 

 

Let us proceed with the execution of our program's first instructionnamely, the +1009 in location 00. As we have indicated, the switch statement simulates this task by prompting the user to enter a value, reading the value and storing it in memory location memory[ operand ]. The value is then read into location 09.

At this point, simulation of the first instruction is completed. All that remains is to prepare the Simpletron to execute the next instruction. Since the instruction just performed was not a transfer of control, we need merely increment the instructioncounter register as follows:

instructionCounter++;

This action completes the simulated execution of the first instruction. The entire process (i.e., the instruction execution cycle) begins anew with the fetch of the next instruction to execute.

Now let us consider how the branching instructionsthe transfers of controlare simulated. All we need to do is adjust the value in the instruction counter appropriately. Therefore, the unconditional branch instruction (40) is simulated within the switch as

instructionCounter = operand;

The conditional "branch if accumulator is zero" instruction is simulated as

if ( accumulator == 0 ) instructionCounter = operand;

At this point, you should implement your Simpletron simulator and run each of the SML programs you wrote in Exercise 7.34. If you desire, you may embellish SML with additional features and provide for these features in your simulator.

Your simulator should check for various types of errors. During the program-loading phase, for example, each number the user types into the Simpletron's memory must be in the range -9999 to +9999. Your simulator should test that each number entered is in this range and, if not, keep prompting the user to reenter the number until the user enters a correct number.

[Page 356]

During the execution phase, your simulator should check for various serious errors, such as attempts to divide by zero, attempts to execute invalid operation codes, and accumulator overflows (i.e., arithmetic operations resulting in values larger than +9999 or smaller than -9999). Such serious errors are called fatal errors. When a fatal error is detected, your simulator should display an error message, such as

***Attempt to divide by zero ***

***Simpletron execution abnormally terminated ***

and should display a full computer dump in the format we discussed previously. This treatment will help the user locate the error in the program.

7.36(Simpletron Simulator Modifications) In Exercise 7.35, you wrote a software simulation of a computer that executes programs written in Simpletron Machine Language (SML). In this exercise, we propose several modifications and enhancements to the Simpletron Simulator. In Exercise 17.26 and Exercise 17.27, we propose building a compiler that converts programs written in a high-level programming language (a variation of Basic) to Simpletron Machine Language. Some of the following modifications and enhancements may be required to execute the programs produced by the compiler:

a.Extend the Simpletron Simulator's memory to contain 1000 memory locations to enable the Simpletron to handle larger programs.

b.Allow the simulator to perform remainder calculations. This modification requires an additional SML instruction.

c.Allow the simulator to perform exponentiation calculations. This modification requires an additional SML instruction.

d.Modify the simulator to use hexadecimal values rather than integer values to represent SML instructions.

e.Modify the simulator to allow output of a newline. This modification requires an additional SML instruction.

f.Modify the simulator to process floating-point values in addition to integer values.

g.Modify the simulator to handle string input. [Hint: Each Simpletron word can be divided into two groups, each holding a two-digit integer. Each two-digit integer represents the ASCII (see Appendix B) decimal equivalent of a character. Add a machine language instruction that will input a string and store the string, beginning at a specific Simpletron memory location. The first half of the word at that location will be a count of the number of characters in the string (i.e., the length of the string). Each succeeding half-word contains one ASCII character expressed as two decimal digits. The machine language instruction converts each character into its ASCII equivalent and assigns it to a half-word.]

h.Modify the simulator to handle output of strings stored in the format of part (g). [Hint: Add a machine-language instruction that will display a string, beginning at a certain Simpletron memory location. The first half of the word at that location is a count of the number of characters in the string (i.e., the length of the string). Each succeeding half-word contains one ASCII character expressed as two decimal digits. The machine-language instruction checks the length and displays the string by translating each two-digit number into its equivalent character.]

[Page 357]

Chapter 8. Classes and Objects: A Deeper

Look

Instead of this absurd division into sexes, they ought to class people as static and dynamic.

Evelyn Waugh

Is it a world to hide virtues in?

William Shakespeare

But what, to serve our private ends, Forbids the cheating of our friends?

Charles Churchill

This above all: to thine own self be true.

William Shakespeare

Don't be "consistent," but be simply true.

Oliver Wendell Holmes, Jr.

OBJECTIVES

In this chapter you will learn:

Encapsulation and data hiding.

The notions of data abstraction and abstract data types (ADTs).

To use keyword this.

To use static variables and methods.

To import static members of a class.

To use the enum type to create sets of constants with unique identifiers.

How to declare enum constants with parameters.

[Page 358]

Outline

8.1 Introduction

8.2 Time Class Case Study

8.3 Controlling Access to Members

8.4 Referring to the Current Object's Members with the this Reference

8.5 Time Class Case Study: Overloaded Constructors

8.6 Default and No-Argument Constructors

8.7 Notes on Set and Get Methods

8.8 Composition

8.9 Enumerations

8.10 Garbage Collection and Method finalize

8.11 static Class Members

8.12 static Import

8.13 final Instance Variables

8.14 Software Reusability

8.15 Data Abstraction and Encapsulation

8.16 Time Class Case Study: Creating Packages

8.17 Package Access

8.18 (Optional) GUI and Graphics Case Study: Using Objects with Graphics

8.19 (Optional) Software Engineering Case Study: Starting to Program the Classes of the ATM System

8.20 Wrap-Up

Summary

Terminology

Self-Review Exercises

Answers to Self-Review Exercises

Exercises

[Page 358 (continued)]

8.1. Introduction

In our discussions of object-oriented programs in the preceding chapters, we introduced many basic concepts and terminology that relate to Java object-oriented programming (OOP). We also discussed our program development methodology: We selected appropriate variables and methods for each program and specified the manner in which an object of our class collaborated with objects of Java API classes to accomplish the program's overall goals.

In this chapter, we take a deeper look at building classes, controlling access to members of a class and creating constructors. We discuss compositiona capability that allows a class to have references to objects of other classes as members. We reexamine the use of set and get methods and further explore the new J2SE 5.0 class type enum (introduced in Section 6.10) that enables programmers to declare and manipulate sets of unique identifiers that represent constant values. In Section 6.10, we introduced the basic enum type, which appeared within another class and simply declared a set of constants. In this chapter, we discuss the relationship between enum types and classes, demonstrating that an enum, like a class, can be declared in its own file with constructors, methods and fields. The chapter also discusses static class members and final instance variables in detail. We investigate issues such as software reusability, data abstraction and encapsulation. Finally, we explain how to organize classes in packages to help manage large applications and promote reuse, then show a special relationship between classes in the same package.

[Page 359]

Chapter 9, Object-Oriented Programming: Inheritance, and Chapter 10, Object-Oriented Programming: Polymorphism, introduce inheritance and polymorphism, respectivelytwo additional key object-oriented programming technologies.

[Page 359 (continued)]

8.2. Time Class Case Study

Time1 Class Declaration

Our first example consists of two classesTime1 (Fig. 8.1) and Time1Test (Fig. 8.2). Class Time1 represents the time of day. Class Time1Test is an application class in which the main method creates one object of class Time1 and invokes its methods. These classes must be declared in separate files because they are both public classes. The output of this program appears in Fig. 8.2.

Figure 8.1. Time1 class declaration maintains the time in 24-hour format.

 

 

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

1

//

Fig. 8.1: Time1.java

2

//

Time1 class declaration maintains the time in 24-hour format.

3

 

 

4public class Time1

5{

6

private

int

hour;

//

0

-

23

7

private int minute; // 0

-

59

8

private

int

second;

//

0

-

59

9

 

 

 

 

 

 

 

10// set a new time value using universal time; ensure that

11// the data remains consistent by setting invalid values to zero

12public void setTime( int h, int m, int s )

13

 

 

 

 

 

 

 

 

 

 

 

 

 

 

14

hour = ( ( h

>= 0

&&

h

<

24

)

? h : 0

);

 

//

validate

hour

15

minute

= ( (

m >=

0

&&

m

<

60

) ? m : 0

);

//

validate

minute

16

second

= ( (

s >=

0

&&

s

<

60

) ? s :

0

);

//

validate

second

17

} // end

method

setTime

 

 

 

 

 

 

 

 

 

 

18

 

 

 

 

 

 

 

 

 

 

 

 

 

 

19// convert to String in universal-time format (HH:MM:SS)

20public String toUniversalString()

21{

22return String.format( "%02d:%02d:%02d", hour, minute, second );

23} // end method toUniversalString

24

25// convert to String in standard-time format (H:MM:SS AM or PM)

26public String toString()

27{

28return String.format( "%d:%02d:%02d %s",

29

( ( hour == 0 || hour == 12 ) ? 12 : hour % 12 ),

30minute, second, ( hour < 12 ? "AM" : "PM" ) );

31} // end method toString

32} // end class Time1

Figure 8.2. Time1 object used in an application.

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

1

//

Fig. 8.2: Time1Test.java

2

//

Time1 object used in an application.

3

 

 

4public class Time1Test

5{

6

public static void main( String args[] )

7

{

8

// create and initialize a Time1 object

9

Time1 time = new Time1(); // invokes Time1 constructor

10

11// output string representations of the time

12System.out.print( "The initial universal time is: " );

13System.out.println( time.toUniversalString() );

14System.out.print( "The initial standard time is: " );

15System.out.println( time.toString() );

16System.out.println(); // output a blank line

17

18// change time and output updated time

19time.setTime( 13, 27, 6 );

20System.out.print( "Universal time after setTime is: " );

21System.out.println( time.toUniversalString() );

22System.out.print( "Standard time after setTime is: " );

23System.out.println( time.toString() );

24System.out.println(); // output a blank line

25

26// set time with invalid values; output updated time

27time.setTime( 99, 99, 99 );

28System.out.println( "After attempting invalid settings:" );

29System.out.print( "Universal time: " );

30System.out.println( time.toUniversalString() );

31System.out.print( "Standard time: " );

32System.out.println( time.toString() );

33} // end main

34} // end class Time1Test

The initial universal time is: 00:00:00

The initial standard time is: 12:00:00 AM

Universal time after setTime is: 13:27:06

Standard time after setTime is: 1:27:06 PM

After attempting invalid settings:

Universal time: 00:00:00

Standard time: 12:00:00 AM

Class Time1 contains three private instance variables of type int (Fig. 8.1, lines 68)hour, minute and secondthat represent the time in universal-time format (24-hour clock format in which hours are in the range 023). Class Time1 contains public methods setTime (lines 1217), toUniversalString (lines 2023) and toString (lines 2631). These methods are also called the public services or the public interface that the class provides to its clients.

In this example, class Time1 does not declare a constructor, so the class has a default constructor that is supplied by the compiler. Each instance variable implicitly receives the default value 0 for an int. Note that instance variables also can be initialized when they are declared in the class body using the same initialization syntax as with a local variable.

Method setTime (lines 1217) is a public method that declares three int parameters and uses them to set the time. A conditional expression tests each argument to determine whether the value is in a specified range. For example, the hour value (line 14) must be greater than or equal to 0 and less than 24, because universal-time format represents hours as integers from 0 to 23 (e.g., 1 PM is hour 13 and 11 PM is hour 23; midnight is hour 0 and noon is hour 12). Similarly, both minute and second values (lines 15 and 16) must be greater than or equal to 0 and less than 60. Any values outside these ranges are set to zero to ensure that a Time1 object always contains consistent datathat is, the object's data values are always kept in range, even if the values provided as arguments to method setTime were incorrect. In this example, zero is a consistent value for hour, minute and second.

A value passed to setTime is a correct value if that value is in the allowed range for the member it is initializing. So, any number in the range 023 would be a correct value for the hour. A correct value is always a consistent value. However, a consistent value is not necessarily a correct value. If setTime sets

hour to 0 because the argument received was out of range, then setTime is taking an incorrect value and making it consistent, so the object remains in a consistent state at all times. In this case, the program might want to indicate that the object is incorrect. In Chapter 13, Exception Handling, you will learn techniques that enable your classes to indicate when incorrect values are received.

Software Engineering Observation 8.1

Methods that modify the values of private variables should verify that the intended new values are proper. If they are not, the set methods should place the private variables into an appropriate consistent state.

[Page 360]

Method toUniversalString (lines 2023) takes no arguments and returns a String in universal-time format, consisting of six digitstwo for the hour, two for the minute and two for the second. For example, if the time were 1:30:07 PM, method toUniversalString would return 13:30:07. The return statement (line 22) uses static method format of class String to return a String containing the formatted hour, minute and second values, each with two digits and possibly a leading 0 (specified with the 0 flag). Method format is similar to method System.out.printf except that format returns a formatted String rather than displaying it in a command window. The formatted String is returned by method

toUniversalString.

Method toString (lines 2631) takes no arguments and returns a String in standard-time format, consisting of the hour, minute and second values separated by colons and followed by an AM or PM indicator (e.g., 1:27:06 PM). Like method toUniversalString, method toString uses static String method format to format the minute and second as two-digit values with leading zeros if necessary. Line 29 uses a conditional operator (?:) to determine the value for hour in the stringif the hour is 0 or 12 (AM or PM), it appears as 12otherwise, the hour appears as a value from 1 to 11. The conditional operator in line 30 determines whether AM or PM will be returned as part of the String.

[Page 361]

Recall from Section 6.4 that all objects in Java have a toString method that returns a String representation of the object. We chose to return a String containing the time in standard-time format. Method toString can be called implicitly whenever a Time1 object appears in the code where a String is needed, such as the value to output with a %s format specifier in a call to System.out.printf.

Using Class Time1

As you learned in Chapter 3, each class you declare represents a new type in Java. Therefore, after declaring class Time1, we can use it as a type in declarations such as

Time1 sunset; // sunset can hold a reference to a Time1 object

The Time1Test application class (Fig. 8.2) uses class Time1. Line 9 declares and creates a Time1 object and assigns it to local variable time. Note that new implicitly invokes class Time1's default constructor, since Time1 does not declare any constructors. Lines 1216 output the time first in universal-time format (by invoking time's toUniversalString method in line 13), then in standard-time format (by explicitly invoking time's toString method in line 15) to confirm that the Time1 object was initialized properly.

Line 19 invokes method setTime of the time object to change the time. Then lines 2024 output the time again in both formats to confirm that the time was set correctly.

To illustrate that method setTime maintains the object in a consistent state, line 27 calls method setTime with arguments of 99 for the hour, minute and second. Lines 2832 output the time again in both formats to confirm that setTime maintained the object's consistent state, then the program terminates. The last two lines of the application's output show that the time is reset to midnightthe initial value of a Time1 objectafter an attempt to set the time with three out-of-range values.

Notes on the Time1 Class Declaration

Consider several issues of class design with respect to class Time1. The instance variables hour, minute and second are each declared private. The actual data representation used within the class is of no concern to the class's clients. For example, it would be perfectly reasonable for Time1 to represent the time internally as the number of seconds since midnight or the number of minutes and seconds since midnight. Clients could use the same public methods and get the same results without being aware of this. (Exercise 8.5 asks you to represent the time in class Time1 as the number of seconds since midnight and show that there is indeed no change visible to the clients of the class.)

Software Engineering Observation 8.2

Classes simplify programming, because the client can use only the public methods exposed by the class. Such methods are usually client oriented rather than implementation oriented. Clients are neither aware of, nor involved in, a class's implementation. Clients generally care about what the class does but not how the class does it.

Software Engineering Observation 8.3

Interfaces change less frequently than implementations. When an implementation changes, implementation-dependent code must change accordingly. Hiding the implementation reduces the possibility that other program parts will become dependent on classimplementation details.