Previous Page TOC Next Page



— 9 — Java Objects

Object-oriented programming is a hot topic in programming these days; it seems as though every manufacturer is jumping on the bandwagon with object-oriented products. Java is no exception. However, centering Java around objects makes sense. The function of Web applets fits well with an approach to programming that attempts to break up programs into objects. Learning object-oriented programming (or OOP) is easily one of the most difficult subjects for the beginner in Java. Have no fear though, it is also one of the most rewarding.

Programming languages and methods of programming have been evolving since the first computer program was written, and with the rapid pace of advancement in the computer industry, you would think software development would keep pace with the latest advancements. Unfortunately, this usually isn't the case. It can take a very long time before a new way of programming takes hold among the general programming population. The explosion of interest in and use of object-oriented programming recently is a testament to just how revolutionary it has been.

existing product; it IS object-oriented from the ground up. - Tech Ed

Revised. -Ken

The Basics of Object-Oriented Programming

since the first computer program was written, and with the rapid pace of advancement in the computer industry, development this usually isn't the case. It way of programming takes hold among the general programming population.he explosion of interest in and use of the last has been.

Object-oriented programming is an attempt to model computer programs as closely as possible on objects in the real world. Modeling in this case means trying to use real-world concepts of objects in your programs. For instance, if your program dealt with oranges, you would make orange objects.

However, for many years, the standard approach to developing all but the simplest program was what is referred to as procedural programming.

With procedural programming, you would ask general questions about what you wanted the program to do. Suppose you were writing a program to control a soda-vending machine. In a procedural approach, you would split up the process of vending a can of soda into a finite number of steps. You might split it up into something similar to the following steps:

  1. Wait for change to be dropped into machine.

  2. If enough change has been taken, enable the soda choice buttons.

  3. If soda selected is not empty, dispense soda.

  4. Dispense any change.

Each of these steps would be a procedure, which is a block of code with a name attached to it. Each procedure could pass information to every other procedure. For instance, the first procedure would tell the second procedure how much money had been added, and the second procedure would call the first procedure again if there were insufficient money.

This process is a perfectly logical way to model a vending machine, and for many years, it was how things were done. Unfortunately, programmers found that the larger the program got, the more difficult it was to keep track of how procedures interacted.

For instance, each of the procedures would have to pass information back and forth to each other, so you would have to decide ahead of time what was the important information to remember. Thus, procedural programming centered around the process that needed to be programmed without much consideration of the objects involved and the relationships between them.

Also, and in some ways more importantly, it was hard to use the code that had been written for one project in another. Because procedures and design were so interwoven, it was difficult to pull out any one piece and put it into another program.

Object-oriented programming is an attempt to make things easier and more modular. It is based around the idea of looking at a problem as if it existed in the real world and trying to find the objects that would make it up.

Try this approach on the soda-vending machine example. What objects would make up the machine? The first and most obvious one would be the machine itself. What important parts of the machine would need to be modeled? There would need to be at least three objects to give basic functionality:

There are two main things to remember about each of these objects. First, each of these objects has variables that keep track of what is currently going on inside the object. For example, the coin-intake object would definitely know at any given time how much money had been inserted into the machine.

Second, each object has a mechanism to allow other objects to communicate with it. This process is known as messaging, and the parts of the object that enable this process are known as methods. If you are used to programming in other languages, methods are much the same as functions or procedures except that they aren't just floating around in a program, they are attached to specific objects.

Doesn't this feel like a more intuitive, and even more fun, way of programming? You take the problem and divide it up in ways that you might use in the real world. Certainly if you were to build a soda-vending machine, it would need to have a coin-intake device, and by having an equivalent in your program, the program seems to make more sense.

Moreover, dividing your program up into objects makes it much easier to reuse parts of it in other programs. For instance, after finishing the soda-vending machine, you may very well want to model a video-game machine. If the coin-intake mechanism on the soda-vending machine was designed for the general purpose of taking coins (always a good idea), you should be able to take that same object and use it in the new program with no changes to the coin-intake code.

Classes Versus Objects

Objects, as discussed above, are software packages that contain data and the procedures that act on that data. Classes are groups of objects that share the same behavior; they are templates that define what each object of that class looks like by specifying what the data is and what the procedures are. Instances are the actual implementations or realizations of a class; the “real” things that a class describes. Each instance is a separate entity and many instances of a class can exist at one time. Instances have values in the data variables. Even though two or more instances may have exactly the same data values, they are still separate things. Tech Ed

