Chapter 14

Classes


CONTENTS

Way back in Chapter 4 you got a general introduction to object-oriented programming concepts. In that chapter, you took a first look at classes and how they're used to organize source code into logically defined modules. Since then, you've been using various classes included as part of the Java language, but you haven't explored the implications of using a class or of creating your own classes. In this chapter, you plug up that hole in your understanding of Java and how it uses classes to create applets.

Classes and Objects

In Chapter 4 you learned that a class is the template for an object and that a class is a way to encapsulate both data (called fields in Java) and the functions (called methods) that operate on that data. You also learned about inheritance, which enables a class (called the subclass) to inherit the capabilities of a base class (called a superclass in Java). Finally, you discovered that polymorphism enables you to create virtual methods that can be implemented differently in derived classes. In this section, you'll apply what you know about object-oriented programming towards creating Java classes.

Defining a Simple Class

As I said, a class is sort of a template for an object. In this way, a class is equivalent to a data type such as int. The main difference is that Java already knows what an integer is. However, when you create a class, you must tell Java about the class's characteristics. You define a class by using the class keyword along with the class name, like this:


class MyClass

{

}

Believe it or not, the preceding lines are a complete Java class. If you save the lines in a file called MyClass.java, you could even compile the class into a .CLASS file, although the file won't actually do anything if you tried to run it. As you can see, the class definition begins with the keyword class followed by the name of the class. The body of the class is marked off by curly braces just like any other program block. In this case, the class's body is empty.

Because its body is empty, this example class doesn't do anything. You can, however, compile the class and even create an object from it. To create an object from a class, you type the class's name followed by the name of the object. For example, the line below creates an object from the MyClass class:


MyClass myObject = new MyClass();

Declaring Fields for a Class

As I said, the MyClass example class doesn't do much yet. In order to be useful, it needs both data fields and methods. You declare fields for your class in much the same way you declare any variable in a program, by typing the data type of the field followed by the name of the field, like this:


int myField;

The above line declares a data field of type integer. However, looking at the above line doesn't tell you much about how data fields are used with classes. In fact, you can't tell from the above line whether myField is actually part of an object or just a normal variable. To clear up this ambiguity, you can plug the above line into the MyClass class definition, as shown in Listing 14.1.


Listing 14.1  LST14_1.TXT: Adding a Data Field to a Class.

class MyClass

{

    int myField;

}


Now you can see that myField is a data field of the MyClass class. Moreover, this data field is by default accessible only by methods in the same package. (For now, you can think of a package as a file.) You can change the rules of this access by using the public, protected, and private keywords. A public data field can be accessed by any part of a program, inside or outside of the class in which it's defined. A protected data field can only be accessed from within the class or from within a derived class (a subclass). A private data field cannot even be accessed by a derived class.

Defining a Constructor

You have now added a data field to MyClass. However, the class has no methods and so can do nothing with its data field. The next step in defining the class, then, is to create methods. One special type of method, called a constructor, enables an object to initialize itself when it's created. A constructor is a public method (a method that can be accessed anywhere in a program) with the same name as the class. Listing 14.2 shows the MyClass class with its constructor in place.


Listing 14.2  LST14_2.TXT: Adding a Constructor to a Class.

class MyClass

{

    int myField;



    public MyClass(int value)

    {

        myField = value;

    }

}


As you can see, the class's constructor starts with the public keyword. This is important because you want to be able to create an object from the class anywhere in your program, and when you create an object, you're actually calling its constructor. After the public keyword comes the name of the constructor followed by the constructor's arguments in parentheses. When you create an object of the class, you must also provide the required arguments.

Example: Creating an Object by Calling a Constructor

If you want to create an object from MyClass, you must supply an integer value that the class uses to initialize the myField data field. This integer is the MyClass constructor's single argument. You'd create an object of the class like this:


MyClass myObject = new MyClass(1);

