Section 2.4. Class Definition

2.4. Class Definition

To program in Java, the main thing you do is write class definitions for the various objects that will make up the program. A class definition encapsulates its objects' data and behavior. Once a class has been defined, it serves as a template, or blueprint, for creating individual objects or instances of the class.

The class as template

A class definition contains two types of elements: variables and methods. Variables are used to store the object's information. Methods are used to process the information. To design an object you need to answer five basic questions:

1.

What role will the object perform in the program?

2.

What data or information will it need?

3.

What actions will it take?

4.

What interface will it present to other objects?

5.

What information will it hide from other objects?

Variables and methods

2.4.1. The Riddle Class

Our definition of the Riddle class from Chapter 1 is summarized in the UML diagram in Figure 2.11. A Riddle has two attributes, question and answer. Each of these variables stores a string of characters, which Java treats as data of type String. The Riddle class contains three methods. The Riddle() constructor method assigns initial values (q and a) to its question and answer variables. The getQuestion() and getAnswer() methods return the data stored in question and answer respectively.

Figure 2.11. The Riddle class.

The instance variables question and answer are designated as private (-), but the Riddle(), getQuestion() and getAnswer() methods are designated as public (+). These designations follow two important object-oriented design conventions, whose justification will become apparent as we discuss the Riddle class:

Effective Design: Private Variables

Instance variables are usually declared private so that they cannot be directly accessed by other objects.

[Page 74]

Effective Design: Public Methods

An object's public methods can be used by other objects to interact with the object. The public methods and variables of an object make up its interface.

Figure 2.12 shows the Java class definition that corresponds to the design given in the UML diagram. It contains the two private instance variables and defines the three public methods listed in the UML diagram. In a Java class definition, access to a class element, such as a variable or a method, is controlled by labeling it with either the private or the public access modifier. An access modifier is a declaration that controls access to a class or one of its elements. Note that the Riddle class itself is declared public. This lets other classes have access to the class and to its public variables and methods.

Recall that a class is like a blueprint or a cookie cutter. The Riddle class defines the type of information (attributes) that each individual Riddle has, but it doesn't contain any actual values. It defines the methods (operations) that each Riddle can perform, but it doesn't actually perform the methods. In short, a class serves as a template, providing a detailed blueprint of the objects (or instances) of that class.

Class as blueprint

2.4.2. The RiddleUser Class

Now that we have defined the Riddle class, we can test whether it works correctly by creating Riddle objects and "asking" them to tell us their riddles. To do this we need to define a main() method, which can be defined either within the Riddle class itself or in a second class named something like RiddleUser.

One advantage of using a second class is that it gets us in the habit of thinking about the need for a separate class to serve as a user interface, with a separate set of tasks from the Riddle class. A user interface is an object or class that handles the interaction between a program's user and the rest of the program's computational tasks. This concept is illustrated in Figure 2.13. Note that we use the general term computational object to distinguish the rest of the program's computations from the user interface. Obviously, the exact nature of the computation will vary from program to program, just as will the details of the user interface.

Figure 2.13. The user interface handles interactions between the user and the rest of the program.

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

User interface

[Page 75]

The computation done by our Riddle class is just the storing and displaying of a riddle's question and answer.

By separating user interface tasks from riddle tasks, this design employs the divide-and-conquer principle: the RiddleUser class will create Riddle objects and handle interactions with the user, and the Riddle class will handle the storing and transmission of riddle information. Thus, as shown in Figure 2.14, this particular Java program will involve interaction between two types of objects: a RiddleUser and one or more Riddles. Note that we characterize the relationship between Riddle and RiddleUser with a one-way arrow labeled "Uses." This is because the RiddleUser will create an instance of Riddle and use its methods to display (for the user) a riddle.

Figure 2.14. This UML class diagram represents an association between the RiddleUser and Riddle classes. The RiddleUser class will use one or more objects of the Riddle class.

Because almost all of our programs will involve some form of a user interface, we can generalize this design approach and follow it throughout the book. One way to think about this approach is as a division of labor between a user interface class and a second computational class, which performs whatever computations are needed by the particular program. In this case the computations are the simple Riddle methods that we have defined. In subsequent programs the computations will become more complex, which will make all the more clear that they should be separated from the user interface.

2.4.3. Object Instantiation: Creating Riddle Instances

Figure 2.15 shows the complete definition of the RiddleUser class, which serves as a very simple user interface. It creates two Riddle objects, named riddle1 and riddle2. It then asks each object to request each riddle's question and answer, and displays them on the console.

We will now discuss the statements that make up RiddleUser's main() method. The following statements use the Riddle() constructor to create, or instantiate, two instances of the Riddle class:

Riddle riddle1 = new Riddle( "What is black and white and red all over?", "An embarrassed zebra."); Riddle riddle2 = new Riddle( "What is black and white and read all over?", "A newspaper.");

Note how the constructor gives each object a pair of Strings that serve as the values of their two instance variables. Each object has its own question and its own answer, and each object has its own unique name, riddle1 and riddle2.

2.4.4. Interacting with Riddles

Once we have created Riddle instances with values assigned to their question and answer instance variables, we can ask each riddle to tell us either of its values. The following expression is an example of a method call:

riddle1.getQuestion()

[Page 77]

Calling (or invoking) a method is a means of executing its code. The preceding method call just gets the String value that is stored in the question instance variable of riddle1.

If we want to display the value of riddle1's question, we can embed this method call within a println() statement

System.out.println(riddle1.getQuestion());

This tells the System.out object to execute its println() method, which displays the string given to it by riddle1 on the console. Thus, the output produced by this statement will be

What is black and white and red all over ?

2.4.5. Define, Create, Use

As our Riddle example illustrates, writing a Java program is a matter of three basic steps:

Define one or more classes (class definition).

Create objects as instances of the classes (object instantiation).

Use the objects to do tasks (object use).

The Java class definition determines what information will be stored in each object and what methods each object can perform. Instantiation creates an instance and associates a name with it in the program. The object's methods can then be called as a way of getting the object to perform certain tasks.