Chapter 1

Understanding Object-Oriented Programming

IN THIS CHAPTER

check Looking at what object-oriented programming is

check Understanding objects and classes

check Investigating inheritance and interfaces

check Designing programs with objects

check Diagramming with UML

This chapter is a basic introduction to object-oriented programming. It introduces some of the basic concepts and terms you need to know as you get a handle on the specific details of how object-oriented programming works in Java.

tip If you’re more of a hands-on type, you may want to skip this chapter and go straight to Book 3, Chapter 2 , where you find out how to create your own classes in Java. You can always return to this chapter later to review the basic concepts that drive object-oriented programming. Either way is okay by me. I get paid the same whether you read this chapter now or skip it and come back to it later.

What Is Object-Oriented Programming?

The term object-oriented programming means many different things. But at its heart, object-oriented programming is a type of computer programming based on the premise that all programs are essentially computer-based simulations of real-world objects or abstract concepts. For example:

technicalstuff The notion of a programming language having a premise of this sort isn’t new. Traditional programming languages such as C (and its predecessors, including even COBOL) are based on the premise that computer programs are computerized implementations of actual procedures — the electronic equivalent of “Step 1: Insert Tab A into Slot B.” The LISP programming language is based on the idea that all programming problems can be looked at as different ways of manipulating lists. And the ever-popular database-manipulation language SQL views programming problems as ways to manipulate mathematical sets.

Here are some additional thoughts about the notion of computer programs being simulations of real-world objects or abstract concepts:

Understanding Objects

All this talk of simulations is getting a little existential for me, so now I’m turning to the nature of the objects that make up object-oriented programming. Objects — both in the real world and in the world of programming — are entities that have certain basic characteristics. The following sections describe some of the most important of these characteristics: identity, type, state, and behavior.

Objects have identity

Every object in an object-oriented program has an identity. In other words, every occurrence of a particular type of object — called an instance — can be distinguished from every other occurrence of the same type of object, as well as from objects of other types.

In the real world, object identity is a pretty intuitive and obvious concept. Pick up two apples, and you know that although both of them are apples (that’s the object type, described in the next section), you know that they aren’t the same apple. Each has a distinct identity. Both are roughly the same color but not exactly. They’re both roundish but have minor variations in shape. Either one (or both) could have a worm inside.

Open a file cabinet that’s full of invoices, and you find page after page of papers that look almost identical, but each one has an invoice number printed somewhere near the top of the page. This number isn’t what actually gives each of these invoices a unique identity, but it gives you an easy way to identify each individual invoice, just as your name gives other people an easy way to identify you.

In object-oriented programming, each object has its own location in the computer’s memory. Thus, two objects, even though they may be of the same type, have their own distinct memory locations. The address of the starting location for an object provides a way of distinguishing one object from another, because no two objects can occupy the same location in memory.

Here are a few other important thoughts about object identity in Java:

Objects have type

I remember studying “Naming of Parts,” a fine poem written by Henry Reed in 1942, back when I was an English major in college:

To-day we have naming of parts. Yesterday,
We had daily cleaning. And to-morrow morning,
We shall have what to do after firing. But to-day,
To-day we have naming of parts. Japonica
Glistens like coral in all of the neighboring gardens,
And today we have naming of parts.

Sure, it’s a fine antiwar poem and all that, but it’s also a little instructive about object-oriented programming. After the first stanza, the poem goes on to name the parts of a rifle:

This is the lower sling swivel. And this
Is the upper sling swivel, whose use you will see,
When you are given your slings. And this is the piling swivel,
Which in your case you have not got.

Imagine a whole room of new soldiers taking apart their rifles, while the drill sergeant tells them, “This is the lower sling swivel. And this is the upper sling swivel.…” Each soldier’s rifle has one of these parts — in object-oriented terms, an object of a particular type. The lower sling swivels in the soldiers’ rifles are different objects, but all are of the type LowerSlingSwivel .

Like the drill sergeant in this poem, object-oriented programming lets you assign names to the different kinds of objects in a program. In Java, types are defined by classes. So when you create an object from a type, you’re saying that the object is of the type specified by the class. The following example statement creates an object of type Invoice :

Invoice i = new Invoice();

In this case, the identity of this object (that is, its address in memory) is assigned to the variable i , which the compiler knows can hold references to objects of type Invoice .

Objects have state

Now switch gears to another literary genius:

One fish, two fish,
Red fish, blue fish

In object-oriented terms, Dr. Seuss here is enumerating a pair of objects of type Fish . The Fish type apparently has two attributes; call them Number and Color . These two objects have differing values for these attributes:

Attribute

Object 1

Object 2

Number

One

Two

Color

Red

Blue