This line not only creates an object of the MyClass class, but also initializes the myField data field to 1. The first word in the line tells Java that myObject is going to be an object of the MyClass class. The next word is the object's name. After the equals sign comes the keyword new and the call to the class's constructor.

Defining Methods

Other methods that you add to a class are just like the methods you've been writing in previous chapters. You just need to be sure to provide the proper type of access to your methods. That is, methods that must be called from outside the class, should be defined as public, methods that must be callable only from the class and its derived classes should be defined as protected, and methods that must be callable only from within the class should be declared as private.

Suppose myField is defined as private, and you now want to be able to set the value of myField from outside the MyClass class. Because that data field is defined as private, meaning it can be accessed only from within the same class, you cannot access it directly by name. To solve this problem, you can create a public method that can set the value for you. You might also want to create a method that returns the value of the field, as well, as shown in Listing 14.3.


Listing 14.3  LST14_3.TXT: Adding a Method to the Class.

class MyClass

{

    private int myField;



    public MyClass(int value)

    {

        myField = value;

    }



    public void SetField(int value)

    {

        myField = value;

    }



    public int GetField()

    {

        return myField;

    }

}


Start defining the MyClass class.
Declare the class's myField data field.
Define the class's constructor.
Initialize the data field.
Start defining the SetField() method.
Set the data field to the value passed to SetField().
Start Defining the GetField() method.
Return the value of the myField data field.

NOTE
According to the rules of strict object-oriented design, all class data fields should be declared as private. Some programmers would go so far as to say that you should not even provide access to data fields through public methods. However, you'll see these rules broken a lot, even by programmers hired by big companies like Microsoft, Borland, and Sun. As you become more familiar with object-oriented programming, you'll better understand why the rules were made and when it's appropriate to break them.

Example: Using Classes in Applets

Up till now, you've been writing applets using the classes already supplied as part of Java. Now, you'll see how to use your own classes in applets. This will help you understand not only how your own classes work, but also help you to understand why you used Java's classes as you did. Follow the steps below to see how all this class stuff works.

  1. Type Listing 14.3 and save it to your CLASSES folder under the name MyClass.java. (If you don't want to type, you can find the listing on this book's CD-ROM, in the CHAP14 folder.)
  2. Start a DOS session by selecting Programs/MS-DOS Prompt from the Start menu. The DOS window appears, as shown in Figure 14.1.
    Figure 14.1 : This is the DOS prompt window.

  3. Type CD C:\CLASSES to switch to your CLASSES folder.
  4. Type javac MyClass.java to compile the MyClass class. You'll then find the MyClass.class file in your CLASSES folder.
  5. Type Listing 14.4 and save it as Applet19.java in your CLASSES folder.
    Listing 14.4  Applet19.java: An Applet That Uses the MyClass Class.
    
    import java.awt.*;
    
    import java.applet.*;
    
    import MyClass;
    
    
    
    public class Applet19 extends Applet
    
    {
    
        MyClass myObject;
    
        TextField textField1;
    
    
    
        public void init()
    
        {
    
            myObject = new MyClass(1);
    
            textField1 = new TextField(10);
    
            add(textField1);
    
            textField1.setText("1");
    
        }
    
    
    
        public void paint(Graphics g)
    
        {
    
            String s = textField1.getText();
    
            int value = Integer.parseInt(s);
    
            myObject.SetField(value);
    
            value = myObject.GetField();
    
            s = String.valueOf(value);
    
            g.drawString("The data field of the object", 30, 80);
    
            g.drawString("is now set to this value:", 40, 95);
    
            g.drawString(s, 90, 125);
    
        }
    
    
    
        public boolean action(Event event, Object arg)
    
        {
    
            repaint();
    
            return true;
    
        }
    
    }
    
    

    Tell Java that the program uses the awt package.
    Tell Java that the program uses the applet package.
    Tell Java that the program uses the MyClass class.
    Derive the Applet19 class from the Applet class.
    Declare an object of the MyClass class.
    Declare a TextField object.
    Override the Applet class's init() method.
    Create an object of the MyClass class.
    Create a TextField object.
    Add the TextField object to the applet.
    Set the TextField object's text.
    Override the Applet class's paint() method.
    Get the text from the TextField object.
    Convert the text to an integer.
    Set myObject's myField data field.
    Get the value of myField from myObject.
    Convert the value to a string.
    Draw the applet's display area.
    Override the Applet class's action() method.
    Repaint the applet's display area.
    Tell Java the method executed okay.
  6. Type javac Applet19.java to compile the Applet19 applet. You'll then have the Applet19.class file in your CLASSES folder.
  7. Type Listing 14.5 and save the file as APPLET19.htmL.