Maybe i’m missing something, but wasn’t what I wrote basically a simplified version of this? -Ken

Before you can start building objects, you need to understand a couple of the more confusing aspects of object-oriented programming. Remember this sentence: Classes are templates, and objects are instances.

In Java, when you want to create a new type of object, you can't just make one. You must first make a blueprint, or template, of the object you want to create. From this template, you can make as many objects as you want. Think of it as a software cookie cutter.

Objects are known as instances of classes. The template has been used to create an object, and the object now exists virtually inside the computer. You can think of an object as the cookie that the cookie cutter creates. If things seem confusing, don't worry. The next section gets to the process of making objects, and things should get much clearer.

Generating Your Own Classes and Objects

The basic syntax to define a class in Java is the following:

     [ClassModifiers] class ClassName {

          // ...

          // Instance variableClass variables and Methods

          // ...

     }

In essence, you are creating your own new data type when you create a class. Much like an the data types discussed in typeChapter 8, this type can now be used throughout your program as many times as you want, and the instances will be independent of each other.independent from all the other ones.

This distinction is important. Because classes are templates for objects and are not the objects themselves, you are creating something that can be used generally, not just a one-shot object.

The ClassModifiers area in the preceding code is an optional field that lets you define how restrictive you want the access to the class to be. This area is discussed in detail later in this chapter. For now, it's safe to just leave it blank.

A Basic Example: Vehicle

The rest of the chapter uses a class library that models vehicles as an example. Although meant mainly as a simple and understandable example, this library could also be used if you were writing a highway simulation or a game with vehicles, basically anywhere you need to model vehicles of any type.

Start with the most general class, a vehicle:

     class Vehicle {

     }

Believe it or not, that's a valid class. It doesn't do much yet, admittedly, but there it is. This code illustrates an important aspect of objects. They are completely general; you can whatever you please with them.

Instance Vvariables

Objects need some way to keep track of their state. The way to allow a class to keep track of its state is to use instance variablevariables. A instance variable can be any of the basic data types discussed in the last chapter, or it can even be another object. The variables are defined within the block (between the curly brackets) of the class.

What would be some obvious things to keep track of in the generic vehicle class? You don't want to include things like number of wheels because a generic vehicle is not necessarily a land vehicle. However, two things that every vehicle has are a weight and a speed. Add those two states as instance variables to the class:

     class Vehicle {

          int weight;

          int speed;

     }

Now every vehicle created must have a weight and speed. You could choose not to store anything in the created variables, but if that's the case, why include them to begin with?

Encapsulation

Some programming languages, and even Java if you insist, allow you to go ahead and address the instance variables yourself. Thus, after creating an instance of the Vehicle class, you could go in and directly change the weight and speed variables yourself. This is a straightforward way to do things, but unfortunately it has many drawbacks. One of the great things about object-oriented programming is that it allows you to reuse objects without worrying about the code that is contained within the object itself.

Suppose your program was using the Vehicle class, and the Vehicle class had been designed and implemented by someone else. It's quite possible that at some point the designer of the class came to the conclusion that maybe an integer isn't specific enough to hold the weight of many vehicles, but that a special object for weight is needed that holds the unit of measurement (pounds, tons, and so on) in addition to the number.

If you upgraded to the new version of Vehicle class and your program was going into the object and directly modifying the weight, expecting an integer, the compiler would generate an error. Encapsulation keeps this error from happening. Encapsulation is the concept that objects should, in general, not be able to change(or even look at directly) each other's instance variables. How then do you get at those variables? Through methods, that's how.

Methods

A method is much like a function or procedure in other programming languages. It lets you create a block of code that can be called from outside the object and can take arguments and optionally return a value.

The basic syntax for a method is as follows:

     [MethodModifiers] ResultType methodName() {

          // ...

          // Method Body

          // ...

     }

This syntax looks more complicated than it is. The MethodModifiers field is an optional field that enables you to state how restrictive the access to the method should be. Many options are available for this field, but there are only two essential ones to remember:

If this method will only be used within the same file or program it is being defined in, stick with the default by leaving the field blank. If you think the object will be reused, go ahead and make the method public.

You then specify what type of value will be returned by the method. This type can be any of the basic types (like integer, float, and so on) or another class type. If the method does not return a value, use the void keyword.

The Vehicle class should have two methods for each instance variablevariable: one to set the value of the variable, and one to get the value of the variable. To add these methods to the Vehicle class, use the following code:

