by Laura Lemay and Rogers Cadenhead
Object-oriented programming (OOP) is one of the biggest programming ideas in recent years-and it's also one of the biggest sources of consternation for programmers unfamiliar with how it works. You may fear that years must be spent learning about OOP and how it makes life easier than other ways to program. The central idea of object-oriented programming is simple: Organize programs in ways that echo how things are put together in the real world.
This chapter provides an overview of object-oriented programming concepts in Java and how they relate to the structure of your programs. The following topics are covered:
If you already are familiar with object-oriented programming, much of this material will be a review for you. Even if you skim over the introductory sections, you may want to create the Java examples in this chapter to get more experience using the language.
Consider, if you will, LEGO building bricks. LEGO bricks, for those of you who do not spend much time with children, are small plastic building blocks in various colors and sizes. They have small round studs on one side that fit snugly into round holes on other bricks to create larger shapes. With different LEGO pieces (wheels, engines, hinges, pulleys, and the like), you can make castles, automobiles, giant robots, or just about anything else you can imagine. Each LEGO piece is a small object that fits together with other small objects in specific ways to create other, larger objects.
Consider another example. You can walk into a computer store and, with a little expertise and some help, assemble an entire personal computer system from various components: a motherboard, a CPU chip, a video card, a hard disk, a keyboard, and so on. Ideally, when you finish assembling the various self-contained units, you have a system in which all the units work together to create a larger system. You can use this larger system to solve the problems you bought the computer for in the first place.
Internally, each of those computer components might be extremely complicated and engineered by different companies using different methods of design. But you don't need to know how each component works, what every chip on the board does, or how an A gets sent to your computer when you press the A key. Each component you use is a self-contained unit, and as the assembler of the overall system, you are interested only in how the units interact with each other. Will this video card fit into a slot on the motherboard? Will this monitor work with this video card? Will each component speak the right commands to the other components it interacts with, so that each part of the computer is understood by every other part? Once you know about the interactions between the components and can match those interactions, putting together the overall system is easy.
What do these examples have to do with programming? Everything. Object-oriented programming is a lot like building structures from LEGO bricks or assembling a PC. When you use object-oriented programming, your overall program is made up of lots of different self-contained components called objects. Each object has a specific role in the program, and all the objects can talk to each other in defined ways.
Object-oriented programming is modeled on the observation that, in the real world, objects are made up of many kinds of smaller objects. However, the capability to combine objects is only one general aspect of object-oriented programming. Object-oriented programming provides several other concepts and features to make the creation and use of objects easier and more flexible. The most important of these features is the class.
A class is a template for multiple objects with similar features. Classes embody all the features of a particular set of objects. When you write a program in an object-oriented language, you don't define individual objects. You define classes of objects.
For example, you might have a Tree class that describes the features of all trees (each tree has branches and roots, grows, and creates chlorophyll). The Tree class serves as an abstract model for the concept of a tree. To reach out and grab, or interact with, or cut down a tree, you must have a concrete instance of that tree. Of course, once you have a Tree class, you can create lots of different instances of that tree, and each different tree instance can have different features (it can be short, tall, bushy, drop leaves in autumn, and so on), yet still behave like a tree and be immediately recognizable as one (see Figure 2.1).
Figure 2.1: The Tree Class and Tree instances.
An instance of a class is an actual object of that class. The class is the general, abstract representation of an object, and an instance is its concrete representation. So what, precisely, is the difference between an instance and an object? Nothing, really. The term object is used more generally, but both instances and objects are the concrete representations of a class. In fact, the terms instance and object often are used interchangeably in OOP terminology. A Tree instance and a Tree object are the same thing.
In an example closer to the kind of thing you may want to do with Java, you can create a class for an on-off switch (an item you intend to use on dialog boxes and other windows). The LightSwitch class defines the following features of an on-off switch:
The class also defines how an on-off switch behaves, as follows:
Once you define the LightSwitch
class, you easily can create instances of that switch-in other
words, LightSwitch objects.
The instances all take on the basic features of a switch as defined
by the class, but each instance can have different appearances
and behavior based on what you want that particular switch to
do. By creating a LightSwitch
class, you don't have to keep rewriting the code for each switch
you want to use in your program. Also, you can reuse the LightSwitch
class to create different kinds of switches as you need them-in
this program and in other programs.
Tip |
If you're used to programming in C, you can think of a class as a way to create a new composite data type that is analogous to using struct and typedef statements in C. Classes, however, can provide much more functionality than just a collection of data, as you'll discover in the rest of this chapter. |
When you write a Java program, you design and construct a set of classes. When your program runs, instances of those classes are created and discarded as needed. Your task, as a Java programmer, is to create the right set of classes to accomplish what your program needs to accomplish.
Fortunately, you don't have to start from scratch. The Java environment comes with a library of classes that implement a lot of the basic behaviors you need. A class library is a set of classes. The Java library has classes to handle basic programming tasks (math functions, arrays, strings, and so on) as well as classes to handle graphics and networking behavior. In many cases, the Java class libraries may be sufficient for your needs; all you have to do in your Java program is to create a single class that uses the standard class libraries. For complicated Java programs, however, you may have to create a whole set of classes with defined interactions between them.
Generally, every class you write in Java is made up of two components: attributes and behavior. In the following sections, you learn about each component as it applies to a theoretical class called Jabberwock. To wrap up this discussion, you'll create the Java code to implement a representation of a jabberwock-a dragon-like monster from the Lewis Carroll poem Jabberwocky.
Attributes are the individual things that differentiate one object from another and determine the appearance, state, or other qualities of that object. Consider how a theoretical class called Jabberwock could be created. The attributes of a jabberwock might include the following:
Attributes of an object also can include other information about its state. For example, you can have features for the jabberwock's attitude (enraged or calm) or its current health (alive or dead).
Attributes are defined by variables; in fact, you can consider attributes to be analogous to global variables for the entire object. Because each instance of a class can have different values for its variables, each variable is called an instance variable. Instance variables define the attributes of an object. The class defines the type of the attribute, and each instance stores its own value for that attribute.
Each attribute, as the term is used here, has a single corresponding instance variable; changing the value of a variable changes the attribute of that object. Instance variables can be set when an object is created and stay constant throughout the life of the object, or they can change at will as the program runs.
Class variables apply to the class itself and to all of its instances. Instance variable values are stored in the instance; class variable values are stored in the class itself.
Behavior is the only way objects can do anything to themselves or have anything done to them. The behavior of a class determines what instances of that class do to change their internal state. Behavior also determines what class instances do when asked to do something by another class or object. For example, the Jabberwock class might have some of the following behaviors:
To define an object's behavior, you create methods. Methods are just like functions in other languages, but they are defined inside classes. Methods operate on instances of their class. Unlike C++, Java does not have functions of any kind defined outside of classes.
Although methods operate within their own class, methods do not affect only a single object. Objects communicate with each other using methods. A class or object can call methods in another class or object to communicate changes in the environment or to ask that an object change its state.
For example, consider the swordsman in the poem Jabberwocky. When he attacked the jabberwock with his vorpal blade, here's what happened:
One, two! One, two! And through and through
The vorpal blade went snicker-snack!
He left it dead, and with its head
He went galumphing back.
In Java, the swordsman could be created as a Knight object. When the swordsman chops the head off the jabberwock, it definitely causes a change in the jabberwock's internal state. The Knight object would use a method to tell the Jabberwock object, "I chopped your head off. You're dead."
Just as there are instance and class variables, there are also instance and class methods. Instance methods (which are so common they're usually just called methods) apply and operate on an instance of a class. Class methods apply and operate on a class itself.
Up to now, this chapter has been pretty theoretical. In this section,
however, you create a working example of the Jabberwock
class so that you can see how instance variables and methods are
defined in a class. You also create a Java applet that creates
a new instance of the Jabberwock
class, displays its instance variables, and modifies one of its
instance variables.
Note |
The syntax of this example is not covered in great detail in this chapter. Don't worry too much if you're not completely sure what's going on. All you need to focus on in this example are the basic parts of the Jabberwock class definition. |
We'll name the applet you are creating JabberwockApplet to distinguish the applet from the Jabberwock class that it uses. With your Java development software, create a source file called JabberwockApplet.java. If you're using the Java Developers Kit, you can create this file with any text editor that can work with plain text files. If a project name is required, call it JabberwockApplet.
You start by creating a basic class definition. Enter the following into your source code editor:
class Jabberwock { }
Congratulations! You have designed a class. Of course, it doesn't do much at the moment, but that's a Java class at its simplest.
To make Jabberwock more sophisticated, create three instance variables for this class. Just below the class Jabberwock { line, add the following three lines:
String color; String sex; boolean hungry;
These lines create three instance variables. Two, color
and sex, can contain String
objects. (String is part
of that standard class library mentioned earlier.) The third,
hungry, is a boolean
that refers to whether the jabberwock is hungry (true)
or full (false).
Note |
In Java, boolean is a real data type that can have the values true or false. Booleans are not numbers, as they are in C. |
You can add some behavior to the class by adding methods. There are all kinds of things a jabberwock can do (claws that catch, jaws that bite, and so on), but to keep things short, just add one method-a method to feed the monster. Add the following lines below the three instance variables in your class definition:
void feedJabberwock(Graphics g, int y) { if (hungry == true) { g.drawString("Yum -- a peasant!", 25, y); hungry = false; } else g.drawString("No, thanks -- already ate.", 25, y); } // more to come
Tip |
The last line, // more to come, is a comment line. Comments are used for the benefit of programmers looking at source code to figure out what it's doing. Everything from the initial // to the end of the line will be ignored by the compiler. In this case, the comment is being used as a placeholder. You'll replace it soon. |
The feedJabberwock() method tests to see whether the jabberwock is hungry (in the line if (hungry == true) {). If it is hungry, the jabberwock is fed (much to its delight), and the state of hungry is changed to false. If the jabberwock is not hungry, a message is displayed that the monster already ate. Here's what your program should look like so far:
class Jabberwock { String color; String sex; boolean hungry; void feedJabberwock(Graphics g, int y) { if (hungry == true) { g.drawString("Yum -- a peasant!", 25, y); hungry = false; } else g.drawString("No, thanks -- already ate.", 25, y); } // more to come }
Tip |
The indentation of each part of the class and the insertion of blank lines aren't required for the program to work correctly-the compiler ignores these blanks. Using some form of indentation, however, makes your class definition easier to read. This readability pays dividends when you or another programmer tries later on to figure out what the code is doing. The indentation used here, with instance variables and methods indented from the class definition, is a commonly used style for Java programs. The Java class libraries use a similar indentation. You can choose any indentation style that you like. |
Before you compile this class, you should add one more method. The showAtts() method displays the current values of the instance variables in an instance of your Jabberwock class. In the program, delete the comment line // more to come and replace it with the following:
void showAtts(Graphics g, int y) { g.drawString("This is a " + sex + " " + color + " jabberwock.", 25, y); if (hungry == true) g.drawString("The jabberwock is hungry.", 25, y+20); else g.drawString("The jabberwock is full.", 25, y+20); }
The showAtts() method displays two lines to the screen: the sex and color of the Jabberwock object, and whether the monster is hungry. Save your source code file after adding the showAtts() method.
At this point, you have a Jabberwock class and methods that can be used to modify or display its instance variables. To do something with the class (for example, to create instances of that class and play with them), you must create the code for a Java applet that uses the Jabberwock class.
Listing 2.1 shows the full source code for JabberwockApplet.java.
Return to your text editor and enter lines 1 through 20 above
the source code you already have entered. When you're done, save
the file.
Caution |
It is important to note that Java is case sensitive. In this example, if you enter g.drawstring as a method name instead of g.drawString, it will result as a compiler error because drawstring will not be found in the java.awt.Graphics class. |
Listing 2.1. JabberwockApplet.java.
1: import java.awt.Graphics; 2: 3: public class JabberwockApplet extends java.applet.Applet { 4: 5: public void paint(Graphics g) { 6: Jabberwock j = new Jabberwock(); 7: j.color = "orange"; 8: j.sex = "male"; 9: j.hungry = true; 10: g.drawString("Calling showAtts ...", 5, 50); 11: j.showAtts(g, 70); 12: g.drawString("Feeding the jabberwock ...", 5, 110); 13: j.feedJabberwock(g, 130); 14: g.drawString("Calling showAtts ...", 5, 150); 15: j.showAtts(g, 170); 16: g.drawString("Feeding the jabberwock ...", 5, 210); 17: j.feedJabberwock(g, 230); 18: } 19: } 20: 21: class Jabberwock { 22: String color; 23: String sex; 24: boolean hungry; 25: 26: void feedJabberwock(Graphics g, int y) { 27: if (hungry == true) { 28: g.drawString("Yum - a peasant!", 25, y); 29: hungry = false; 30: } else 31: g.drawString("No, thanks - already ate.", 25, y); 32: } 33: 34: void showAtts(Graphics g, int y) { 35: g.drawString("This is a " + sex + " " + color 36: + " jabberwock.", 25, y); 37: if (hungry == true) 38: g.drawString("The jabberwock is hungry.", 25, y+20); 39: else 40: g.drawString("The jabberwock is full.", 25, y+20); 41: } 42: }
Before you can test the applet, you must compile it. If you're using the Java Developers Kit (JDK), the command to compile the file JabberwockApplet.java is the following:
javac JabberwockApplet.java
javac is the compiler included with the JDK. It takes one or more .java source code files as input and creates class files of compiled Java bytecode, which have the file extension .class. When JabberwockApplet.java is compiled, two .class files are created: JabberwockApplet.class and Jabberwock.class.
If the source code has been entered correctly, it should compile without any errors.
Although most of the code in the Jabberwock class definition has been described, the contents of the JabberwockApplet class in Listing 2.1 are largely new to you. This section more fully explains the lines that involve the Jabberwock class to give you an idea of how classes are used.
Line 6, Jabberwock j = new Jabberwock(), creates a new instance of the Jabberwock class and stores a reference to it in the variable j. Remember that you usually do not operate directly on classes in your Java programs. Instead, you create objects from those classes and call methods in those objects. Lines 7, 8, and 9 set the instance variables for the Jabberwock object j. The color is set to orange, the sex is set to male, and the hungry boolean instance variable is set to true.
Line 11 calls the showAtts() method, defined in your Jabberwock object, with the parameters (g, 70). (The parameters used here and elsewhere in the program determine where text will be displayed in the applet. Disregard them for now.) The showAtts() method displays the values of the instance variables sex and color for the Jabberwock object j. It also displays the value of the instance variable hungry.
Line 13 calls the feedJabberwock() method in Jabberwock to feed object j. Jabberwock object j is hungry when the applet starts because hungry is initially set to true, so the object eats the food. As you saw in the feedJabberwock() method described previously, the instance variable hungry is set to false after the Jabberwock object eats.
Line 15 calls the showAtts() method again, displaying the values of the instance variables for a second time. A change in state for hungry is shown. Line 17 tries to feed the jabberwock again to see what happens. Because Jabberwock object j is no longer hungry, the object refuses to eat the food.
Now that you have become familiar with what the program is doing, you should be ready to run JabberwockApplet. If you're using the Java Developers Kit or some other tool that does not have the facility to immediately test applets, you must create a simple Web page that can load the applet. Enter the text from Listing 2.2 into a file called JabberwockApplet.html. Using the Java Developers Kit, you can see the output of this applet by using the following command:
appletviewer JabberwockApplet.html
Listing 2.2. The HTML code of JabberwockApplet.html.
1: <html> 2: <body> 3: <applet code=JabberwockApplet.class height=250 width=300> 4: </applet> 5: </body> 6: </html> The output should look like the following: Calling showAtts ... This is a male orange jabberwock. The jabberwock is hungry. Feeding the jabberwock ... Yum -- a peasant! Calling showAtts ... This is a male orange jabberwock. The jabberwock is full. Feeding the jabberwock ... No, thanks -- already ate.
With a basic grasp of classes, objects, methods, and variables, you have put them together successfully in a Java program. But this is only part of the story of object-oriented programming. It's time to learn about the features that make this style of programming so powerful.
Inheritance, interfaces, and packages are all mechanisms for organizing classes and class behaviors. The Java class libraries use all these concepts-and so will the best class libraries you write for your own programs.
Inheritance is one of the most crucial concepts in object-oriented programming, and it has a direct effect on how you design and write Java classes. Inheritance is a powerful mechanism that allows a class to inherit functionality from an existing class. To create the new class, you only have to specify how that class is different from an existing class, and inheritance gives you automatic access to the existing class.
With inheritance, all classes-those you write, those from other class libraries that you use, and those from the standard utility classes as well-are arranged in a strict hierarchy such as the one shown in Figure 2.2.
Figure 2.2: A class hierarchy.
Each class has a superclass (the class above it in the hierarchy)-except for the topmost class in the hierarchy. Each class can have one or more subclasses (classes below it in the hierarchy). Classes in the hierarchy inherit from classes above them in the hierarchy.
Subclasses inherit all the methods and variables from their superclasses. In practical terms, this means that if the superclass defines behavior your class needs, you don't have to redefine that behavior or copy that code from some other class. Your class automatically receives that behavior from its superclass, the superclass gets behavior from its superclass, and so on, all the way up the hierarchy. Your class becomes a combination of all the features of the classes above it in the hierarchy, as well as its own features.
At the top of the Java class hierarchy is the Object class-all classes inherit from this one superclass. Object is the most general class in the hierarchy; it defines behavior inherited by all the classes in the Java class hierarchy. Each class further down the hierarchy adds more information and becomes more tailored to a specific purpose. A class hierarchy defines abstract concepts at the top of the hierarchy, and those concepts become more concrete the further you go down the chain of subclasses.
Most of the time when you create a new class in Java, you will want your class to have all the functionality of an existing class with some new additions or modifications of your own creation. For example, you may want a version of a LightSwitch class with images for the switch. To receive all the LightSwitch functionality, all you have to do is define your class as a subclass of LightSwitch. Your class automatically has all the behavior defined in LightSwitch, and all the behavior defined in the superclasses of LightSwitch. All you have to worry about are the things that make your new class different from LightSwitch itself. The mechanism of defining new classes as the differences between them and their superclasses is called subclassing.
Subclassing is the creation of a new class that inherits from an existing class in the class hierarchy. Using subclassing, you only have to define the differences between your class and its parent (superclass). The basic behavior is available to your class through inheritance.
What if your class defines entirely new behavior, and it isn't really a subclass of another class? Your class also can inherit directly from Object, which still allows it to fit neatly into the Java class hierarchy. In fact, if you create a class definition that doesn't indicate its superclass in the first line, Java assumes that the new class is inheriting directly from Object. The Jabberwock class you created in the previous section inherited from the Object class.
If you're creating a larger set of classes, it makes sense for your classes not only to inherit from the existing class hierarchy, but also to make up a hierarchy themselves. Creating this hierarchy can take some planning beforehand when you're trying to figure out how to organize your Java code. However, the advantages are significant:
Imagine that you have created a Java class to implement all the features of a Jabberwock. It's done, it works, and everything is fine. Your next task is to create a Java class called Dragon.
Dragon and Jabberwock have many similar features-both are large monsters that eat peasants. Both have sharp claws, powerful teeth, and fiery breath. Your first impulse may be to open up your Jabberwock class file and copy a lot of the functionality from it into the new Dragon class.
A far better plan is to factor out the common information for Dragon and Jabberwock into a more general class hierarchy. This can be a lot of work just for the classes Jabberwock and Dragon, but when you add classes for Medusa, Yeti, Sasquatch, and so on, having common behavior in a reusable superclass significantly reduces the overall amount of work you have to do.
To design a class hierarchy that serves this purpose, start at the top with the class Object, the pinnacle of all Java classes. The most general class to which Jabberwock and Dragon both belong might be called Monster. A monster, generally, is defined as a ferocious creature of some kind that terrorizes people. In the Monster class, you define only the behavior that qualifies something as ferocious and terrifying to people, and nothing more.
Below Monster? How about two classes: FlyingMonster and WalkingMonster? FlyingMonster is different from WalkingMonster because it can fly (obviously). The behaviors of flying monsters might include swooping down on prey, carrying people off into the sky, dropping them from great heights, and so on. Walking monsters behave differently. Figure 2.3 shows what you have so far.
Figure 2.3: The basic Monster hierarchy.
Now the hierarchy becomes even more specific. With FlyingMonster, you may have several subclasses: Mammal, Reptile, Amphibian, and so on. As an alternative, you can factor out still more behavior and have intermediate classes for TwoLegged and FourLegged monsters, with different behaviors for each (see Figure 2.4).
Figure 2.4: Two-legged and four-legged flying monsters.
Finally, the hierarchy is done, and you have a place for Jabberwock. It can be a subclass of reptile, four-legged, flying monsters. (Actually, going all the way up the class hierarchy, Jabberwock would be a subclass of reptile, four-legged, flying monster objects, because FlyingMonster is a subclass of Object.)
Where do qualities such as sex, color, or appetite come in? They come in at the place they fit into the class hierarchy most naturally. If you define sex and color as instance variables in Monster, all subclasses will have those variables as well. Remember that you need to define a feature or a behavior only once in the hierarchy, and it is automatically reused by each subclass.
How does inheritance work? How is it that instances of one class automatically receive variables and methods from the classes further up in the hierarchy? For instance variables, when you create a new instance of a class, you get a slot for each variable defined in the current class and a slot for each variable defined in all its superclasses. In this way, all the classes combine to form a template for the current object, and each object fills in the information appropriate to its situation.
Methods operate similarly. New objects have access to all the method names of the object's class and its superclasses, but method definitions are chosen dynamically when a method is called. That is, if you call a method of a particular object, Java first checks the object's class for the definition of that method. If the method is not defined in the object's class, Java looks in the superclass of that class, and so on up the chain until the method definition is found (see Figure 2.5).
Figure 2.5: How methods are located.
Things get complicated when a subclass defines a method that has the same name, return type, and arguments as a method defined in a superclass. In this case, the method definition that is found first (starting at the bottom of the hierarchy and working upward) is the one that is executed. Because of this, you can intentionally create a new method in a subclass to hide a method in the superclass by defining the new method with the same name, return type, and arguments as the superclass method. This procedure is called overriding (see Figure 2.6).
Figure 2.6: Overriding methods.
Java's form of inheritance, as described in the previous sections, is called single inheritance. The rule of single inheritance is that each Java class can have only one superclass (although any superclass can have multiple subclasses).
In other object-oriented programming languages, such as C++, classes can have more than one superclass, and they inherit the variables and methods from all those superclasses. This arrangement is called multiple inheritance. Multiple inheritance provides enormous power (classes can be created that encompass just about any imaginable behavior), but it also significantly complicates class definitions and the code needed to produce them. Java makes inheritance simpler by allowing only single inheritance.
Because of single inheritance, any Java class has only a single superclass. It inherits variables and methods from all superclasses above it in the hierarchy. This makes subclassing easier to implement and design, but it also can be restricting-especially when you have similar behavior that must be duplicated across different branches of a class hierarchy. Java solves the problem of shared behavior by using interfaces.
An interface is a collection of method names, without actual definitions, which indicate that a class has a set of behaviors in addition to the behaviors it receives from its superclasses. Although a single Java class can have only one superclass, that superclass can also implement any number of interfaces. By implementing an interface, a class provides method definitions for the method names defined by the interface. If two very different classes implement the same interface, they both can respond to the same method calls as defined by that interface. However, what each class does in response to those method calls can be completely different.
You don't need to know much about interfaces right now, so don't panic if this information is confusing. You'll learn more as the book progresses.
In Java, packages are a way of grouping together related classes and interfaces. Packages enable groups of classes to be available only if they are needed. Packages also eliminate potential conflicts between class names in different groups of classes.
For now, you need to know the following things about packages:
As a final exercise in this chapter, you will create a subclass of another class and override some methods. You also will get a better feel for how packages work.
When you start programming in Java, the most common use of subclassing is when applets are created. You already relied on subclassing when you wrote JabberwockApplet. All applets are subclasses of the class Applet, which is part of the java.applet package. By creating a subclass of Applet, you automatically received behavior from windowing and layout classes that enabled your applet to be drawn in the right place and to interact with system operations such as mouse clicks and key presses.
To become familiar with subclassing, we'll create an applet called BigPalindrome, a program that displays a line of text that reads the same backwards as forwards (and does so with some panache). Begin developing a new applet with the filename BigPalindrome.java.
To start the example, first construct the class definition for the applet. Enter the following class definition:
public class BigPalindrome extends java.applet.Applet { // placeholder }
This definition creates a class called BigPalindrome. Take a look at the phrase extends java.applet.Applet-this phrase is what makes BigPalindrome a subclass of the Applet class. Because the Applet class is contained in the java.applet package, as opposed to the java.lang package, you do not have automatic access to the class. You have to refer to it explicitly by package and class name.
The other new part of this class definition is the public keyword. The public keyword means that your class is available to the Java system at large once it is loaded. Most of the time, you need to make a class public only if you want it to be visible to all other classes in your Java program. However, applets must be declared as public.
A class definition with nothing in it is pointless-if you don't add anything new, or override the variables or methods of its superclasses, why is the new class needed at all? Let's add some things to make this class different from its superclass.
First, add an instance variable to contain a Font object. Replace the // placeholder line with the following:
Font f = new Font("TimesRoman", Font.BOLD, 30);
The f instance variable now contains a new instance of the class Font, part of the java.awt package. This particular font object is a 30-point Times Roman font in boldface style. If a Font object is not used and text is displayed, it defaults to 12-point Times Roman. By using a Font object, you can change the font of the text displayed in your applet.
By creating an instance variable to hold this Font object, you make the object available to all the methods in your class. Now, you will create a method that uses the object.
When you write applets, there are several standard methods defined in the Applet superclass that you normally will override in the class of your applet. These standard methods include methods to initialize the applet, to start it running, to handle operations such as mouse movements, and to clean up when the mouse stops running.
One of the methods in the Applet superclass is the paint() method, which displays your applet on-screen. The default definition of paint() does nothing at all-it's an empty method. By overriding paint(), you tell the applet what should be drawn on-screen. After the Font line, enter the following definition for paint():
public void paint(Graphics g) { g.setFont(f); g.setColor(Color.red); g.drawString("Go hang a salami, I'm a lasagna hog.", 5, 25); }
Note that this method is declared public, just as the applet itself was. Unlike the applet, however, the paint() method is public because the method it is overriding also is public. If the method of a superclass is defined as public, the method to override it also has to be public or an error will occur when the class is compiled.
Also note that the paint() method takes a single argument: an instance of the Graphics class. The Graphics class provides platform-independent behavior for rendering fonts, colors, and basic drawing operations. You learn more about the Graphics class in Chapter 18, "Programming Applets," when you create more extensive applets.
Inside your paint() method, you have done the following:
For an applet this simple, no more code seems necessary. However, something is missing. If you don't know what it is, save the source file and compile it. You will get a bunch of errors like the following:
BigPalindrome.java:3: Class Font not found in type declaration.
These errors occur because classes such as Font and Graphics are part of a package. Remember that the only package you automatically have access to is java.lang. You referred to the Applet class in the first line of the class definition by referring to its full package name (java.applet.Applet). Further down in the program, however, you referred to several other classes as if they already were available.
There are two ways to solve this problem. You can refer to all external classes by full package name, or you can import the appropriate class or package at the beginning of your class file. The solution you choose is mostly a matter of personal choice, but if you refer to a class in another package numerous times, you may want to use the import statement to cut down on the typing required.
In the BigPalindrome example, import the needed classes: Graphics, Font, and Color. All three are part of the java.awt package. Before the first line of the program, insert the following three lines:
import java.awt.Graphics; import java.awt.Font; import java.awt.Color;
Tip |
You also can import an entire package of public classes by using an asterisk (*) in place of a specific class name. For example, to import all classes in the awt package, you can use the following statement: import java.awt.*; |
Listing 2.3 shows the full source code of the BigPalindrome applet.
Listing 2.3. BigPalindrome.java.
1: import java.awt.Graphics; 2: import java.awt.Font; 3: import java.awt.Color; 4: 5: public class BigPalindrome extends java.applet.Applet { 6: 7: Font f = new Font("TimesRoman", Font.BOLD, 30); 8: 9: public void paint(Graphics g) { 10: g.setFont(f); 11: g.setColor(Color.red); 12: g.drawString("Go hang a salami, I'm a lasagna hog.", 5, 25); 13: } 14: }
Now that the proper classes have been imported into your program, it should work successfully. Compile the applet, and if you have to create an HTML page to see it, enter the code in Listing 2.4 into a file called BigPalindrome.html. Java Developers Kit users can see the output of the applet by using the following command:
appletviewer BigPalindrome.html
Listing 2.4. The HTML code of BigPalindrome.html.
1: <html> 2: <body> 3: <applet code=BigPalindrome.class height=150 width=500> 4: </applet> 5: </body> 6: </html>
Run the applet and the output should look like Figure 2.7.
Figure 2.7: The output of the BigPalindrome applet.
If this chapter was your first encounter with object-oriented programming, a lot of the information probably seems both theoretical and overwhelming at this point. You do not have to fully understand the information yet because you will be using object-oriented techniques for the rest of this book. The information will become more familiar to you as you gain more experience.
One of the biggest hurdles of object-oriented programming is not
necessarily the concepts, it's the names. There is a lot of jargon.
To summarize the material in this chapter, here's a glossary of
terms and concepts that were covered:
class | A template for an object that contains variables to describe the object, and methods to describe how the object behaves. Classes can inherit variables and methods from other classes. |
Object | A concrete instance of a class-in other words, a real instance that has been created using a class as its template. Multiple instances of the same class have access to the same methods, but they often have different values for their instance variables. |
Instance | An object made real through the use of a class. |
Superclass | A class further up the class hierarchy than another class (its subclass). The subclass inherits variables and methods from all superclasses above it in the hierarchy. |
Subclass | A class further down the class hierarchy than another class (its superclass). When you create a new class to inherit the behavior of another class, the process is called subclassing. |
Instance method | A method defined in a class that operates on an instance of that class. Instance methods usually are just called methods. |
class method | A method defined in a class that operates on the class itself and can be called through the class or any of its instances. |
Instance variable | A variable owned by an individual instance of a class, and whose value is stored in that instance. |
class variable | A variable owned by the class and all its instances as a whole, and whose value is stored in the class. |
Interface | A collection of abstract behavior specifications that can be implemented by individual classes. |
Package | A collection of related classes and interfaces. Classes from packages other than java.lang must be imported explicitly or referred to by their full package names. |