Listing 14.5  APPLET19.htmL: The HTML Document for Applet19.

<title>Applet Test Page</title>

<h1>Applet Test Page</h1>

<applet

    code="Applet19.class"

    width=200

    height=200

    name="Applet19">

</applet>


You're now ready to run the Applet19 applet, which uses the MyClass class. To run the program, type APPLETVIEWER APPLET19.htmL. When you do, you see the window shown in Figure 14.2.

Figure 14.2 : This is Applet19 running under Appletviewer.

The applet's display area shows the current setting of MyClass's data field, myField. You can change this setting by typing a new value into the text box and pressing Enter.

Understanding the Applet

By now, you should have a good idea of how classes work, at least generally. Still, you'll now examine parts of Applet19's source code. First, near the top of the source code is this line:


import MyClass;

Because the MyClass class is located in a different file than Applet19, you need to tell Java where to find it. The above line tells Java that it can find everything it needs to know about MyClass in the MyClass.class file, which you created when you compiled MyClass.java.

The next line of interest is this one, which is located at the top of Applet19's definition:


MyClass myObject;

This line tells Java that you'll be creating an object of the MyClass class and that the object will be called myObject.

At this point, you don't have the object created yet. You have to create the object, which Applet19 does in its init() method, using the new operator, like this:


myObject = new MyClass(1);

After the above line executes, Java has created the object, which means you can now call the object's public methods to manipulate the object as appropriate. Objects of the MyClass class have only two public methods (not counting the constructor). Applet19 calls these methods in its paint() method, like this:


myObject.SetField(value);

value = myObject.GetField();

In the first line, Applet19 calls the object's SetField() method, whose single argument is the value to which to set the myField data field. Due to its private access, this is the only way to set the value of myField outside of the class. If you tried to access myField with the line


myObject.myField = value;

you wouldn't even be able to compile the file. The compiler will generate an error telling you that you cannot access myField in this way (Figure 14.3).

Figure 14.3 : The compiler complains when you ignore rules of access.

Using Inheritance

You may not know it, but throughout the second part of this book, you've been using inheritance to create your applets. Specifically, you've been deriving your applet classes (i.e, Applet10, Applet11, and so on) from Java's Applet superclass. By using inheritance in this way, you can take an existing class and create a new similar class that does things a little differently. The new class will have all the characteristics of its superclass, but will also have any new characteristics that you choose to add.

Creating a Subclass

You derive a new class from a superclass by using the extends keyword, an apt name for a keyword because by deriving a new class you usually extend the abilities of the original class. For example, when you create a new applet, you start the applet's class with a line that looks something like this:


public class MyApplet extends Applet

First, Java insists that all applet classes be declared as public. Next in the line, you can see the class keyword followed by the name of the class. Finally comes the extends keyword followed by the name of the superclass. In English, the above line means that the public class MyApplet is derived from (is a subclass of) the existing Applet class. As you've probably already figured out, Applet is a class that the Java makers created for you. This class contains all the basic functionality you need to create an applet. You need only extend (there's that word again) the specifics of the class in order to create your own applet class. Again, you've been doing that in every applet you've written so far.

Adding Fields and Methods to the Subclass