class Vehicle {

     int weight;

     int speed;

     public void set_weight(int new_weight) {

          weight = new_weight;

     }

     public int get_weight() {

          return weight;

     }

     public void set_speed(int new_speed) {

          speed = new_speed;

     }

     public int get_speed() {

          return speed;

     }

}

Note that the methods that need to return a variable use the keyword return. Make sure that the value that is being returned is the same as the value specified in the method declaration.

Methods declared inside of a class have complete access to all the instance variables defined within that class and can access them as if they were defined inside the method. For example, in the set_weight method, the variable weight specified is the same as the instance variable weight declared at the start of the class with the int weight; statement.

Constructors

When an object is created from the template defined by its class, it often makes sense to have the instance variables set to default values. For instance, for the original example of a soda-vending machine, you might have a boolean flag in the coin intake object to set whether enough money has been added to allow a soda to be dispensed. You probably would want to set this flag to false in the beginning; otherwise, whenever the machine is turned on, it might allow a soda to be dispensed for free.

For the Vehicle example, you might want to set the vehicle's weight and speed to zero by default. You set this default setting by using what is known as a constructor. A constructor is in essence a method that has the same name as the class, is called automatically when an instance of the class is created, and does not return a value. The following code adds a constructor to the Vehicle class:

Vehicle() {

          weight = 0;

          speed = 0;

}

Constructors can also take arguments, if you want to be able to specify initial values when an instance of the object is made. In fact, this is done quite often throughout the Java class library. To enable this feature, just add parameters to the cConstructor:

Vehicle(int start_weight, int start_speed ) {

          start_weight = 0;

          start_speed = 0;

}

Creating Objects

Now that you know how to create basic classes, creating objects (or instances) based upon them is the logical next step. Creating a variable that contains an object takes two steps. First, like any variable, you must declare the variable name for the object and its type somewhere in your program. You perform this step by using the class name as the data type and whatever name you want for the variable. The following code is an example of this process for the Vehicle class:

     Vehicle myVehicle;

At this point, much like an array, nothing is in the variable yet. All you have done is state that eventually myVehicle will contain an object. Next you need to create the object.

Creating an object is quite simple; you use the new keyword followed by the name of the class and any parameters that the class constructor may take. Because the Vehicle constructor does not take any parameters, you don't need to worry about passing it any:

     myVehicle = new Vehicle();

Accessing Methods

Now that you have created the object, the next step is to be able to call the methods in the objects. This step is quite straightforward. To call the method for an object, you just put a period after the object and then the method name followed by parameters, if any. For instance, if you wanted to call the set_weight() method of the myVehicle object created in the last section and set the weight to 1000, you would use the following form:

     myVehicle.set_weight(1000);

A Sample Applet

You now know how to create basic classes, add instance variablevariables and methods to them, create instances of those classes, and access the methods of those instances. This section shows how these elements work from inside an applet.

Because the basics of applets and the Abstract Windows Toolkit (the class library you use to draw on the screen) are not be covered until the next few chapters, this section already provides the essential code you need to demonstrate the Vehicle class. You only need to pay attention to three things inside the TestApplet definition:

  1. A instance variable called myVehicle is declared. This variable is an instance of the Vehicle class.

  2. The only code that should be edited is within the init() method of the TestApplet after the Add Code Here comment. This comment marks the place where your code is run.

  3. A method is called print enables you to print things to the applet screen. You can call this method with either an integer or a string.

The code for the applet is in Listing 9.1. Other than the applet code itself, all the class definitions and object creation are identical to the code examples earlier in this chapter, with the addition of a call to the print method of the applet to output the weight of myVehicle. Figure 9.1 shows tThe running aApplet is shown in Figure 9.1.

import java.awt.*;

import java.lang.*;

class Vehicle {

     int weight;

     int speed;

     Vehicle() {

          weight = 0;

          speed = 0;

     }

     public void set_weight(int new_weight) {

          weight = new_weight;

     }

     public int get_weight() {

          return weight;

     }

     public void set_speed(int new_speed) {

          speed = new_speed;

     }

     public int get_speed() {

          return speed;

     }

}

public class TestApplet extends java.applet.Applet {

     List output;

     Vehicle myVehicle;

     public void init() {

          setLayout(new BorderLayout() );

          output = new List();

          add("Center", output);

          // Add Code Here

          myVehicle = new Vehicle();

          myVehicle.set_weight(1000);

          print(myVehicle.get_weight());

          // Add No Code After This Point

     }

