Chapter 3

Object-Oriented Programming with Java

by Bryan Morgan


CONTENTS

One of the most overused words in the field of software development is object. Because developers realize the value of object-based design and development, tool makers and other manufacturers continually market themselves as object based or object oriented. Fortunately for the Visual J++ programmer, the Java language truly is a full-featured, object-oriented language. This chapter presents the basic tenets of object-oriented programming and gives examples that show how Java supports these basic principles.

What Is Object-Oriented Programming?

Before delving into the specifics of Java's object-oriented nature, you need to understand what object-oriented programming (OOP) is and why it is important. OOP is, at its highest level, the process of building applications or systems with objects. To a mechanical engineer or construction supervisor, this concept may seem like an obvious way to do things. In fact, examining the process of building a house, you can draw some interesting parallels between home construction and object-oriented software construction.

Before you begin to build a house, you must complete several steps, such as purchasing bricks, roofing materials, and wood for framing and laying a foundation. You also have to decide how to acquire the bricks:

The builder will be forced to make similar choices throughout the building process. Although you could go to a forest, cut down some trees, and produce lumber for your construction project, you probably would not choose to do so. Because the most commonly used building objects are used by so many people, the building industry has established a widely accepted set of properties and potential uses for various objects. This system allows you to avoid "reinventing the wheel" and concentrate on actually constructing the house. When a particular object such as a door has a problem (that is, it won't lock), it is quite simple to locate that object, repair it, or replace it.

Object-oriented programming is used to build applications out of building blocks, or objects. These objects can be either source code objects (as is the case with Java or C++ classes) or binary objects (such as ActiveX or CORBA objects). A true object-oriented programming language supports the following properties:

These properties are explained in detail in the following sections.

Encapsulation

The goal of object-oriented programming is to allow the software developer to construct software in the same way that the builder builds a house. No matter what type of system is being developed, programmers can always group together common functionalities and features in the form of software objects. For instance, graphical user interfaces repeatedly use a common group of objects such as buttons, dialog boxes, and menu items. Each of these objects has a set of properties (Color, Font, Height) and methods (Show, Close, Create, Resize). Because these features are grouped together within an object named Button, for instance, programmers are not forced to think of an item's data separately from that item's behavior. This feature is known as encapsulation.

Inheritance

Suppose now that you have chosen to redesign an application written for your local public library. This application was written in a procedural language such as C, FORTRAN, BASIC, or Pascal. After analyzing your application, you see that a large group of objects share the same properties. Things such as science fiction books, computer books, history books, and cookbooks all have a common set of features: an author, a publisher, a price, and an identification number used by the library. Each book can also be checked out, checked in, purchased, or sold.

Ideally, a programmer developing in an object-oriented language could define a parent object named Book that contains these properties. Each individual book type then could be implemented as a child of the parent object Book. This hierarchy would allow all the common functionality of each book to reside in one place without being repeated for each object that shares the functionality. Each specific book type would also then appear to be much simpler to anyone viewing your code. This is because each type of book inherits from the "parent" Book and therefore inherits all of that object's public member variables and methods. The new "child" object gains all this underlying functionality without writing any new code!

Object-oriented programming implements this process through a feature known as inheritance. Inheritance allows child objects to be derived from parent objects, which ultimately means that programmers can reuse code. For instance, the CheckIn or CheckOut methods for a ScienceFiction book probably do not differ in any way from the methods for a History book. By making these methods part of the parent Book class, they would automatically be inherited by the Book class's children.

Polymorphism

In many situations, however, all aspects of the parent's behavior may not be passed on to the child. (We all know that this happens in real life, so why not in programming?!?) The parent Book object could have a method called Catalog that was used to place a book on a shelf. Because the shelf location of this book depends on what type of book it is, the Book object would probably specify a default behavior that was intended to be overridden. In a procedural language, the programmer might write something like the following:


if Book = ScienceFiction then

 PutOnScienceFictionShelf()

else if Book = History then

 PutOnHistoryShelf()

else if Book = Cooking then

 PutOnCookingShelf()

else if Book = Computer then

 PutOnComputerShelf();

if...then...else statements like this result in unnecessarily large amounts of code to be maintained, particularly when all the methods (such as PutOnScienceFictionShelf) produce the same basic result: putting a book on a shelf. Object-oriented programming allows child classes to provide new implementations of their parent's properties and methods if so desired. This feature is known as polymorphism. Polymorphism is a big word that means a child can change its inherited behavior without changing the primary intent of that behavior. Using OOP, if the Book object contained a method known as PutOnShelf, the child objects ComputerBook, HistoryBook, CookingBook, and ScienceFictionBook would all inherit this method. However, thanks to OOP, each child object implements its own PutOnShelf method that overrides the parent's behavior. Therefore, when a child object's PutOnShelf methods are called, the child's-not the parent's-implementation will be called.

Some programming languages (such as Java and C++) take the concept of polymorphism a step further. Java allows programmers to duplicate behavior within an object, not just via inheritance. Recall the method named PutOnShelf in the previous example. In Java and C++, a single object can provide several methods named PutOnShelf that can all reside within the same object as long as each method accepts different arguments. The following methods would all be legal within a C++ class:

The concept of polymorphism allows the programmer to build an object that can be reused within an application or across multiple applications. The base class (or parent object) could have a default implementation consisting of actions and data. Each of these actions would specify a specific set of parameters. These sets of parameters define the protocol that is used to interact with other objects within a program. If child objects were derived from this parent object, these actions could be redefined to meet the child objects' purposes.

Information Hiding and Object-Oriented Programming

As you are now aware, every object-oriented language allows programmers to model real-world attributes as programming objects. Although syntax varies from language to language, the key feature of object-oriented languages is that programmer-created objects can be reused throughout an application as a new data type.

The ability to create new data types that can be reused is the characteristic that makes object-oriented programming languages special. In Java and C++, a new object is known as a class. In Object Pascal (used by Borland Delphi), a new object is known as a type. All object-oriented languages share the features of encapsulation, inheritance, and polymorphism.

Note
In the case of C++ and Java, the words class and object are often used interchangeably. The convention most often used is to refer to a type that has been defined within source code as a "class." Once this class has been instantiated and resides in memory within a program, most developers refer to it as an "object."

Some object-oriented languages also allow the creator of an object to restrict access to that object's attributes. This feature allows the designer of an object to hide variables or methods from other objects or, as is more common, to force other objects to access data in a standard way. Suppose, for instance, that you want a flag to be set whenever a variable is updated. The way to ensure that the flag is set correctly within your object is to force another object to call a Set() method.

Restricting Access to Members

Restricting access to an object is accomplished through the use of keywords such as public, protected, and private. (Both Java and C++ support the use of these keywords.) The meanings of these restrictions are as follows:

Java also allows objects themselves to be created as public or private. Only one public object can be created within a single source file, although multiple private objects can be created within that same source file. The catch is that because these objects are designated as private, they can only be used by the public class within that source file. The following example shows a public and private class that could be created within the same source file:


public class Class1

{

  int x;

  DoSomethingWithX(int x);

}



private class Class2

{

  int y;

  DoSomethingWithY(int y);

}

This brief introduction to the basic concepts of encapsulation, inheritance, polymorphism, and access restriction should help you understand the following discussion of objects, as well as the object-oriented specifics of the Java language.

An Object-Oriented Example

This brief demonstration of encapsulation, inheritance, polymorphism, and access restriction builds a set of objects to represent employees within a company. Each employee is an autonomous object that can stand alone. However, for a company to be successful, the employees need to be able to interact in a meaningful fashion.

Note
Keep in mind that the following objects are built using what is often called pseudocode. Try to focus on the concepts being discussed and rest assured that the Java syntax will be covered in detail later.

The People Object

Although many different types of employees work within a company, this example assumes that all employees are people. (I realize that this may be a stretch in certain cases, but some generalizations have to made to simplify this example.) Therefore, the People object should encapsulate the common information and behavior of a standard employee. Using the pseudo-language, the first step is to add the data that should apply to every employee:


Object People  {

string Name;

string Address;

int Age;

long SSN;

long Salary;

char Sex;

bool Married;

int YearsOfService;

}

The preceding set of properties should look very familiar to most programmers-even to someone who is new to object-oriented programming. In fact, the structure could be created in just about every programming language in existence today. However, data alone is not enough to accurately model the typical person. In addition to the set of data that provides information about the person, each person also performs a set of routine actions throughout the day. Object-oriented languages allow programmers to use encapsulation to mix information and actions together. The next step is to use the pseudo-language to add some behavior to the People object:


Object People  {

string Name;

string Address;

int Age;

long SSN;

long Salary;

char Sex;

bool Married;

int YearsOfService;

void DriveToWork(int TimeLeft);

void DriveBackHome(int TimeLeft);

String DoWork();

void GoToLunch();

}

Through encapsulation, the object's variables and methods have been combined into a single, autonomous entity. This object could be used to apply to every employee within a company, but it is very generic. Although identifiers like name, address, or salary may mean the same thing for every employee, the method DoWork() could be dramatically different depending on an employee's job title. This set of common features coupled with individual differences can be represented best using inheritance.

Now you can use the public, private, and protected keywords to take advantage of the object-oriented pseudo-language's information-hiding features. The following object is similar to the People object created earlier, only now the Salary variable is hidden from all other objects:


Object People  {

string Name;

string Address;

int Age;

long SSN;

private long Salary;

char Sex;

bool Married;

int YearsOfService;

void DriveToWork(int TimeLeft);

void DriveBackHome(int TimeLeft);

String DoWork();

void GoToLunch();

}

After this change has been made, all classes deriving from the People class are unable to access the Salary class. In many cases, it is considered good programming style to hide all variables from public view by making them private. Data access methods are then provided as public methods so that other objects can have access to an object's data. The following class provides access to a member variable through the use of data access methods:


Object People  {

string Name;

string Address;

int Age;

long SSN;

private long Salary;

char Sex;

bool Married;

int YearsOfService;

void DriveToWork(int TimeLeft);

void DriveBackHome(int TimeLeft);

String DoWork();

void GoToLunch();

public void SetSalary(long newSalary);

public long GetSalary();

}

Using access methods (such as SetSalary() and GetSalary()) prevents users from inadvertently modifying data. In addition, using access methods makes your code more readable and also allows the creator of an object to fully control access to an object's data. For example, you might want to store a boolean value in the object that would be true if the person received a raise. To do so, add the following line to the SetSalary() method: ReceivedRaise := True;. This line adds functionality to your object without changing a single line of code anywhere else within the application.

Using the People Object to Create Employees

Most technical organizations have three primary types of employees: support, technical, and managerial. Each of these primary types of employees is responsible for performing specific tasks. If any of these groups is missing, the organization cannot function in an optimal fashion. Therefore, the next step in this example is to create three new employee objects: Support, Technical, and Managerial. To provide these objects with some basic functionality, they will be derived from the existing People object.

The process of creating the Support object demonstrates the concepts of inheritance and polymorphism. This type of employee can be thought of as performing work that is not directly turned into profit for the company. Examples of support personnel are secretaries, receptionists, and accountants. Obviously, the work an accountant does is a necessity, but an accountant's output cannot be sold to a customer. Therefore, support personnel are generally classified by whom they support and by the services they offer. The following Support object inherits from the People class:


Object Support Inherits From People {

string Department;

void ReceiveInstructions();

void ReportFindings();

void DoWork();

}

Notice that the Support object is designated to inherit all of People's attributes. Also note that the DoWork() method is listed in order to override the default DoWork() behavior of the People object. In an actual implementation, the People object's DoWork() method will probably be left blank. Each child object would then be responsible for providing the functionality for this method.

Java: Fully Buzzword Compliant

One of the creators of Java, James Gosling, has stated that Java is fully buzzword compliant; in other words, Java is an object-oriented, thread-safe, distributed, secure, and platform-independent language. Although much has been made of Java's platform independence, Microsoft has publicly stated that Java is also a great programming language. Java's designers included nearly every feature valued by developers and intentionally left out many extraneous, more cumbersome programming features. This section focuses on how Java supports object-oriented programming.

Encapsulation Using a Class

Unlike languages such as C++ and Object Pascal, every line of code written in Java must occur within an object (known as a class).

Note
Although C++ provides the ability to encapsulate data and methods together within a class, it allows programmers to use data and methods outside a class, as well.

The syntax used to create a new class in Java is


Modifier class className [extends ParentClass] [implements Interfaces]

{

/* Provide class variables and methods */

}

Modifier can be any of the following keywords:

Because Java supports encapsulation, variables and methods can be combined within a class. Listing 3.1 should give you some idea of how to create classes in Java.


Listing 3.1. Sample Java classes.

public class Animal  {

String Species;

int Age;

int NumberOfLegs;

int IQ;

int Run(int speed);

}



public final Automobile  {

String Manufacturer;

int Year;

int Price;

int Doors;

int Drive(int speed);

}



private class Button  {

Color FaceColor;

String Caption;

private int Size;

int Press(int velocity);

}


The classes in Listing 3.1 illustrate the creation of some simple Java classes. The first class, Animal, is declared as a public class. The second class, Automobile, is declared as a public final class. Therefore, other classes can access the Automobile class, but no other class can derive from it. The final class, Button, is declared with the private modifier, which means that it can be used only by other classes within its source file. Note that the final member variable, Size, was itself declared as private.

Just as classes can be declared using a variety of modifiers, Java also allows the class designer to use a variety of method and field modifiers to control access to class members. Each method and variable within a class can be prefixed with any of the following modifiers:

public-A method or variable declared as public can be accessed by any class.
protected-A method or variable declared as protected can be accessed only by subclasses.
private-A method or variable declared as private can be accessed only by other methods within this class.
<empty>-If no modifier is given, the method or variable can be accessed by any other class within this class's package.
static-The static modifier designates a method or variable that is shared globally by all instances of this class.
native-The native modifier denotes a native method that is implemented in another language, such as C. Native methods are discussed in detail in Chapter 7 "Advanced Java Programming."
final-final specifies a method or variable that is constant (for a variable) or cannot be overridden by a subclass (for a method). A constant variable is a variable whose value cannot be changed at runtime. Once the variable is initialized to some value, that value is set for the duration of the application.
synchronized-The synchronized keyword locks this object when a method is entered and unlocks it when this method exits. A method is entered when it is called by some other method. You can exit a method by issuing the return statement or by completing all the statements within that method.

It is possible to create a simple class using the information just presented. However, one of the most important features of object-oriented programming is reuse of code through inheritance.

Inheriting from Other Classes

Java supports inheritance through the use of the extends keyword. In Java-speak, if a class Dog is derived from a parent class Animal, Dog extends Animal. The example in Listing 3.2 shows you how to extend objects through inheritance.


Listing 3.2. Extending objects through inheritance.

public class Animal extends LifeForm  {

String Species;

int Age;

int NumberOfLegs;

int IQ;

int Run(int speed);

}



public final Automobile extends Vehicle  {

String Manufacturer;

int Year;

int Price;

int Doors;

int Drive(int speed);

}



private class Button extends Component {

Color FaceColor;

String Caption;

private int Size;

int Press(int velocity);

}


Unlike C++, Java supports only single inheritance-that is, an object can inherit from only one other class. Although single inheritance may seem restrictive, most classes that you create only need to derive from one other class. Java does allow programmers to extend the functionality of a class in another way: through the use of interfaces. In addition, you can group related classes and interfaces to form packages.

Interfaces and Packages

An interface is a declaration of a set of methods whose implementation is not provided. You can think of an interface as a contract between the interface designer and the "implementor" of the interface (the class designer). The class that implements the interface is responsible for providing the actual implementation of the interface's methods. Java is interesting in that it allows classes to be typecast as interfaces; that is, a class can be passed as an interface argument as long as the class actually implements the interface. This implementation is done through the use of the implements keyword. Interfaces can be derived from one or more other interfaces. Keep in mind also that although a class can inherit only from one other class, it can implement as many interfaces as it chooses!

Listing 3.3 includes an example of an interface (the Behavior interface). Behavior specifies a group of methods that collectively make up the behavior of some form of life. The implementation of these methods is left to the implementor of the interface.


Listing 3.3. Extending an object using inheritance and interfaces.

public interface Behavior  {

void Eat();

void Breathe();

void Sleep();

}



public class Animal extends LifeForm implements Behavior {

String Species;

int Age;

int NumberOfLegs;

int IQ;

int Run(int speed);



void Eat() {

/* Provide implementation here */

  };



void Breathe()  {

/* Provide implementation here */

  };



void Sleep()  {

/* Provide implementation here */

  };

}


Once you have built up a library of classes and interfaces that have something in common, you can place the group of objects into a package by adding the following line to the beginning of each source file:


package PackageName;

Imagine that you have created an entire library of classes to represent living creatures, including the following:

You can group these classes and interfaces together into a package named Creature by placing the text package Creature; at the beginning of each source file containing the classes and interfaces.

As you may be aware, Visual J++ comes with a large number of packages, each of which contains many classes and interfaces. Because a primary focus of object-oriented programming is the reuse of objects created by you or by others, this chapter includes an explanation of the packages (also referred to as the class library) that ship with Visual J++. First, however, take a look at an interesting example of classes and interfaces within the java.applet package that is a standard package in every runtime Java environment.

Case Study: The java.applet Package

No matter which platform you are running your Java code on, installed somewhere with the Java Virtual Machine is a package known as the java.applet package. You can find it by locating a java subdirectory and then by locating the applet subdirectory under it.

Note
A Java convention is to create package names based on their underlying directory structure. For instance, to create a subpackage named Package1.Package2.Package3, a directory named Package1 would be created followed by a subdirectory Package2 and a sub-subdirectory Package3. All of subpackage Package3's files would be stored in the Package3 subdirectory.

The java.applet package contains a number of classes and interfaces. This java.applet package provides the basic set of classes used to create an actual Java applet. (A Java applet is a small program that is capable of running within a Web page. Java applets are discussed in great detail throughout this book.)

The java.applet package contains the Applet class as well as three interfaces: AppletContext, AppletStub, and AudioClip. The various interfaces were designed by Sun to be used by Web browsers. It is left up to each browser manufacturer to provide its own implementations of these interfaces. For example, the AudioClip interface defines the following methods:


public interface AudioClip {

public abstract void play()

public abstract void loop()

public abstract void stop()

}

Because AudioClip is an interface, the implementation of these methods is left to the class developer. Therefore, if the developers of the Netscape Navigator browser decide to support WAV sound files, they simply need to provide a class that implements the AudioClip interface that is capable of playing, looping, and stopping WAV sound files.

A better example of interfaces in use is the Applet class itself. The Applet class looks like this:


public class Applet extends Panel {

public final void setStub(AppletStub stub)

public boolean isActive()

public URL getDocumentBase()

public URL getCodeBase()

public String getParameter(String name)

public AppletContext getAppletContext()

public void resize(int width, int height)

public void resize(Dimension d)

public void showStatus(String msg)

public Image getImage(URL url)

public Image getImage(URL url, String name)

public AudioClip getAudioClip(URL url)

public AudioClip getAudioClip(URL url, String name)

public String getAppletInfo()

public String[][] getParameterInfo()

public void play(URL url)

public void play(URL url, String name)

public void init()

public void start()

public void stop()

public void destroy()

}

Notice that the setStub method accepts an AppletStub interface as a parameter. The AppletStub interface allows the Applet class to retrieve information from its surrounding environment (known as the applet context). Because AppletStub was defined as an interface, the designers of the java.applet package did not need to write an implementation for each environment that a Java applet would ever run in. Instead, this environment can be described in terms of an interface that the developers of Web browsers, such as Microsoft and Netscape, can implement.

Here are the methods defined by the AppletStub and AppletContext interfaces:


public interface AppletStub {

public abstract boolean isActive()

public abstract URL getDocumentBase()

public abstract URL getCodeBase()

public abstract String getParameter(String name)

public abstract AppletContext getAppletContext()

public abstract void appletResize(int width, int height)

}



public interface AppletContext {

public abstract AudioClip getAudioClip(URL url)

public abstract Image getImage(URL url)

public abstract Applet getApplet(String name)

public abstract Enumeration getApplets()

public abstract void showDocument(URL url)

public abstract void showDocument(URL url, String target)

public abstract void showStatus(String status)

}

The Visual J++ Class Library

Most of this discussion of object-oriented programming with Java focuses on the creation of new objects for use in application development. However, most of the objects that you will create during your Java programming experiences will probably inherit from existing objects. These existing objects may be among the hundreds of classes included with Visual J++, or you may have purchased them from a Java-object vendor. (A burgeoning market currently exists for Java classes such as spreadsheets, charts, editors, and other common programming objects.)

The classes included with Visual J++ allow you to inherit from a large body of existing classes used for

Packages containing all these classes are located in the CLASSES.ZIP file that was installed when you installed Visual J++. The default location for this file is the \windows\java\classes directory. To determine the exact location of the file, examine the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Java_VM\ClassPath registry key in the Windows Registry. The following sections discuss the primary packages included in the CLASSES.ZIP file.

The com.ms Package

The com.ms package contains a number of subpackages that are useful in developing COM applications.

Note
Microsoft provides the com.ms package on Microsoft machines only. You will not find this package on non-Microsoft Java Virtual Machine installations.

Subpackages included in the com.ms package include the com, applet, awtX.directx, awtX.win32, and net.wininet subpackages. The com subpackage provides the basic COM functionality for the Iunknown, IID, and IExternalConnectionSink interfaces as well as the definitions of CLSID, GUID, and the Variant COM data type. The DirectX subpackages provide the Java implementations for Microsoft's DirectX graphics API.

The java.applet Package

The java.applet package contains the classes used to create and work with Java applets. Each Java applet is derived directly from the java.applet.Applet class in this package. Interfaces specified in this package are AudioClip, AppletContext, and AppletStub.

The java.awt Package

The java.awt package contains the classes and subpackages that make up the Java Abstract Windowing Toolkit (AWT). The AWT provides the core user interface objects that allow a GUI application written in Java to run on any platform. Examples of classes included within the java.awt package include Button, List, Menu, Checkbox, and Color.

The java.io Package

The java.io package contains the classes used to provide programmers with input/output capabilities in Java. Classes within this package allow developers to read and write from streams to standard input/output, files, and byte arrays. Examples of classes within the java.io package are FileInputStream, FileOutputStream, PrintStream, and DataInputStream.

The java.lang Package

The java.lang package contains the classes that correspond to the Java primitive data types (int, float, boolean, char, byte, long, short, and double). Also included in this package are the System and Thread classes. The System class provides access to system information such as operating system name and vendor and Java Virtual Machine version and vendor. The Thread class provides multithreading capabilities to applets or applications.

The java.net Package

The java.net package includes classes that can be used to open sockets for communication between processes on remote machines. Also included in this package are the URL and InetAddress classes. These classes are used to encapsulate World Wide Web addresses and information.

The java.util Package

The java.util package provides the developer with a large number of utility classes. These classes include common data structures such as HashTable, Dictionary, Stack, and Vector. Also included in the java.util package are the Date, Properties, and Random classes. Each of these classes provides a number of useful methods and properties that may be of interest to developers.

The sun Package

Like the com.ms package, the sun package is not guaranteed to be a part of every Java Virtual Machine installation. However, many items currently in the sun package are slated to become permanent parts of the Java package at a later date, so it will continue to be a "test bed" for internal packages developed by Sun Microsystems. Developers should remember that classes within this package are not guaranteed to appear on every user's local machine. Subpackages available within the sun package are applet, audio, awt, misc, and net.

Summary

After being touted in academic circles and large development projects as the development paradigm of choice, object-oriented programming has finally entered the mainstream. This acceptance is partly associated with the popularity of rapid application development environments that speed routine development tasks by providing easy-to-use user interfaces for accomplishing those tasks.

For a language to be considered truly object oriented, it must support inheritance, encapsulation, and polymorphism. Java supports all three of these and in many ways is very similar to the object-oriented C++ language. Classes in Java are used to encapsulate member data and methods. These members can be granted different access levels (public, private, protected, or friendly) depending on the goals of the class designer. Java supports single inheritance of classes but allows multiple implementations of interfaces.

Anyone using J++ needs to become acquainted with the capabilities of the Visual J++ class library, which contains literally hundreds of thousands of lines of prewritten source code. The library includes all popular GUI objects as well as objects to be used in COM, networking, and database access applications.

Chapter 4 "Understanding the Java Base Platform," introduces the Java packages that comprise the Java Base platform. These packages are included with every certified Java Virtual Machine installation. Chapter 5 "Elements of the Java Language," introduces the basic elements of the Java language. This introduction to Java constructs, combined with your knowledge of object-oriented programming, should enable you to design and build Java programs by the time you have finished reading Chapter 6 "Creating Programs with Java."