Object-oriented programming (or OOP for short) is the dominant programming paradigm these days, having replaced the "structured," procedural programming techniques that were developed in the early 1970s. Java is totally object oriented, and it is impossible to program it in the procedural style that you may be most comfortable with. We hope this section—especially when combined with the example code supplied in the text and on the companion web site—will give you enough information about OOP to become productive with Java.
Let's begin with a question that, on the surface, seems to have nothing to do with programming: How did companies like Compaq, Dell, Gateway, and the other major personal computer manufacturers get so big, so fast? Most people would probably say they made generally good computers and sold them at rock-bottom prices in an era when computer demand was skyrocketing. But go further—how were they able to manufacture so many models so fast and respond to the changes that were happening so quickly?
Well, a big part of the answer is that these companies farmed out a lot of the work. They bought components from reputable vendors and then assembled them. They often didn't invest time and money in designing and building power supplies, disk drives, motherboards, and other components. This made it possible for the companies to produce a product and make changes quickly for less money than if they had done the engineering themselves.
What the personal computer manufacturers were buying was "prepackaged functionality." For example, when they bought a power supply, they were buying something with certain properties (size, shape, and so on) and a certain functionality (smooth power output, amount of power available, and so on). Compaq provides a good example of how effective this operating procedure is. When Compaq moved from engineering most of the parts in its machines to buying many of the parts, it dramatically improved its bottom line.
OOP springs from the same idea. Your program is made of objects, with certain properties and operations that the objects can perform. Whether you build an object or buy it might depend on your budget or on time. But, basically, as long as objects satisfy your specifications, you don't care how the functionality was implemented. In OOP, you only care about what the objects expose. So, just as computer manufacturers don't care about the internals of a power supply as long as it does what they want, most Java programmers don't care how an object is implemented as long as it does what they want.
Traditional structured programming consists of designing a set of procedures (or algorithms) to solve a problem. After the procedures were determined, the traditional next step was to find appropriate ways to store the data. This is why the designer of the Pascal language, Niklaus Wirth, called his famous book on programming Algorithms + Data Structures = Programs (Prentice Hall, 1975). Notice that in Wirth's title, algorithms come first, and data structures come second. This mimics the way programmers worked at that time. First, you decided how to manipulate the data; then, you decided what structure to impose on the data to make the manipulations easier. OOP reverses the order and puts data first, then looks at the algorithms that operate on the data.
The key to being most productive in OOP is to make each object responsible for carrying out a set of related tasks. If an object relies on a task that isn't its responsibility, it needs to have access to another object whose responsibilities include that task. The first object then asks the second object to carry out the task. This is done with a more generalized version of the procedure call that you are familiar with in procedural programming. (Recall that in the Java programming language these procedure calls are usually called method calls.)
In particular, an object should never directly manipulate the internal data of another object, nor should it expose data for other objects to access directly. All communication should be through method calls. By encapsulating object data, you maximize reusability, reduce data dependency, and minimize debugging time.
Of course, just as with modules in a procedural language, you will not want an individual object to do too much. Both design and debugging are simplified when you build small objects that perform a few tasks, rather than building humongous objects with internal data that are extremely complex, with hundreds of procedures to manipulate the data.