The type of an object determines what attributes the object has. Thus all objects of a particular type have the same attributes. They don’t necessarily have the same values for those attributes, however. In this example, all Fish have attributes named Number and Color , but the two Fish objects have different values for these attributes.

The combination of the values for all the attributes of an object is called the object’s state . Unlike its identity, an object’s state can — and usually does — change over its lifetime. Some fish can change colors, for example. The total sales for a particular customer changes each time the customer buys another product. The grade-point average for a student changes each time a new class grade is recorded. The address and phone number of an employee change if the employee moves.

Here are a few more interesting details about object state:

Objects have behavior

Another characteristic of objects is that they have behavior, which means that they can do things. Like state, the specific behavior of an object depends on its type. But unlike state, behavior isn’t different for each instance of a type. Suppose that all the students in a classroom have calculators of the same type. Ask them all to pull out the calculators and add two numbers — any two numbers of their choosing. All the calculators display a different number, but they all add in the same way — that is, they all have a different state but the same behavior.

Another way to say that objects have behavior is to say that they provide services that can be used by other objects. You’ve already seen plenty of examples of objects that provide services to other objects. Objects created from the NumberFormat class, for example, provide formatting services that turn numeric values into nicely formatted strings such as $32.95 .

In Java, the behavior of an object is provided by its methods. Thus the format method of the NumberFormat class is what provides the formatting behavior for NumberFormat objects.

Here are a few other notable points about object behavior:

Understanding the Life Cycle of an Object

As you work with objects in Java, understanding how objects are born, live their lives, and die is important. This topic is called the life cycle of an object, and it goes something like this:

  1. Before an object can be created from a class, the class must be loaded. To do that, the Java runtime locates the class on disk (in a .class file) and reads it into memory. Then Java looks for any static initializers that initialize static fields — fields that don’t belong to any particular instance of the class, but belong to the class itself and are shared by all objects created from the class.

    A class is loaded the first time you create an object from the class or the first time you access a static field or method of the class. When you run the main method of a class, for example, the class is initialized because the main method is static.

  2. An object is created from a class when you use the new keyword. To initialize the class, Java allocates memory for the object and sets up a reference to the object so that the Java runtime can keep track of it. Then Java calls the class constructor, which is like a method but is called only once: when the object is created. The constructor is responsible for doing any processing required to initialize the object — initializing variables, opening files or databases, and so on.
  3. The object lives its life, providing access to its public methods and fields to whoever wants and needs them.
  4. When it’s time for the object to die, the object is removed from memory, and Java drops its internal reference to it. You don’t have to destroy objects yourself. A special part of the Java runtime called the garbage collector takes care of destroying all objects when they are no longer in use.

Working with Related Classes

So far, most of the classes you’ve seen in this book have created objects that stand on their own, each being a little island unto itself. The real power of object-oriented programming, however, lies in its ability to create classes that describe closely related objects.

Baseballs, for example, are similar to softballs. Both are specific types of balls. Each type has a diameter and a weight; both types can be thrown, caught, or hit. Baseballs and softballs, however, have different characteristics that cause them to behave differently when they’re thrown, caught, or hit.

If you’re creating a program that simulates the way baseballs and softballs work, you need a way to represent these two types of balls. One option is to create separate classes to represent each type of ball. These classes are similar, so you can just copy most of the code from one class to the other.

Another option is to use a single class to represent both types of balls. Then you pass a parameter to the constructor to indicate whether an instance of the class behaves like a baseball or like a softball.

Java has two object-oriented programming features that are designed specifically to handle classes that are related this way: inheritance and interfaces. I briefly describe these features in the following sections.

Inheritance

Inheritance is an object-oriented programming technique that lets you use one class as the basis for another. The existing class is called the base class, superclass, or parent class; the new class that’s derived from it is called the derived class, subclass, or child class.

When you create a subclass, the subclass is automatically given all the methods and fields defined by its superclass. You can use these methods and fields as is, or you can override them to alter their behavior. In addition, you can add methods and fields that define data and behavior that’s unique to the subclass.

You could use inheritance to solve the baseball/softball problem from the preceding section by creating a class named Ball that provides the basic features of all types of balls and then using it as the base class for separate classes named BaseBall and SoftBall . Then these classes could override the methods that need to behave differently for each type of ball.

One way to think of inheritance is as a way to implement is-a-type-of relationships . A softball is a type of ball, as is a baseball. Thus inheritance is an appropriate way to implement these related classes. (For more information about inheritance, see Book 3, Chapter 4 .)

Interfaces

An interface is a set of methods and fields that a class must provide to implement the interface. The interface itself is simply a set of public method and field declarations that are given a name. Note that the interface itself doesn’t provide any code that implements those methods. Instead, it just provides the declarations. Then a class that implements the interface provides code for each of the methods the interface defines.