One thing you can do when you create a subclass is to add your own data fields and methods. For example, when you derive your own applet class from Java's Applet class, although your class inherits tons of data fields and methods from the superclass, you'll undoubtedly need fields and methods not supplied in the superclass. Maybe your new applet is designed to play Tic-Tac-Toe. (Hmmmm. Where have I seen that before?) Obviously, when the fine programmers at Sun created the Applet class, they didn't think to add the methods needed to play Tic-Tac-Toe. You'll have to add those methods yourself.

Example: Adding Fields and Methods

Take the MyClass class that you created earlier in this chapter (shown in Listing 14.3). Suppose you want to create a new class that has a new data field called myNewField, as well as a constructor and methods for setting and retrieving the value of this new data field. You might come up with something like Listing 14.6.


Listing 14.6  MYSUBCLASS.JAVA: Creating a Subclass.

import MyClass;



class MySubClass extends MyClass

{

    private int myNewField;



    public MySubClass(int value)

    {

        super(value);

        myNewField = value;

    }



    public void SetNewField(int value)

    {

        myNewField = value;

    }



    public int GetNewField()

    {

        return myNewField;

    }

}


The file containing the MySubClass class first imports the MyClass file, because Java will need the information contained in that file. In the constructor, the class first calls


super(value);

which ensures that the superclass (MyClass) is properly initialized by calling its constructor. The keyword super refers to the class's superclass. After calling the superclass's constructor, the MySubClass constructor initializes the new data field, myNewField. The new class also supplies new methods for setting and getting the value of myNewField. In short, MySubClass now has two data fields-myField, which it inherited from MyClass, and the new myNewField-and four methods-SetField() and GetField, which it inherited from MyClass, and the new SetNewField() and GetNewField() methods.

Example: Using a Subclass in a Program

Now that you have the MySubClass subclass, it might be nice to see how it works in a real programming situation. Applet20, which is shown in Listing 14.7, does the honors of putting MySubClass to work. In most places, compared to Applet19, the applet merely replaces occurrences of MyClass with MySubClass. The paint() method has to work a bit harder, though, calling all four of MySubClass's methods to prove they work.


Listing 14.7  APPLET20.JAVA: Using a Subclass in a Program.

import java.awt.*;

import java.applet.*;

import MySubClass;



public class Applet20 extends Applet

{

    MySubClass mySubObject;

    TextField textField1;

    TextField textField2;



    public void init()

    {

        mySubObject = new MySubClass(1);

        textField1 = new TextField(10);

        add(textField1);

        textField1.setText("1");

        textField2 = new TextField(10);

        add(textField2);

        textField2.setText("2");

    }



    public void paint(Graphics g)

    {

        String s = textField1.getText();

        int value = Integer.parseInt(s);

        mySubObject.SetField(value);

        value = mySubObject.GetField();

        s = String.valueOf(value);

        g.drawString("The myField data field", 30, 80);

        g.drawString("is now set to this value:", 40, 95);

        g.drawString(s, 90, 125);



        s = textField2.getText();

        value = Integer.parseInt(s);

        mySubObject.SetNewField(value);

        value = mySubObject.GetNewField();

        s = String.valueOf(value);

        g.drawString("The myNewField data field", 30, 155);

        g.drawString("is now set to this value:", 40, 170);

        g.drawString(s, 90, 200);

    }



    public boolean action(Event event, Object arg)

    {

        repaint();

        return true;

    }

}


When you run Applet20 under Appletviewer, you see the window shown in Figure 14.4. Use the first text box to enter values for the original myField data field. Use the second text box to enter values for myNewField. Whenever you press Enter, the applet reads the values from the boxes and calls MySubClass's methods to set the new values and to retrieve the set values from the object.

Figure 14.4 : This is Appletviewer running the Applet20 applet.

Overriding Methods of the Superclass