     public void print(int line) {

          output.addItem(String.valueOf(line));

     }

     public void print(String line) {

          output.addItem(line);

     }

}

The following is from the above code? If so, I think it needs an introductory sentence or two explaining what it is. Also, there needs to be a text reference to Fig. 9.1. HS

Ok. Done. -Ken

Here is the HTML for the TestApplet:

<html>

<applet code="TestApplet.class" width=150 height=250>

</applet>

</html>

Figure 9.1. The TestApplet applet demonstrates a simple object.

Inheritance

Thus far you've learned how to define basic classes and create objects, skills which add a great deal of flexibility to the types of programs you can write. The one big aspect of object-oriented programming that you're still missing is inheritance.

Inheritance lets you make new classes that are based upon and extend the functionality of old classes without having to go back and change the original class. This relationship is often called an "is-a" relationship. Thus, if you were creating a class library for representing shapes, you might have a Triangle class that is based on the Shape class. This inheritance fits because a triangle "is-a" shape. Inheriting from another class is quite easy, you just add the keyword extends after the name of the class you are defining, followed by the class you are inheriting from.

Even when you don'’t explicitly inherit from another class, the compiler still makes the class inherited from the generic class Object. This means that aAt the top level, all objects descend from the same class.


Note: You may have already noticed that the code examples from this chapter and previous chapters often contains extends java.applet.Applet. The reason for this line is that all applets are based upon the basic applet class that Sun provides, which gives basic applet functionality. This functionality is discussed in Chapter 10.

Suppose you wanted to add two more specific classes that inherit from the Vehicle class, LandVehicle and AirVehicle. Defining these classes make sense because they are two distinct types of vehicles. Figure 9.2 shows this relationship graphically. In the process, a instance variablevariable is added to each. For LandVehicle, the variable wheels is added to store the number of wheels each vehicle has. For AirVehicle, the variable ceiling is added to store the maximum height for the vehicle. Methods to get and set each variable are also added:

class LandVehicle extends Vehicle {

     int wheels;

     public void set_wheels(int new_wheels) {

          wheels = new_wheels;

     }

     public int get_wheels() {

          return wheels;

     }

}

class AirVehicle extends Vehicle {

     int ceiling;

     public void set_ceiling(int new_ceiling) {

          ceiling = new_ceiling;

     }

     public int get_ceiling() {

          return ceiling;

     }

}

Figure 9.2. LandVehicle and AirVehicle inherit from Vehicle.

Functionality

When LandVehicle and AirVehicle were created, the only reference to Vehicle is right after the extends keyword. However, by inheriting from (or extending) Vehicle with the two new classes, you keep all the functionality of the base class. To understand the implications of this fact, look at the following code, which is perfectly legal:

     LandVehicle myCar;

     myCar = new LandVehicle();

     myCar.set_weight(2000);

Notice that no reference is made in this code to the Vehicle class, yet a method from the Vehicle class is called. This code illustrates just how straightforward and seamless inheritance is. When inheritance is called an "is-a" relationship, that's exactly what it means. In nearly every way, an inherited class can act as if it were the base class in addition to using its new features.

Polymorphism

Often when designing classes that inherit from a base class, you encounter a situation where it would make sense to have the base class define a standard method to perform actions in subclasses. For example, if you were writing the Shape and Triangle classes mentioned earlier, you might want all shapes to have a method to draw themselves, but each shape will define that method differently.

To accomplish this task, you can define the name and return type of the method in the base class prefixed with the keyword abstract. Declaring a method abstract means that it will not be defined in this class, but that the method must be defined in any classes that inherit from this class. The class that defines the abstract method must also be declared abstract itself, so that no instances of it can be made. This rule makes sense because there would be a method with no code attached to it if you could make an instance of the abstract class.

To add a move() method to the Vehicle class, for example, you would use the following code:

abstract class Vehicle {

     abstract String move();

     // ... The rest of the class ...

}

Now every class that inherits from Vehicle must define the move() method, which must return a string. You can then define the return value to be a text description of the vehicle moving.

Next, add the move() method to the LandVehicle and AirVehicle classes:

class LandVehicle extends Vehicle {

     abstract String move() {

          return "Vrooom....";

     }

     // ... The rest of the class ...

}

class AirVehicle extends Vehicle {

     abstract String move() {

          return "Bzzzzzzz.....";

     }