You could use an interface to solve the baseball/softball problem by creating an interface named Ball that specifies all the methods and fields that a ball should have. Then you could create the SoftBall and BaseBall classes so that they both implement the Ball interface.

Interfaces are closely related to inheritance but have two key differences:

You find out more about interfaces in Book 3, Chapter 5 .

Designing a Program with Objects

An object-oriented program usually isn’t just a single object. Instead, it’s a group of objects that work together to get a job done. The most important part of developing an object-oriented program is designing the classes that are used to create the program’s objects. The basic idea is to break a large problem into a set of classes, each of which is manageable in size and complexity. Then you write the Java code that implements those classes.

So the task of designing an object-oriented application boils down to deciding what classes the application requires — and what the public interface to each of those classes should be. If you plan your classes well, implementing the application is easy. If you plan your classes poorly, you’ll have a hard time getting your application to work.

One common way to design object-oriented applications is to divide the application into several distinct layers or tiers that provide distinct types of functions. Most common is a three-layered approach, as shown in Figure 1-1 . Here the objects of an application are split into three basic layers:

image

FIGURE 1-1: Three-layered design.

Diagramming Classes with UML

Since the very beginning of computer programming, programmers have loved to create diagrams of their programs. Originally, they drew flowcharts that graphically represented a program’s procedural logic.

Flowcharts were good at diagramming procedures, but they were way too detailed. When the structured programming craze hit in the 1970s, and programmers started thinking about the overall structure of their programs, they switched from flowcharts to structure charts, which illustrated the organizational relationships among the modules of a program or system.

Now that object-oriented programming is the thing, programmers draw class diagrams to illustrate the relationships among the classes that make up an application. Figure 1-2 shows a class diagram of a simple system that has four classes. The rectangles represent the classes themselves, and the arrows represent the relationships among the classes.

image

FIGURE 1-2: A simple class diagram.

You can draw class diagrams in many ways. To add some consistency to their diagrams, most programmers use a standard called UML, which stands for Unified Modeling Language . The class diagram in Figure 1-2 is an example of a simple UML diagram, but UML diagrams can get much more complicated.

The following sections describe the details of creating UML class diagrams. Note that these sections don’t even come close to explaining all the features of UML. I include just the basics of creating UML class diagrams so that you can make some sense of UML diagrams when you see them and so that you know how to draw simple class diagrams to design the class structure for your applications.

Drawing classes

The basic element in a class diagram is a class. In UML, each class is drawn as a rectangle. At minimum, the rectangle must include the class name. You can subdivide the rectangle into two or three compartments that can contain additional information about the class, as shown in Figure 1-3 .

image

FIGURE 1-3: A class.

The middle compartment of a class lists the class variables, whereas the bottom compartment lists the class methods. The name of each variable or method can be preceded by a visibility indicator, which can be one of the symbols listed in Table 1-1 . (In actual practice, it’s common to omit the visibility indicator and list only those fields or methods that have public visibility.)

TABLE 1-1 Visibility Indicators for Class Variables and Methods

Indicator

Description

+

Public

Private

#

Protected

If you want, you can include type information for variables as well as for methods and parameters. The type of a variable is indicated by following the variable name with a colon and the type:

connectionString: String

A method’s return type is indicated in the same way:

getCustomer(): Customer

Parameters are listed within the parentheses, and both the name and type are listed. For example:

getCustomer(custno: int): Customer

Note: Omitting the type and parameter information from UML diagrams is common.

tip Interfaces are drawn pretty much the same way as classes, but the class name is preceded by the word interface :

<<interface>>
ProductDB

Note: The word interface is enclosed within a set of double-left and double-right arrows. These arrows aren’t just two less-than or greater-than symbols typed in a row; they’re a special combination of symbols. Fortunately, the double-arrow symbol is a standard part of the ASCII character set. You can access it in Microsoft Word via the Insert Symbol command.

Drawing arrows

Besides using rectangles to represent classes, class diagrams include arrows to represent relationships among classes. UML uses a variety of types of arrows, as I describe in the following paragraphs.

A solid line with a hollow closed arrow at one end represents inheritance:

image

The arrow points to the base class. A dashed line with a hollow closed arrow at one end indicates that a class implements an interface:

image

The arrow points to the interface. A solid line with an open arrow indicates an association :

image

An association simply indicates that two classes work together. It may be that one of the classes creates objects of the other class or that one class requires an object of the other class to perform its work. Or perhaps instances of one class contain instances of the other class.

You can add a name to an association arrow to indicate its purpose. If an association arrow indicates that instances of one class create objects of another class, you can place the word Creates next to the arrow.