If you've been reading the pseudocode sections that follow many of the listings in this book, you've seen the term "overriding" many times. When you override a method, you are creating a new version of a method that's part of the superclass. For example, in many of the applets you've created, you've overridden methods like init(), paint(), and action(). All of these methods are defined in some general way in the Applet superclass. When you derive a new class from applet, you can override these methods to perform the tasks you want them to perform, rather than the general tasks assigned to them by the Applet class.

NOTE
In general object-oriented programming discussions, the term "derive" means exactly the same thing as "subclass" (when the latter is used as a verb). Ditto for the terms "base class" and "superclass," which are the same thing. In other words, when you derive a new class from a base class, you are subclassing a new class from a superclass.

For example, you know that, when Java starts up an applet, it calls the applet's init() method. Here's how the Applet class defines init():


public void init()

{

}

No, your eyes aren't fooling you. In the Applet class, the init() method does nothing at all. It's only there so you can override it in your own class. Here's how it all works: When you derive your applet class from Applet, your applet class inherits all of Applet's data fields and methods. If you don't override a method, Java calls the original version as necessary. In other words, if you don't override init() in your applet class, when Java starts your applet, it calls the Applet class's version of init(), which does nothing. However, if you override init() in your class, Java is smart enough to call the new version rather than the original do-nothing version. Cool, eh?

The this Keyword

There may be times when you need to explicitly refer to an object from within the object's methods. For example, you might need to pass a reference to the object as an argument in a method call. When you need to refer to the object explicitly, use the this keyword. In many cases, the this keyword is implicit in the method call or variable reference. For example, inside an object that has the data field dataField, the line


dataField = 1;

is the same as


this.dataField = 1;

In the first case, the this keyword is implicit, whereas in the second case, you've included it explicitly. If you needed to pass a reference to the object as an argument, you might write something like this:


SomeMethod(this);

Of course, the SomeMethod() method would have been written to accept an object of this's type as its single argument.

Summary

If you've never done any object-oriented programming, it might take you a while to get used to using classes. Classes are the single biggest hurdle to jump when making the transition from normal procedural programming to object-oriented programming (OOP). Just think of classes as a way to provide another level of abstraction to your programs. In your non-OOP programs, you had program elements called programs, files, and procedures, listed in the order of their level of abstraction. Now, you can add classes to the end of the list, right between files and procedures.

Review Questions

  1. What is a class?
  2. How do classes help you to organize your programs?
  3. What are the three parts of a simple, empty class?
  4. What two elements do you add to complete the class?
  5. How do you create an object from a class?
  6. How do you use a class that's defined in a different file than the file that accesses the class?
  7. What is inheritance and how does it help you create new classes quickly?
  8. What is a subclass and a superclass?
  9. How do you create a subclass?
  10. How do you override a method inherited from a superclass?

Review Exercises

  1. Write a basic, empty class called TestClass.
  2. Add to TestClass a string data field called data1. This data field should be private to the class.
  3. Add to TestClass a constructor that accepts a starting value for data1 as its single argument, and public methods for setting and retrieving the value of data1. Call these methods SetData() and GetData().
  4. Compile the finished class.
  5. Write a subclass called TestSubClass that is derived from TestClass and that adds an integer data field called data2 (declared as private) and a public method called CreateDataString() that creates a string object from data1 and data2. That is, if data1 is equal to Java is cool! and data2 is equal to 15, the CreateDataString() method should return Java is cool! 15 as a single string object. Also, create public methods called SetData2() and GetData2() for setting and retrieving the value of data2, as well as a constructor that accepts arguments for the starting values of data1 and data2.
  6. Modify Applet20 so that it creates an object of the TestSubClass class. You should provide text boxes for enabling the user to set data1 and data2, as well as write paint() so that it displays the string returned by CreateDataString(). Figure 14.5 shows what the ClassApplet applet should look like. (You can find the solutions for these exercises in the CHAP14 folder of this book's CD-ROM.)
    Figure 14.5 : This is ClassApplet running under Appletviewer.