     // ... The rest of the class ...

}

Declaring Vehicle to be abstract ensures that every class that inherits from this class has a move() method. This is very useful, but the true power of abstract classes comes from how they facilitate polymorphism.

Polymorphism is the capability to call a method from a class without knowing ahead of time exactly how that action will be performed. For example, no code is associated with the move() method in the Vehicle class, but you can still call that method when you have a reference to a vehicle object.

How can that be? Earlier it was stated that you cannot make an instance of an abstract class. This statement is true, but you can treat classes that inherit from that abstract class as if they were instances of that class. Remember that inherited classes retain the functionality of their parents.

This concept is pretty difficult to just imagine, so look at the example in Listing 9.2. The running applet is shown in Figure 9.3.

import java.awt.*;

import java.lang.*;

abstract class Vehicle {

     int weight;

     int speed;

     abstract String move();

     Vehicle() {

          weight = 0;

          speed = 0;

     }

     public void set_weight(int new_weight) {

          weight = new_weight;

     }

     public int get_weight() {

          return weight;

     }

     public void set_speed(int new_speed) {

          speed = new_speed;

     }

     public int get_speed() {

          return speed;

     }

}

class LandVehicle extends Vehicle {

     int wheels;

     String move() {

          return "Vrooom....";

     }

     public void set_wheels(int new_wheels) {

          wheels = new_wheels;

     }

     public int get_wheels() {

          return wheels;

     }

}

class AirVehicle extends Vehicle {

     int ceiling;

     String move() {

          return "Bzzzzzzz.....";

     }

     public void set_ceiling(int new_ceiling) {

          ceiling = new_ceiling;

     }

     public int get_ceiling() {

          return ceiling;

     }

}

public class PolyTestApplet extends java.applet.Applet {

     List output;

     LandVehicle myCar;

     AirVehicle myPlane;

     Vehicle aVehicle;

     public void init() {

          setLayout(new BorderLayout() );

          output = new List();

          add("Center", output);

          // Add Code Here

          myCar = new LandVehicle();

          myPlane = new AirVehicle();

          aVehicle = myCar;

          print(aVehicle.move());

          aVehicle = myPlane;

          print(aVehicle.move());

          // Add No Code After This Point

     }

     public void print(int line) {

          output.addItem(String.valueOf(line));

     }

     public void print(String line) {

          output.addItem(line);

     }

}

The following is from the above code? If so, I think it needs an introductory sentence or two explaining what it is. Also, there needs to be a text reference to Fig. 9.3. HS

Done. -Ken

Here is the HTML for the polymorphism example:

<html>

<applet code="PolyTestApplet.class" width=150 height=250>

</applet>

</html>

Figure 9.3. An applet with polymorphism.

The most important thing to notice in this example is that aVehicle is a reference to a vehicle object, not a LandVehicle or an AirVehicle object. The myCar and myPlane objects are assigned at different times to the aVehicle reference, and then aVehicle calls the move() method.

This is polymorphism in action and is a very powerful tool. Imagine you were writing a vehicle simulation program and wanted to have a loop that went through and moved all the vehicles. By using polymorphism, you could have a method go through and get references to all the vehicles in the simulation and call the move() methods of each. The important thing to remember is that because you would be getting references to each as a vehicle, not as the subclass that they were created under, you could add new vehicle types (perhaps SeaVehicle or SpaceVehicle) without changing a single line of the loop in the main program that moves the vehicles.

Summary

This chapter has moved quickly through the main topics in object-oriented programming, but if you've understood the general concepts presented here, you now can say quite truthfully that you understand object-oriented programming. In addition, the syntax and concepts that Java has for handling objects are quite similar to those of most other modern object-oriented languages like C, C++, and Delphi. Having a basic understanding of objects and object-oriented programming is essential to working with Java because it was designed from the ground up to function as an object-oriented programming language.

Don't worry if this chapter left you feeling like you only have a vague notion of objects. In terms of learning Java as a new programming language, it's a bit of a Catch-22. You need to understand objects to program Java, but you need to know Java before you can program objects in Java. This chapter tried to give you an understanding of objects, along with some real code examples to help you visualize some complex programming ideas.

The next chapter backtracks a bit to cover Java programming in more detail and to help you work your way into programming your own applets. As you read on, you will see why you have to have a basic understanding of objects when you start creating applets. Even if you are still fuzzy about objects, your knowledge of them so far will help with learning Java as a whole.

Previous Page TOC Next Page