This chapter is a basic introduction to object-oriented programming. It introduces you to 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.
If you're more of a hands-on type, you may want to just skip this chapter and go straight to Book III, 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.
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:
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:
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 more important of these characteristics: identity, type, state, and behavior.
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 they aren't the same apple. Each has a distinct identity. They're both 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 to one another. However, 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 others 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 us with 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:
I remember studying Naming of Parts, a fine poem written by Henry Reed in 1942, back when I was an English major in college:
Today we have naming of parts. Yesterday,
We had daily cleaning. And tomorrow morning,
We shall have what to do after firing. But today,
Today 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 anti-war 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 each soldier's rifle 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 kind 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. For example, the following 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.
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:
Open table as spreadsheet
The type of an object determines what attributes the object has. Thus, all objects of a particular type have the same attributes. However, they don't necessarily have the same values for those attributes. 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. For example, some fish can change colors. 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. And the address and phone number of an employee change if the employee moves.
Here are a few more interesting details about object state:
Another characteristic of objects is that they have behavior, which means they can do things. Like state, the specific behavior of an object depends on its type. But unlike state, the behavior isn't different for each instance of a type. For example, suppose 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-they all have a different state but the same behavior.
Another way to say that objects have behavior is to say 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. For example, objects created from the NumberFormat class 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:
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:
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. For example, when you run the main method of a class, the class is initialized because the main method is static.
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. However, the real power of object-oriented programming lies in its ability to create classes that describe objects that are closely related to each other.
For example, baseballs are similar to softballs. Both are specific types of balls. Each has a diameter and a weight; both can be thrown, caught, or hit. However, they have different characteristics that cause them to behave differently when thrown, caught, or hit.
If you're creating a program that simulated 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.
However, Java has two object-oriented programming features that are designed specifically to handle classes that are related like this: inheritance and interfaces. I briefly describe these features in the following sections.
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 additional 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 previous 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. For example, 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 III, Chapter 4.)
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 about interfaces in Book III, Chapter 5.
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 down into a set of classes that are each 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. But if you poorly plan your classes, 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. The most common is a three-layered approach, as shown in Figure 1-1. Here the objects of an application are split up into three basic layers:
Figure 1-1: Three-layered design.
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. For example, the simple class diagram shown in Figure 1-2 shows a class diagram for a simple system that has four classes. The rectangles represent the classes themselves, and the arrows represent the relationships among the classes.
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 than this example.
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 help you design the class structure for your applications. If you're interested in digging deeper into UML, check out UML 2 For Dummies by Michael Jesse Chonoles and James A. Schardt (Wiley Publishing, Inc.).
The basic element in a class diagram is a class. In UML, each class is drawn as a rectangle. At the minimum, the rectangle must include the class name. However, you can subdivide the rectangle into two or three compartments that can contain additional information about the class, as shown in Figure 1-3.
Figure 1-3: A class.
The middle compartment of a class lists the class variables, while 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.)
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:
A method's return type is indicated in the same way:
Parameters are listed within the parentheses, and both the name and type are listed. For example:
getCustomer(custno: int): Customer
Omitting the type and parameter information from UML diagrams is common.
Interfaces are drawn pretty much the same as classes, but the class name is preceded by the word interface:
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.
Besides rectangles to represent classes, class diagrams also include arrows to represent relationships among classes. UML uses a variety of different types of arrows, as I describe in the following paragraphs.
A solid line with a hollow closed arrow at one end represents inheritance:
The arrow points to the base class. A dashed line with a hollow close arrow at one end indicates that a class implements an interface:
The arrow points to the interface. A solid line with an open arrow indicates an association:
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. For example, 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.
Book I - Java Basics
Book II - Programming Basics
Book III - Object-Oriented Programming
Book IV - Strings, Arrays, and Collections
Book V - Programming Techniques
Book VI - Swing
Book VII - Web Programming
Book VIII - Files and Databases
Book IX - Fun and Games