Timothy Budd - Understanding Object-Oriented Programming With Java
Timothy Budd - Understanding Object-Oriented Programming With Java
Timothy A. Budd
Oregon State University
Corvallis, Oregon
USA All rights reserved.
No part of this publication may be reproduced,
stored in a retrieval system, or transmitted,
in any form or by any means, electronic, mechanical,
photocopying, recording, or otherwise,
without the prior written permission of the Author.
Copyright 1997 by Timothy A. Budd
July 23, 1997
0
2. I've tried (not always successfully) to avoid sounding like a language reference man-
ual. In fact, many items of syntax or features of the library that are not particulary
notworthy are not explained in detail at all. Will instructors see this as a serious
disadvantage?
3. There are three chapters in part 1. The history chapter is probably expected, but
is somewhat unrelated to the other two. This makes deciding the appropriate order
somewhat dicult.
4. Part 5 of the book is somewhat problematic. It doesn't t well with the rest of the
book, but I've not found a way to t it in with the structure of the earlier sections.
The material is not necessarily so advanced that it should be left this late { in fact,
I can imagine that many instructors would want to reference some of the material
earlier in the term.
5. Should more emphasis be placed on applets and the web? I see this as a rather
tangental issue, but I suspect others might disagree.
6. In addition to study questions and exercises, a feature I started adding to some of the
later chapters is a short section near the end entitied cross references. This would be a
short section where I point out where in the book I discuss in more details ideas that
might have been only glossed over in the current chapter. Since so many concepts are
so entertwined, it is not possible to discuss everything at once. This would help the
reader trying to track down a specic idea, or trying to nd an example that illustrates
the use of a given construct.
7. Are there other topics you think I should address that are not described here either
in the text or the table of contents?
A potential source of problems is the fact that Java is not yet a stable language. Ev-
erything I describe here is version 1.1 (which may already be one version more recent than
some of the reviewers). However, some of the hints I have heard indicate that there is likely
another round of language revisions coming soon, particularly the introduction of generics,
which, if true, should certainly be mentioned in part 4 of the book.
Contents
I Understanding the Object-Oriented World View 11
1 Object-Oriented Thinking 13
1.1 A Way of Viewing the World . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.1.1 Agents and Communities . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.1.2 Responsibility, Messages, and Methods . . . . . . . . . . . . . . . . . . 15
1.1.3 Responsibilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.1.4 Classes and Instances . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.1.5 Class Hierarchies{Inheritance . . . . . . . . . . . . . . . . . . . . . . . 16
1.1.6 Method Binding, Overriding, and Exceptions . . . . . . . . . . . . . . 19
1.1.7 Summary of Object-Oriented Concepts . . . . . . . . . . . . . . . . . 19
1.2 Computation as Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.2.1 The Power of Metaphor . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.3 Chapter Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2 A Brief History of Java 27
2.1 Client Side Computing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2.1.1 Bytecode Interpreters and Just In Time Compilers . . . . . . . . . . . 29
2.1.2 Security Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.1.3 Specialization of Interfaces . . . . . . . . . . . . . . . . . . . . . . . . 30
2.2 The White Paper Description . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.2.1 Java is Simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2.2 Java is Object-Oriented . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2.3 Java is Network Savvy . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2.4 Java is Interpreted . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.2.5 Java is Robust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.2.6 Java is Secure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2.7 Java is Architecture Neutral . . . . . . . . . . . . . . . . . . . . . . . . 33
2.2.8 Java is Portable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.2.9 Java is High-performance . . . . . . . . . . . . . . . . . . . . . . . . . 34
2.2.10 Java is Multithreaded . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3
4 CONTENTS
II Understanding Paradigms 59
4 A Paradigm 61
4.1 Program Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
4.2 The Connection to the Java world . . . . . . . . . . . . . . . . . . . . . . . . 64
4.3 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
4.4 Access Modiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
4.5 Lifetime Modiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
CONTENTS 5
15.11Bridge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
15.12Chapter Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
Understanding the
Object-Oriented World View
11
Chapter 1
Object-Oriented Thinking
This is a book about object-oriented programming. In particular, this is a book that explores
the principle ideas of object-oriented programming in the context of the Java programming
language. Object-oriented programming has been a hot topic for the past decade, and more
recently Java has become the commonly perceived embodiment of object-oriented ideas.
This book will help you understand Java. It makes no pretensions to being a language
reference manual there are many other books that fall into that category. But knowing the
syntax for a language should not be confused with an understanding of why the language
has been developed in the way it has, why certain things are done the way they are, or why
Java programs look the way they do. This book explores this issue of why.
Object-oriented programming is frequently referred to as a new programming paradigm.
The word paradigm originally meant example, or model. For example, a paradigm sentence
would help you remember how to conjugate a word in a foreign language. More generally,
a model is an example that helps you understand how the world works. For example, the
Newtonian model of physics explains why apples fall to the ground. In computer science, a
paradigm explains how the elements that go into making a computer program are organized
and how they interact with each other. For this reason the rst step in understanding Java
is appreciating the object-oriented world view.
easy enough task I merely go down to my local orist (who happens to be named Flora),
tell her the variety and quantity of owers I wish to send and give her Sally's address, and
I can be assured the owers will be delivered expediently and automatically.
Let us move our discussion back to the level of computers and programs. There, the
distinction between message passing and procedure calling is that, in message passing, there
is a designated receiver, and the interpretation{the selection of a method to execute in
response to the message{may vary with dierent receivers. Usually, the specic receiver
for any given message will not be known until run time, so the determination of which
method to invoke cannot be made until then. Thus, we say there is late binding between
the message (function or procedure name) and the code fragment (method) used to respond
to the message. This situation is in contrast to the very early (compile-time or link-time)
binding of name to code fragment in conventional procedure calls.
1.1.3 Responsibilities
A fundamental concept in object-oriented programming is to describe behavior in terms of
responsibilities. My request for action indicates only the desired outcome ( owers for my
friend). Flora is free to pursue any technique that achieves the desired objective and is not
hampered by interference on my part.
By discussing a problem in terms of responsibilities we increase the level of abstraction.
This permits greater independence between agents, a critical factor in solving complex prob-
lems. The entire collection of responsibilities associated with an object is often described
by the term protocol.
The dierence between viewing software in traditional, structured terms and viewing it
from an object-oriented perspective can be summarized by a twist on a well-known quote:
Ask not what you can do to your data structures,
but rather ask what your data structures can do for you.
1.1.4 Classes and Instances
Although I have only dealt with Flora a few times, I have a rough idea of the behavior I can
expect when I go into her shop and present her with my request. I am able to make certain
assumptions because I have information about orists in general, and I expect that Flora,
being an instance of this category, will t the general pattern. We can use the term Florist
to represent the category (or class) of all orists. Let us incorporate these notions into our
next principle of object-oriented programming:
All objects are instances of a class. The method invoked by an object in response
to a message is determined by the class of the receiver. All objects of a given
class use the same method in response to similar messages.
' $
Material Object
' $
Animal
' Mammal
$
' $
'Human
$
Shopkeeper
' $
Florist
Flora
&
& %%
&
& %
%
& %
& %
Figure 1.2: { The categories surrounding Flora.
of the transaction, and that in return for payment I will be given a receipt. These actions
are true of grocers, stationers, and other shopkeepers. Since the category Florist is a more
specialized form of the category Shopkeeper, any knowledge I have of Shopkeepers is also
true of Florists and hence of Flora.
One way to think about how I have organized my knowledge of Flora is in terms of a
hierarchy of categories (see Figure 1.2). Flora is a Florist, but Florist is a specialized form
of Shopkeeper. Furthermore, a Shopkeeper is also a Human so I know, for example, that
Flora is probably bipedal. A Human is a Mammal (therefore they nurse their young and
have hair), and a Mammal is an Animal (therefore it breathes oxygen), and an Animal is a
Material Object (therefore it has mass and weight). Thus, quite a lot of knowledge that I
have that is applicable to Flora is not directly associated with her, or even with her category
Florist.
The principle that knowledge of a more general category is also applicable to a more
18 CHAPTER 1. OBJECT-ORIENTED THINKING
Material Objects
HH
HH
HH
HH
H
HH
H
Animal Plant
Mammal
X
Flower
;@XXXXX
; @ XXX
XXX
;
; @
@ XX
Dog Human Platypus
;H
B HH
; B HH
;
; B
B HH
Shopkeeper Artist Dentist
Florist Potter
specic category is called inheritance. We say that the class Florist will inherit attributes of
the class (or category) Shopkeeper.
There is an alternative graphical technique often used to illustrate this relationship,
particularly when there are many individuals with diering lineage's. This technique shows
classes listed in a hierarchical tree-like structure, with more abstract classes (such as Material
Object or Animal) listed near the top of the tree, and more specic classes, and nally
individuals, are listed near the bottom. Figure 1.3 shows this class hierarchy for Flora. This
same hierarchy also includes Elizabeth, my dog Flash, Phyl the platypus who lives at the
zoo, and the owers I am sending to my friend.
Information that I possess about Flora because she is an instance of class Human is also
applicable to my wife Elizabeth, for example. Information that I have about her because
1.1. A WAY OF VIEWING THE WORLD 19
she is a Mammal is applicable to Flash as well. Information about all members of Material
Object is equally applicable to Flora and to her owers. We capture this in the idea of
inheritance:
Classes can be organized into a hierarchical inheritance structure. A child class
(or subclass) will inherit attributes from a parent class higher in the tree. An
abstract parent class is a class (such as Mammal) for which there are no direct
instances it is used only to create subclasses.
1. Everything is an object.
2. Computation is performed by objects communicating with each other, requesting that
other objects perform actions. Objects communicate by sending and receiving mes-
sages. A message is a request for action bundled with whatever arguments may be
necessary to complete the task.
3. Each object has its own memory, which consists of other objects.
4. Every object is an instance of a class. A class simply represents a grouping of similar
objects, such as integers or lists.
5. The class is the repository for behavior associated with an object. That is, all objects
that are instances of the same class can perform the same actions.
6. Classes are organized into a singly rooted tree structure, called the inheritance hier-
archy. Memory and behavior associated with instances of a class are automatically
available to any class associated with a descendant in this tree structure.
i: j:
2 3
#
# x:
47
"!
"! a1]: a2]: a3]: a4]:
4 6 2 4
can quickly assemble the way a kid builds faces on Mr. Potato Head.
Possibly this feature, more than any other, is responsible for the frequent observation
that it is often easier to teach object-oriented programming concepts to computer novices
than to computer professionals. Novice users quickly adapt the metaphors with which they
are already comfortable from their everyday life, whereas seasoned computer professionals
are blinded by an adherence to more traditional ways of viewing computation.
As you start to examine the Java programs presented in the book, as well as creating
your own Java programs, you may nd it useful to envision the process of programming as
similar to the task of \training" a universe of agents to interact smoothly with each other,
each providing a certain small and well dened service to the others, each contributing to
the eective execution of the whole.
can be created and tested as independent units, in isolation from other portions of a
software application.
Reusable software components permit the programmer to deal with problems on a
higher level of abstraction. We can dene and manipulate objects simply in terms of
the messages they understand and a description of the tasks they perform, ignoring
implementation details.
Further Reading
I said at the beginning of the chapter that this is not a reference manual. The reference
manual written by the developers of the language is Gosling 96]. But perhaps even more
useful for most programmers is the annotated description of the Java class library pre-
sented by Chan 96]. Information on the internal workings of the Java system is presented
by Lindholm 97].
I noted earlier that many consider Alan Kay to be the father of object-oriented pro-
gramming. Like most simple assertions, this one is only somewhat supportable. Kay
himself Kay 1993] traces much of the in uence on his development of Smalltalk to the
earlier computer programming language Simula, developed in Scandinavia in the early
1960s Dahl 1966]. A more accurate history would be that most of the principles of object-
oriented programming were fully worked out by the developers of Simula, but that these
would have been largely ignored by the profession had they not been rediscovered by Kay
in the creation of the Smalltalk programming language. A widely read 1981 issue of Byte
magazine, in which the quote by Ingalls given earlier in this chapter appears, did much to
popularize the concepts developed by Kay and his team at Xerox PARC.
Like most terms that have found their way into the popular jargon, object-oriented is used
more often than it is dened. Thus, the question What is object-oriented programming?
is surprisingly dicult to answer. Bjarne Stroustrup has quipped that many arguments
appear to boil down to the following syllogism:
X is good.
Object-oriented is good.
Ergo, X is object-oriented Stroustrup 1988].
Roger King argued Kim 1989], that his cat is object-oriented. After all, a cat exhibits char-
acteristic behavior, responds to messages, is heir to a long tradition of inherited responses,
and manages its own quite independent internal state.
Many authors have tried to provide a precise description of the properties a program-
ming language must possess to be called object-oriented. I myself have written an earlier
book (Budd 97]) that tries to explain object-oriented concepts in a language-indepent fash-
ion. See also, for example, the analysis by Josephine Micallef Micallef 1988], or Peter
24 CHAPTER 1. OBJECT-ORIENTED THINKING
Wegner Wegner 1986]. Wegner, distinguishes object-based languages, which support only
abstraction (such as Ada), from object-oriented languages, which must also support inheri-
tance.
Other authors{notably Brad Cox Cox 1990]{dene the term much more broadly. To
Cox, object-oriented programming represents the objective of programming by assembling
solutions from collections of o-the-shelf subcomponents, rather than any particular tech-
nology we may use to achieve this objective. Rather than drawing lines that are divisive, we
should embrace any and all means that show promise in leading to a new software Industrial
Revolution. Cox's book on OOP Cox 1986], although written early in the development of
object-oriented programming and now somewhat dated in details, is nevertheless one of the
most readable manifestos of the object-oriented movement.
Study Questions
1. What is the original meaning of the word paradigm?
2. How do objects interact with each other?
3. How are messages dierent from procedure calls?
4. What is the name applied to describe an algorithm an object uses to respond to a
request?
5. Why does the object-oriented approach naturally imply a high degree of information
hiding?
6. What is a class? How are classes linked to behavior?
7. What is a class inheritance hierarchy? How is it linked to classes and behavior?
8. What does it mean for one method to override another method from a parent class?
9. What are the basic elements of the process-state model of computation?
10. How does the object-oriented model of computation dier from the process-state
model?
Exercises
1. In an object-oriented inheritance hierarchy, each level is a more specialized form of
the preceding level. Give an example of a hierarchy found in everyday life that has
this property. Some types of hierarchy found in everyday life are not inheritance
hierarchies. Give an example of a noninheritance hierarchy.
Further Reading 25
2. Look up the denition of paradigm in at least three dictionaries. Relate these deni-
tions to computer programming languages.
3. Take a real-world problem, such as the task of sending owers described earlier, and
describe its solution in terms of agents (objects) and responsibilities.
4. If you are familiar with two or more distinct computer programming languages, give
an example of a problem showing how one language would direct the programmer to
one type of solution, and a dierent language would encourage an alternative solution.
5. Argue either for or against the position that computing is basically simulation. (You
may want to read the article by Alan Kay in Scientic American Kay 1977].)
26 CHAPTER 1. OBJECT-ORIENTED THINKING
Chapter 2
and intimately tied into the other aspects of the language. This exception handing facility
meant that any programmer writing in Java would be forced to deal with the possibilities of
how programs could fail in unpredictable ways, and create code to handle the unexpected
in a (hopefully) graceful fashion.
For a number of reasons, Java (or Oak) as a language for embedded consumer electronics
did not materialize. But as interest in embedded systems at Sun was starting to wane, the
phenomena known as the World-Wide-Web was just beginning. The Web was originally
developed in the late 1980s by a small group of scientists at a research lab in Switzerland as
a means of quickly communicating research results to a physically far ung set of colleagues.
It was quickly realized, however, that the framework provided by the Web was applicable
to a wide range of information. First scientists in all disciplines started using the Web, and
eventually the ideas found their way into the mainstream. Now, almost every organization,
large or small, must have a web page. Similarly, almost every advertisement in print or
television contains an obligatory web address, or URL.
To understand how Java ts into the world-wide-web, and the importance of internet
computing, one must rst understand a little about the concept of clients and servers, and
the dierence between server side computing and client side computing.
@
XXX @
@
with many clients at once (perhaps hundreds or thousands), causing further reduction in
performance. In contrast, the client machines are often lightly loaded personal machines.
Frequently the client machine is executing little more than the single internet application.
The key idea of client-side computing is that rather than executing the program on the
server side and transmitting the result, the server will transmit the program to the client.
The client will then execute the program locally. Not only is the program then run on a
less heavily loaded system, but the only delay is the time to transmit the program. Once
the program starts executing, any interactions between the user and the program take place
locally, and do not need to cross the internet.
and translates them into the native machine code for the client system. These programs
then run as fast as any compiled program created specically for the client computer.
in this book will not), the language provides a rich set of tools for programming across
a network. The Java standard library provides a plethora of classes for describing URLs
(Universal Resource Locators), for making connections between client and server computers
(See Chapter 22), and for execution in controlled environments such as a world-wide-web
browser.
Another feature that makes Java programs more robust is automatic memory manage-
ment, or garbage collection. Programmers writing in languages that use manual memory
management, for example C++, frequently forget to release memory resources once they
are nished with them. Long running programs therefore slowly increase their memory
requirements, until they catastrophically fail. The Java run-time system instead automat-
ically detects and recovers memory that is no longer being used by the currently running
program. This both simplies the programmers task, and makes programs more reliable.
Study Questions
1. What was the original name given to the Java language?
2. What was the original intended use of Java programs?
3. What are some characteristics of embedded systems?
4. What is the dierence between server-side computing (also known as cgi-bin process-
ing) and client-side computing?
5. What is a just-in-time compiler?
36 CHAPTER 2. A BRIEF HISTORY OF JAVA
Chapter 3
Object-Oriented Design
A supercial description of the dierences between an object-oriented language, such as Java,
and a conventional programming language, such as Pascal, might concentrate on syntactic
dierences. In this area discussion would center on topics such as classes, inheritance,
message passing, and methods. But such an analysis miss the most important point of
object-oriented programming, which has nothing to do with syntax.
Working in an object-oriented language (that is, one that supports inheritance, message
passing, and classes) is neither a necessary nor sucient condition for doing object-oriented
programming. As we emphasized in Chapter 1, the most important aspect of OOP is a design
technique driven by the determination and delegation of responsibilities among members of a
community of agents working together in the solution of a common problem. This technique
has been called responsibility-driven design Wirfs-Brock 1989b, Wirfs-Brock 1990].
of individual components, who may dier as well from those involved in the integration
of various components in the nal product. No single individual can be considered
responsible for the entire project, or even necessarily understands all aspects of the
project.
The major problem in the software development process is the management of details
and the communication of information between diverse portions of the project.
While the beginning student will usually be acquainted with programming in the small,
aspects of many object-oriented languages are best understood as responses to the problems
encountered while programming in the large. Thus, some appreciation of the diculties
involved in developing large systems is a helpful prerequisite to understanding OOP.
' $
P
PP
H
H PP
H HH PH
HH H H HH Welcome
H HPPH to the
H
HH H PHPH IIKH
HHHH HH HP PHP the
HH HHHH HHH P
H HHHHPP Interactive
HHHHH H HH H P Intelligent
HHH HH HHHHHH P Kitchen
HH H HHHHH Helper
HHHH
HH
HH Press Return
to begin
HH
HH
& %
H
22222222
222222222
2222222
maintaining a database of recipes, the kitchen helper assists in the planning of meals for an
extended period, say a week. The user of the IIKH can sit down at a terminal, browse the
database of recipes, and interactively create a series of menus. The IIKH will automatically
scale the recipes to any number of servings and will print out menus for the entire week, for
a particular day, or for a particular meal. And it will print an integrated grocery list of all
the items needed for the recipes for the entire period.
As is usually true with the initial descriptions of most software systems, the specication
for the IIKH is highly ambiguous on a number of important points. It is also true that, in
all likelihood, the eventual design and development of the software system to support the
IIKH will require the eorts of several programmers working together. Thus, the initial goal
of the software team must be to clarify the ambiguities in the description and to outline how
the project can be divided into components to be assigned for development to individual
team members.
The fundamental cornerstone of object-oriented programming is to characterize software
in terms of behavior that is, actions to be performed. We will see this repeated on many
levels in the development of the IIKH. Initially, the team will try to characterize, at a
3.5. CRC CARDS{RECORDING RESPONSIBILITY 41
very high level of abstraction, the behavior of the entire application. This then leads to
a description of the behavior of various software subsystems. Only when all behavior has
been identied and described will the software design team proceed to the coding step. In
the next several sections we will trace the tasks the software design team will perform in
producing this application.
A component should interact with other components to the minimal extent possible.
We will shortly discuss the reasoning behind the second characteristic. For the moment we
are simply concerned with the identication of component responsibilities.
already possessed a working system. Every activity that must take place is identied and
assigned to some component as a responsibility.
As part of this process, it is often useful to represent components using small index
cards. Written on the face of the card is the name of the software component, the respon-
sibilities of the component, and the names of other components with which the component
must interact. Such cards are sometimes known as CRC (Component, Responsibility, Collab-
orator) cards Beck 1989, Bellin 97], and are associated with each software component. As
responsibilities for the component are discovered, they are recorded on the face of the CRC
card.
3.5.1 Give Components a Physical Representation
While working through scenarios, it is useful to assign CRC cards to dierent members
of the design team. The member holding the card representing a component records the
responsibilities of the associated software component, and acts as the \surrogate" for the
software during the scenario simulation. He or she describes the activities of the software
system, passing \control" to another member when the software system requires the services
of another component.
An advantage of CRC cards is that they are widely available, inexpensive, and erasable.
This encourages experimentation, since alternative designs can be tried, explored, or aban-
doned with little investment. The physical separation of the cards encourages an intuitive
understanding of the importance of the logical separation of the various components, helping
to emphasize the cohesion and coupling (which we will describe shortly). The constraints
of an index card are also a good measure of approximate complexity{a component that is
3.5. CRC CARDS{RECORDING RESPONSIBILITY 43
expected to perform more tasks than can t easily in this space is probably too complex, and
the team should nd a simpler solution, perhaps by moving some responsibilities elsewhere
to divide a task between two or more new components.
3.5.3 Documentation
At this point the development of documentation should begin. Two documents should be
essential parts of any software system: the user manual and the system design documen-
tation. Work on both of these can commence even before the rst line of code has been
written.
The user manual describes the interaction with the system from the user's point of
view it is an excellent means of verifying that the development team's conception of the
application matches the client's. Since the decisions made in creating the scenarios will
closely match the decisions the user will be required to make in the eventual application,
the development of the user manual naturally dovetails with the process of walking through
scenarios.
Before any actual code has been written, the mindset of the software team is most similar
to that of the eventual users. Thus, it is at this point that the developers can most easily
anticipate the sort of questions to which a novice user will need answers.
The second essential document is the design documentation. The design documentation
records the major decisions made during software design, and should thus be produced when
these decisions are fresh in the minds of the creators, and not after the fact when many of
the relevant details will have been forgotten. It is often far easier to write a general global
description of the software system early in the development. Too soon, the focus will move
to the level of individual components or modules. While it is also important to document
44 CHAPTER 3. OBJECT-ORIENTED DESIGN
the module level, too much concern with the details of each module will make it dicult for
subsequent software maintainers to form an initial picture of the larger structure.
CRC cards are one aspect of the design documentation, but many other important
decisions are not re ected in them. Arguments for and against any major design alternatives
should be recorded, as well as factors that in uenced the nal decisions. A log or diary of
the project schedule should be maintained. Both the user manual and the design documents
are rened and evolve over time in exactly the same way the software is rened and evolves.
Greeter Collaborators
Database Manager
Display Informative Initial Message
Plan Manager
Oer User Choice of Options
Pass Control to either
Recipe Database Manager
Plan Manager for processing
categories, such as \soups," \salads," \main meals," and \desserts"? Alternatively, should
the user be able to describe keywords to narrow a search, perhaps by providing a list of
ingredients, and then see all the recipes that contain those items (\Almonds, Strawberries,
Cheese"), or a list of previously inserted keywords (\Bob's favorite cake")? Should scroll
bars be used or simulated thumb holes in a virtual book? These are fun to think about,
but the important point is that such decisions do not need to be made at this point (see
Section 3.6.2, \Preparing for Change"). Since they aect only a single component, and do
not aect the functioning of any other system, all that is necessary to continue the scenario
is to assert that by some means the user can select a specic recipe.
The primary objective is that changes should aect as few components as possible.
Even major changes in the appearance or functioning of an application should be
possible with alterations to only one or two sections of code.
Try to predict the most likely sources of change and isolate the eects of such changes
to as few software components as possible. The most likely sources of change are
interfaces, communication formats, and output formats.
Try to isolate and reduce the dependency of software on hardware. For example, the
interface for recipe browsing in our application may depend in part on the hardware
on which the system is running. Future releases may be ported to dierent platforms.
A good design will anticipate this change.
Reducing coupling between software components will reduce the dependence of one
upon another, and increase the likelihood that one can be changed with minimal eect
on the other.
In the design documentation maintain careful records of the design process and the
discussions surrounding all major decisions. It is almost certain that the individuals
responsible for maintaining the software and designing future releases will be at least
partially dierent from the team producing the initial release. The design documen-
tation will allow future teams to know the important factors behind a decision and
help them avoid spending time discussing issues that have already been resolved.
of performing this new task are a subset of those we already identied in permitting users
to edit existing recipes.
Having explored the browsing and creation of new recipes, we return to the Greeter and
investigate the development of daily menu plans, which is the Plan Manager's task. In some
way (again, the details are unimportant here) the user can save existing plans. Thus, the
Plan Manager can either be started by retrieving an already developed plan or by creating
a new plan. In the latter case, the user is prompted for a list of dates for the plan. Each
date is associated with a separate Date component. The user can select a specic date for
further investigation, in which case control is passed to the corresponding Date component.
Another activity of the Plan Manager is printing out the recipes for the planning period.
Finally, the user can instruct the Plan Manager to produce a grocery list for the period.
The Date component maintains a collection of meals as well as any other annotations
provided by the user (birthday celebrations, anniversaries, reminders, and so on). It prints
information on the display concerning the specied date. By some means (again unspecied),
the user can indicate a desire to print all the information concerning a specic date or choose
to explore in more detail a specic meal. In the latter case, control is passed to a Meal
component.
The Meal component maintains a collection of augmented recipes, where the augmenta-
tion refers to the user's desire to double, triple, or otherwise increase a recipe. The Meal
component displays information about the meal. The user can add or remove recipes from
the meal, or can instruct that information about the meal be printed. In order to discover
new recipes, the user must be permitted at this point to browse the recipe database. Thus,
the Meal component must interact with the recipe database component. The design team
will continue in this fashion, investigating every possible scenario. The major category of
scenarios we have not developed here is exceptional cases. For example, what happens if a
user selects a number of keywords for a recipe and no matching recipe is found? How can
the user cancel an activity, such as entering a new recipe, if he or she decides not to con-
tinue? Each possibility must be explored, and the responsibilities for handling the situation
assigned to one or more components.
Having walked through the various scenarios, the software design team eventually decides
that all activities can be adequately handled by six components (Figure 3.3). The Greeter
needs to communicate only with the Plan Manager and the Recipe Database components.
The Plan Manager needs to communicate only with the Date component and the Date
agent, only with the Meal component. The Meal component communicates with the Recipe
Manager and, through this agent, with individual recipes.
Greeter
H
;
;
HH
H
Plan Manager Recipe Database
@ Q
@ Q
Date Q
Q
Q
H Meal
HH
Recipe
Figure 3.3: { Communication between the six components in the IIKH.
diagram, time moves forward from the top to the bottom. Each component is represented by
a labeled vertical line. A component sending a message to another component is represented
by a horizontal arrow from one line to another. Similarly, a component returning control
and perhaps a result value back to the caller is represented by an arrow. (Some authors use
two dierent arrow forms, such as a solid line to represent message passing and a dashed
line to represent returning control.) The commentary on the right side of the gure explains
more fully the interaction taking place.
With a time axis, the interaction diagram is able to describe better the sequencing of
events during a scenario. For this reason, interaction diagrams can be a useful documenta-
tion tool for complex software systems.
Recipe component this includes activities such as editing the preparation instructions,
displaying the recipe on a terminal screen, or printing a copy of the recipe.
The state of a component represents all the information held within it. For our Recipe
component the state includes the ingredients and preparation instructions. Notice
that the state is not static and can change over time. For example, by editing a recipe
(a behavior) the user can make changes to the preparation instructions (part of the
state).
It is not necessary that all components maintain state information. For example, it
is possible that the Greeter component will not have any state since it does not need to
remember any information during the course of execution. However, most components will
consist of a combination of behavior and state.
The term class is used to describe a set of objects with similar behavior. We will see
in later chapters that a class is also used as a syntactic mechanism in almost all object-
oriented languages. An individual representative of a class is known as an instance. Note
that behavior is associated with a class, not with an individual. That is, all instances of
a class will respond to the same instructions and perform in a similar manner. On the
other hand, state is a property of an individual. We see this in the various instances of the
class Recipe. They can all perform the same actions (editing, displaying, printing) but use
dierent data values.
description is valid regardless of the particular implementation used by the Recipe Database
component to perform the actual browsing action.
The purposeful omission of implementation details behind a simple interface is known
as information hiding. We say the component encapsulates the behavior, showing only how
the component can be used, not the detailed actions it performs. This naturally leads
to two dierent views of a software system. The interface view is the face seen by other
programmers. It describes what a software component can perform. The implementation
view is the face seen by the programmer working on a particular component. It describes
how a component goes about completing a task.
The separation of interface and implementation is perhaps the most important concept in
software engineering. Yet it is dicult for students to understand, or to motivate. Informa-
tion hiding is largely meaningful only in the context of multiperson programming projects.
In such eorts, the limiting factor is often not the amount of coding involved, but the amount
of communication required between the various programmers and between their respective
software systems. As we will describe shortly, software components are often developed in
parallel by dierent programmers, and in isolation from each other.
There is also an increasing emphasis on the reuse of general-purpose software components
in multiple projects. For this to be successful, there must be minimal and well-understood
interconnections between the various portions of the system. These ideas were captured by
computer scientist David Parnas in a pair of rules, known as Parnas's principles:
The developer of a software component must provide the intended user with all the
information needed to make eective use of the services provided by the component,
and should provide no other information.
The developer of a software component must be provided with all the information
necessary to carry out the given responsibilities assigned to the component, and should
be provided with no other information.
A consequence of the separation of interface from implementation is that a program-
mer can experiment with several dierent implementations of the same structure without
aecting other software components.
implemented as classes. Names are given to each of the responsibilities identied on the CRC
card for each component, and these will eventually be mapped onto function or procedure
names. Along with the names, the types of any arguments to be passed to the function
are identied. Next, the information maintained within the component itself should be
described. All information must be accounted for. If a component requires some data to
perform a specic task, the source of the data, either through argument or global value, or
maintained internally by the component, must be clearly identied.
Date Collaborators
Plan Manager
Maintain information about specic date
Meal
Date(year, month, day){create new date
DisplayAndEdit(){display date information
in window allowing user to edit entries
BuildGroceryList(List &){add items from
all means to grocery list
that a true value means the printer is working, whereas \PrinterStatus" is much less
precise.
Take extra care in the selection of names for operations that are costly and infrequently
used. By doing so, errors caused by using the wrong function can be avoided.
Once names have been developed for each activity, the CRC cards for each component
are redrawn, with the name and formal arguments of the function used to elicit each behavior
identied. An example of a CRC card for the Date is shown in Figure 3.5. What is not yet
specied is how each component will perform the associated tasks.
Once more, scenarios or role playing should be carried out at a more detailed level to
ensure that all activities are accounted for, and that all necessary information is maintained
and made available to the responsible components.
designing the data structures that will be used by each subsystem to maintain the state
information required to fulll the assigned responsibilities.
It is here that the classic data structures of computer science come into play. The
selection of data structures is an important task, central to the software design process. Once
they have been chosen, the code used by a component in the fulllment of a responsibility
is often almost self-evident. But data structures must be carefully matched to the task at
hand. A wrong choice can result in complex and inecient programs, while an intelligent
choice can result in just the opposite.
It is also at this point that descriptions of behavior must be transformed into algorithms.
These descriptions should then be matched against the expectations of each component
listed as a collaborator, to ensure that expectations are fullled and necessary data items
are available to carry out each process.
Hardware may change. For example, the system may be moved to dierent platforms,
or input devices, such as a pen-based system or a pressure-sensitive touch screen, may
become available. Output technology may change{for example, from a text-based
system to a graphical window-based arrangement.
User expectations may change. Users may expect greater functionality, lower cost,
and easier use. This can occur as a result of competition with similar products.
Better documentation may be requested by users.
A good design recognizes the inevitability of changes and plans an accommodation for
them from the very beginning.
Study Questions
1. What is the key idea driving object-oriented design?
2. How is the idea of responsibility tied to information hiding?
3. What are some of the characteristics of programming in the small?
3.13. CHAPTER SUMMARY 57
4. How does programming in the large dier from programming in the small?
5. Why is information hiding an important aspect of programming in the large?
6. Why should the design of a software system begin with the characterization of behav-
ior?
7. What is a scenario? How does a scenario help the identication of behaviors?
8. What do the three elds of a CRC card represent?
9. What are some of the advantages of using a physical index card to represent a CRC
card?
10. What is the what-who cycle?
11. Why should the user manual be written before actual coding of an application is
begun?
12. What are the most common sources of change in the requirements for an application
over time? How can some of the diculties inherent in change be mitigated?
13. What information is being conveyed by an interaction diagram?
14. Describe in your own words the following aspects of software components
(a) Behavior and state
(b) Instances and Classes
(c) Coupling and Cohesion
(d) Interface and Implementation
15. What are Parnas's principles of information hiding?
16. What are some guidelines to follow in the selection of names for components, argu-
ments, behaviors, and so on?
17. After design, what are the later stages of the software life cycle?
18. What is software maintenance?
58 CHAPTER 3. OBJECT-ORIENTED DESIGN
Exercises
1. Describe the responsibilities of an organization that includes at least six types of
members. Examples of such organizations are a school (students, teachers, principal,
janitor), a business (secretary, president, worker), and a club (president, vice-president,
member). For each member type, describe the responsibilities and the collaborators.
2. Create a scenario for the organization you described in Exercise 1 using an interaction
diagram.
3. For a common game such as solitaire or twenty-one, describe a software system that
will interact with the user as an opposing player. Example components include the
deck and the discard pile.
4. Describe the software system to control an ATM (Automated Teller Machine). Give
interaction diagrams for various scenarios that describe the most common uses of the
machine.
Part II
Understanding Paradigms
59
Chapter 4
A Paradigm
As we noted in Chapter 1, to a medieval scholar a paradigm was an example sentence, one
that could be used as a model or as an aid in learning a language. You are learning a
new language, the programming language Java. This book will introduce Java by means
of many small paradigms, or example code fragments. You as the reader should examine
these programs carefully, paying close attention to those features that are new or dierent in
comparison to earlier programs. Learning to view programs as a form of literature, that is,
learning how to read programs as well as to write them, is a skill well worth an investment
in time.
Our rst paradigm is shown in Figure 4.1. Line numbers have been provided in comments
along the right side. Like all comments, these are mainly intended to help the human reader,
and are not actually part of the program. While exceedingly short and largely lacking in
interesting functionality (the program prints one line of output and exits), this program
nevertheless exhibits characteristics found in all Java programs, and is therefore a good place
to begin our explorations. In the remainder of this chapter we will analyze the features of
this program from several dierent perspectives.
import java.io. // 1
public class FirstProgram f // 2
public static void main ( String ] args ) f // 3
System.out.println( "Your first Java program!") // 4
g // 5
g // 6
Figure 4.1: A simple Java program
61
62 CHAPTER 4. A PARADIGM
A class consists of a class header and a class body. The header is found on line 2, and
provides the name of the class. The keyword class indicates (both to the compiler, and to
you as a program reader) that this is a new class description, and that the text following
the class keyword should be taken to be the class name.
public class FirstProgram f // 2
...
g // 6
The class body begins with the curly brace at the end of line 2, and terminates with
the matching curly brace on line 6. The Java language places few restrictions on the use of
spaces in programs, and the placement of elements such as curly braces relative to the rest
of the line is largely a matter of personal taste, and consequently the subject of a great deal
of heated debate. I personally like to place my starting brace on the same line as the unit it
is grouping, with the closing brace on a line all by itself. I deviate from this only when an
entire statement group can be placed on a line by itself. Others prefer to place both braces
on separate lines, as in the following:
public class FirstProgram
f
public static void main ( String ] args )
f
System.out.println( "Your first Java program!")
g
g
Find a style that seems comfortable to you personally, and use it consistently.
Within the body of a class are found a series of members. A member can be either a
data eld, or a method. The former characterize the internal data being held by an object,
while the latter dene the behaviors an instance of the class can perform.
In our initial program there are no data elds, and only one method. This method
is named main, which must be the name used in describing the rst method that will be
invoked when execution commences.
A method is a function. Like a class, a function consists of two parts a function header
and a function body. All function headers have the same form, which can be described as a
sequence of zero or more modiers, a return type, a name, and a list of arguments. Thus,
a prototypical function has the following form:
modifiers return-type function-name ( arguments ) f
sequence-of-statements
g
64 CHAPTER 4. A PARADIGM
The function header for main is given on line number 3 of our example program. It in-
cludes two modiers, public and static. The rst, as we indicated earlier, will be subsequently
discussed in Section 4.4, while the latter is described in Section 4.5. The return type for
this procedure is void, which we will introduce in Section 4.3. The remaining parts are the
name of the function (main) and the list of arguments to the function. The initial function
for execution always takes a single argument, which is an array of string values. We will
have more to say about Java types, such as the types shown in the argument declaration,
in Section 4.3.
public static void main ( String ] args ) f // 3
...
g // 5
The function body begins with the curly brace on line 3, and ends with the corresponding
curly brace on line 5. Function bodies must always be properly nested within a class
description.
Within a function body are a series of statements, that indicate the actions to be executed
when an instance of the given class is asked to perform the indicated method. In our sample
program, there is one action, which is to print a single line of output. We will discuss this
statement in more detail in the next section.
function println, which takes as argument a text string, and uses the argument to print a
single line of output on a standard output area (often called the output console).
System.out.println( "Your first Java program!") // 4
System is one of many useful objects that already populate the Java universe when a
program begins execution. Another example is Math, which is an object that can perform
many common mathematical operations. We will encounter several other system objects in
later examples.
4.3 Types
In addition to a variety of useful objects, the initial Java world contains the descriptions for
a large collection of useful types that programmer can employ in their own code.
The most basic types are integers and real (or oating-point) values. Integer variables
are declared using the keyword int, as in the following, which both declares a new integer
variable and initializes it with a value.
int newVar = 42
Such variables could be declared either as data elds within a class or as local variables
within a function. Floating point values are declared using either the types oat or double.
Another basic type is boolean. A boolean represents a true or false value. Booleans are
produced by the relational operators (less-than, written <, less-than-or-equal, written <=
and so on) as well as the logical operators (and, written &, or, written |, and the like). The
most common use for boolean values are in the test portion of an if or while statement.
The keyword void is used as a type mainly to describe procedures that do not, in fact,
return any value. We see this in our example program, as the return type for the procedure
main:
public static void main ( String ] args ) f // 3
The argument list for this procedure also illustrates another useful data type provided
by the Java language, the type String. A literal value, for example, has the type String.
String name = "Fred Smith"
Notice that the types int, oat, double and boolean all begin with lower case letters,
while the type String, as well as the majority of other types provided by the Java library,
begin with an upper case letter. The reason for this that the more primitive types (int and
the like) are technically not objects, while all other values are objects. That is, there is no
66 CHAPTER 4. A PARADIGM
class denition that corresponds to int, while there is a class description that denes the
characteristics of the String data type. This is a minor distinction that in rare situations is
important, and one we will return to in a later chapter.
An array in Java is rather dierent from arrays in many other languages. One dierence
is that the array type declaration does not specify the number of elements, or extent, of the
array. We see this in our sample program in line 3:
public static void main ( String ] args ) f // 3
The parameter value for this procedure is named args, and is an array of string values.
The square brackets in the declaration give us the clue that the value is an array, however
they do not specify the size of the array. Instead, methods provided by the class Array can
be used to access information about the array. For example, consider the following program
that is only slightly more complicated than the rst example:
import java.io.
Here the data eld length is being used to determine the number of values held by the
array named args. If the user entered a command line argument, such as the string \Fred",
the output would be \hello Fred".2
If the size of the array args is larger than zero (that is, if there are array elements) then
the subscript operator is used to access the rst element. The set of legal index values for
an array in Java begin with zero, and extend to the value one smaller than the number of
elements in the array.
Finally, this example shows the use of the + operator with a string value. When at least
one argument to the \addition" operator is a String, the other argument is automatically
converted into a string, and the operation of string catenation is performed. The result
will be a new string value in which the left argument is immediately followed by the right
2 Exactly how command line arguments are entered di ers depending upon which platform you are exe-
cuting your Java programs. You should consult a reference manual for further information.
4.4. ACCESS MODIFIERS 67
argument. This feature is often used to format output. For example, suppose x is an integer
variable, we could display the value of x by means of the following statement:
System.out.println("The value of x is " + x)
There are other interesting features of both strings and the array data type in Java that
we will discuss in subsequent chapters.
class BankAccount f
Figure 4.3: A data eld being hidden using the keyword private
There are frequently times when a programmer desires that features of a class, or entire
classes themselves, be \hidden" from other classes. This means that other objects in the
program universe cannot \see" these features, and since they cannot be seen, they cannot
be manipulated.
Data elds are most commonly hidden. An object might want to hold a data value, and
not let the value be seen by other objects. It can do this by using the keyword private. For
example, the class description shown in Figure 4.3 is a simple model of a bank account.
The bank account object holds an \internal" piece of information, which represents the
account balance. Because the variable holding this value is declared private, other objects
in the program universe are not allowed to directly examine or modify the account balance.
There are, however, two functions that are declared as public. These allow deposits or
withdrawals to be made from the bank account object. Thus, other objects in the simulation
can indirectly modify the value of the balance (by performing a deposit or a withdrawal)
even though they cannot directly set the account balance.
Private features (both data elds and functions) can only be accessed within the bounds
of a class description. A third possibility, termed protected, comes into play when inheritance
is used as a technique to create new types of objects out of an existing, older class description.
A protected eld is one that is still inaccessible to other objects, but is accessible within
the bounds of any subclass (or derived class). We will see examples of this in subsequent
chapters.
4.5. LIFETIME MODIFIERS 69
g
70 CHAPTER 4. A PARADIGM
The import statement connects this Java program to the initial Java universe it indi-
cates which portions of the Java run-time system will be used by this program.
A Java program is a sequence of class descriptions.
Each class description consists of a class heading and a class body.
The class heading consists of modiers, the keyword class, and a class name.
A class body is a sequence of members.
A member is either a data member, or a method.
A method is a function, and consists of a function heading and a function body.
A function heading consists of modiers, the function name, and the argument list.
A function body is a sequence of statements.
The modier public indicates attributes (entire classes, or members within a class)
that can be accessed and used by other objects.
The modier static indicates attributes (data members of methods) that are shared
by all instances of a class. Such elds exist even when no instances of the class have
yet been created.
The function main must be declared as both public and static, since it must be visible
to the program loader and must exist even before instances of the class have been
created.
Cross References
Other, more extensive paradigms will be introduced in the remaining chapters in this part
of the book.
The keyword protected, discussed brie y in Section 4.4, becomes important when inher-
itance is used to create new classes. Inheritance will be investigated more fully beginning
in Chapter 8. The class String and related facilities will be explored in Chapter 18.
Study Questions
1. What is the original meaning of the word paradigm?
2. What is the overall structure of a Java program?
3. What are the two major parts of a class description?
4.6. CHAPTER SUMMARY 71
4. What are the two types of members that can be found within a class body?
5. What are the parts of a function header?
6. What operation is performed by System.out.println?
7. What is the type void mainly used for?
8. What does the dierence in case in the initial letter of the types int and String indicate?
9. How in Java does one determine the number of elements held by an array?
10. What is the meaning of the + operator when one of the arguments is a String?
11. What are the three access modier keywords? What does each of them signify?
12. When applied to a data eld, what does the modier static signify?
Exercises
1. Add a member function named display to the class description shown in Figure 4.3.
When invoked, this function should print the current account balance.
2. The looping statement in Java uses the for keyword, and consists of three parts. The
rst part is an initialization statement, which can also be used to declare the loop
variable. The second part is a test for termination the loop will execute as long as
the expression returns true. The nal part is the increment, which is a statement that
is evaluated to update the loop variable.
Consider the following main program. Describe the eect produced by the program
when it is executed with three command line arguments.
public static void main ( String ] args ) f
for (int i = 0 i < args.length i = i + 1)
System.out.println(argsi])
g
Describe the pattern of the output when the program is executed with three command
line arguments.
4. Consider the following main program:
public static void main ( String ] args ) f
String result = ""
for (int i = args.length - 1 i >= 0 i = i - 1)
result = result + " " + argsi]
System.out.println(result)
g
What does this function do? What will be the result printed given the arguments Sam
saw Sarah said Sally ?
5. Another useful function provided by the class String is the substr operation. This takes
an integer argument, and returns the portion of the string that remains following
the given index position. For example, if word is a variable containing the string
\unhappy", then word.substr(2) is the string \happy".
This operation is used in the following program. What will the output be given the
command line argument Sally?
static public void main ( String ] args ) f
String name = args0]
String shortName = name.substr(1)
System.out.println(name + "," + name + ", bo-B" + shortName)
System.out.println("Banana-fana Fo-F" + shortName)
System.out.println("Fee, Fie, mo-M" + shortName)
System.out.println(name + "!")
g
6. By placing the code shown in the previous question inside a loop, write a program
that will take any number of command line arguments, and write one verse of the
name game for each.
Chapter 5
Ball Worlds
In our intuitive description of object-oriented programming presented in Chapter 1, we
described an object-oriented program as a universe of interacting agents. However, in our
rst example Java program, in Chapter 4, we did not actually create any new objects, but
only used the static procedure named main in the program class.
Our second program is slightly more complex in structure, although hardly more com-
plicated in functionality. It places a graphical window on the user's screen, draws a ball
that bounces around the window for a few moments, and then halts.
Our second example program, or paradigm, is constructed out of two classes. The rst
of these appears in Figure 5.1. Again, we have added line numbers for the purposes of
73
74 CHAPTER 5. BALL WORLDS
reference, however these are not part of the actual program. The reader should compare
this program to the example program described in the previous chapter, noting both the
similarities and dierences. Like the previous program, this program imports (on line 1)
information from the Java library. Like the earlier program, execution will begin in the
procedure named main, (lines 3 through 6), which is declared as static, void and public. Like
all main programs, this procedure must take as argument an array of string values, which
are, in this case, being ignored.
However, this program also incorporates a number of new features. These are summa-
rized by the following list, and will be the subject of more detailed discussion in subsequent
sections.
The class denes a number of private internal variable elds, some of which are con-
stant, some of which are initialized but not constant, and some of which are not
initialized. These data elds will be described in detail in Section 5.1.
The main program creates an instance of the class BallWorld. This object is initialized
by means of a constructor. A constructor is a function that automatically ties together
the actions of object creation and object initialization. Constructors will be introduced
in Section 5.2.
The class is declared as an extension of an existing Java class named Frame. This
technique is called inheritance, and is the principal means in object-oriented languages
for constructing new software abstractions that are variations on existing data types.
Inheritance will be introduced in Section 5.3, and will be more extensively studied
beginning in Chapter 8.
The output displayed in a window by this program is created using some of the graph-
ics primitives provided by the Java run-time library. These graphics operators are
explained in Section 5.4.
can be used only within the bounds of the class description in which the declaration appears.
Recall also that the keyword static means that there is one instance of the data eld, shared
by all instances of the class. The modier keyword nal generally means that this is the last
time when an object is changed. It is here applied to a variable declaration we will in later
chapters see how the modier can also be applied to a function denition. When used with
a variable declaration, the declaration must also include an initialization, as shown here.
Variables that are static and nal are used to create symbolic names for constants, as
they are variables that are guaranteed to exist only in one place, and not change values.
Because they cannot be modied, there is less reason to encapsulate a static nal variable by
declaring it private. Thus, such values are often made public, as shown here. The particular
symbolic values being dened in this program represent the height and width of the window
in which the application will eventually produce its output. Symbolic constants are useful
in programs for a number of dierent reasons:
By being dened in only one place, they make it easy to subsequently change, should
circumstances require. For example, changing the height and or width of the window
merely requires editing the le to change the values being used to initialize these
symbolic constants, rather than hunting down all locations in the code where the
quantities are used.
When subsequently used elsewhere in the program, the symbolic name helps document
the purpose of the constant values.
The counter data eld is an integer value, initialized to zero:
private int counter = 0 // 10
Because the eld is declared private we know it can be used only within the bounds of the
class denition. Because it was not declared static, we know that each instance of the class
will hold its own dierent value. Because it was not declared as nal we know that the value
being assigned is simply the initial value the variable will hold, but that it subsequently
could be reassigned. We will see how this variable is used when we discuss the graphical
aspects of the current program.
private Ball aBall // 9
The nal data eld is declared as an instance of class Ball, which is the second class used
in the creation of our example program. A ball is an abstraction that represents a bouncing
ball. It is represented by a colored circle that can move around the display surface. The
class Ball will be described in Section 5.5. How this eld is initialized is described in the
next section.
5.2. CONSTRUCTORS 77
5.2 Constructors
As we noted at the beginning of the chapter, one of the major topics we address in this
chapter is the creation of new objects. This occurs in two places in the program shown in
Figure 5.1. The rst is in the main program, which creates an instance of the class BallWorld.
BallWorld world = new BallWorld (Color.red) // 4
The new operator is always used to create a new instance of a class. In this case, it is
being used to create an instance of BallWorld, which (we will see in the next section) is the
name given to the window in which the program will display its output. The new operator
is followed by a class name, indicating the type of object being created. A parenthesized
list then gives any arguments needed in the initialization of the object.
Object creation and object initialization are intimately tied in concept, and it is impor-
tant that a programming language also bring these concepts together. Without support
from the programming language, two types of errors can easily occur:
An object is created, but it is used before it is ever initialized.
An object is created, and initialized multiple times before it is used.
The language Java uses a concept called a constructor to guarantee that objects are
placed into a proper initial state the moment they are created. A constructor bears a strong
resemblance to a function, however the name of the function matches the name of the class in
which it appears, the function does not specify a return type, and the user will never directly
execute the constructor. However, like a function, a constructor can have arguments, and
the body of the constructor consists of a sequence of statements. In our example program
the constructor occurs in lines 11 to 19:
private BallWorld (Color ballColor) f// constructor for new window 11
// resize our frame, initialize title 12
setSize (FrameWidth, FrameHeight) // 13
setTitle ("Ball World") // 14
In this particular case, the argument represents a color. The class Color is part of the
Java run-time library. The value red is simply a constant (a value declared both as static
and nal) in the class description of Color.
BallWorld world = new BallWorld (Color.red) // 4
The corresponding parameter value in the constructor function is named ballColor (see
line 11). The constructor function must ensure that the instance of the class BallWorld
is properly initialized. As we noted earlier, the BallWorld represents the window in which
the output will be displayed. The rst two statements in the constructor set some of the
attributes for this window namely, the size and the title.
Line 17 of the constructor again uses the new operator to create and initialize a new
object. In this case the object is an instance of the class Ball. Not only will memory
for this object be created by the new statement, but the arguments will be matched by a
corresponding constructor in the class Ball, which will then be invoked to initialize the newly
created ball:
public class Ball f // a generic round colored object that moves
...
public Ball (int x, int y, int r) f // ball with given center and radius
...
g
g
The complete class description for Ball will be shown in Figure 5.2 (page 82). Not all aspects
of a Ball are set by the constructor. The nal two statements in the constructor for BallWorld
set the color of the ball, and set the direction of motion for the ball. These attributes will
be discussed in more detail in Section 5.5.
5.3 Inheritance
The most important feature of this program is the use of inheritance (sometimes also called
extension). As we noted earlier, the ball world is a rectangular window in which the action
of the program (the bouncing ball) is displayed. The code needed to display and manipulate
a window in a modern graphical user interface is exceedingly complex due in part to the
fact that the user can indicate actions such as moving, resizing, or iconifying the window.
As a consequence, recent languages attempt to provide a means of reusing existing code so
that the programmer need only be concerned with those features of the application that
distinguish the program from other window applications.
The programming language Java uses the class Frame to represent a generic window.
By saying that the class BallWorld extends the class Frame, we indicate that our new class,
5.4. THE JAVA GRAPHICS MODEL 79
the ball world, is a type of frame, but a more specialized type with a single purpose. The
class Frame denes code to perform actions such as resizing the window, arranging for the
window to be displayed on the workstation screen, and so on. By extending the class Frame,
our new class inherits this functionality, which means the abilities are made available to the
new class, and do not need to be rewritten anew.
public class BallWorld extends Frame f // 2
By executing the example program the reader can verify that the window exhibits the
functionality we expect of graphical windows the ability to move, resize, and iconify, even
though the program does not explicitly dene any code to support these behaviors. (The
reader might also note some expected behaviors that are not provided. For example, the
handling of menu items and the close or quit box. In a later chapter we will describe how
these features can be provided.)
We can observe the use of inheritance in the variety of methods that are invoked in our
example program, but are not dened by the class BallWorld. These functions are instead
inherited from the parent class Frame. Two examples are the functions setSize and setTitle
invoked in the BallWorld constructor. These functions set the dimensions (in pixels) and
title value for the window, respectively.
private BallWorld (Color ballColor) f// constructor for new window 11
// resize our frame, initialize title 12
setSize (FrameWidth, FrameHeight) // 13
setTitle ("Ball World") // 14
...
g // 19
Another example is the function show, which is invoked in the static procedure main after
the instance of BallWorld has been created. The show function arranges for the window to
appear on the display surface, and then for the surface of the window to be drawn.
public static void main (String ] args) f // 3
BallWorld world = new BallWorld (Color.red) // 4
world.show () // 5
g // 6
the structure of a program, but no application specic details. The overall control, the ow
of execution, is provided by the framework, and therefore does not need to be rewritten for
each new program. Thus, the programmer does not \see" the majority of the program code.
This is illustrated by the actions that occur subsequent to the program issuing the show
method that is inherited from the class Frame. The window in which the action will take
place is created, and the image of the window must be rendered. To do so, the show method
invokes a function named paint, passing as argument a graphics object.
The programmer therefore denes the appearance of the window by providing an im-
plementation of the function paint. The graphics object passed as argument provides the
ability to draw a host of items, such as lines and polygons as well as text. In our example
program we use the paint procedure for two purposes. The only image in the window itself
is the bouncing ball. The image of the ball is produced by invoking the paint method in the
class Ball (see Figure 5.2). The second purpose of the paint method is to provide a simple
means of updating the location for the ball. The ball is moved slightly, checking to see if
the resulting new location is outside the bounds of the window. If so, the direction of the
ball is reversed. Finally, invoking the repaint method (also inherited from Frame) indicates
to the framework that the window should be redrawn, and the cycle continues.1 A counter
is used to prevent the program from running indenitely, invoking the function System.exit
after a certain number of iterations. (Later programs will use other techniques to halt the
program).
public void paint (Graphics g) f // 20
// rst, draw the ball 21
aBall.paint (g) // 22
// then move it slightly 23
aBall.move() // 24
if ((aBall.x() < 0) jj (aBall.x() > FrameWidth)) // 25
aBall.setMotion (-aBall.xMotion(), aBall.yMotion()) // 26
if ((aBall.y() < 0) jj (aBall.y() > FrameHeight)) // 27
aBall.setMotion (aBall.xMotion(), -aBall.yMotion()) // 28
// nally, redraw the frame 29
counter = counter + 1 // 30
if (counter < 2000) repaint() // 31
else System.exit(0) // 32
g // 33
1 Some readers might object that the control of the animation has little to do with the rendering of the
image on the window, and thus does not belong in the paint routine. While there is merit to this argument,
this is also the simplest way to make simple animations. In later chapters we will present more robust ways
to control animations.
5.5. THE CLASS BALL 81
Note that the programmer calls the inherited method named repaint, which in turn will
eventually result in the paint method being invoked. The programmer does not directly call
the paint method for the class.
In later examples we will investigate more of the abilities of the graphics objects provided
by the Java library.
public Ball (int x, int y, int r) f // ball with given center and radius
location = new Rectangle(x-r, y-r, 2r, 2r)
dx = 0 dy = 0 // initially no motion
color = Color.blue
g
in the Java library. These are the ability to set the current color for rendering graphics
(setColor) and to display a painted oval at a given location on the window (llOval).
The reader should try making this change, and observe the result. Note how one window
is bouncing a red ball, and the second is bouncing a yellow ball. This indicates that each
instance of class BallWorld must be maintaining its own Ball value, as a ball cannot be both
red and yellow at the same time.
A second variation illustrates even more dramatically the independence of dierent ob-
jects, even when they derive from the same class. The class MultiBallWorld (Figure 5.3) is
similar to our initial program, only it creates a collection of balls, rather than just a single
ball. Only the lines that have changed are included, and those that are elided are the same
as the earlier program. The new program declares an array of Balls, rather than just a
single ball. Note the syntax used to declare an array. As we noted in the previous chapter,
arrays in Java are dierent from arrays in most other languages. Even though the array is
declared, space is still not set aside for the array elements. Instead, the array itself must be
created (again with a new command):
ballArray = new Ball BallArraySize ]
Note how the size of the array is specied by a symbolic constant, dened earlier in the
program. Even then, however, the array elements cannot be accessed. Instead, each array
element must be individually created, once more using a new operation:
for (int i = 0 i < BallArraySize i++) f
ballArrayi] = new Ball(10, 15, 5)
84 CHAPTER 5. BALL WORLDS
...
private Ball ] ballArray
private static final int BallArraySize = 10
ballArrayi].setColor (ballColor)
ballArrayi].setMotion (3.0+i, 6.0-i)
g
Each ball is created, and initialized with the given color, and set in motion. We have
used the loop index variable to change the direction of motion slightly, so that each ball will
initially move in a dierent direction.
When executed, ten dierent balls will be created. Each ball will maintain its own
location and direction. As each ball is asked to paint it will display its value on the window.
Each ball will then move, independently of all other balls.
The class Rectangle (used in our class Ball) is a library class that represents a rect-
angular region on the two-dimensional window surface. The class provides a large
amount of useful functionality.
Multiple instances of the same class each maintain their own separate data elds.
This was illustrated by creating multiple independent Ball objects, which move inde-
pendently of each other.
Cross References
We will use the Ball class in case studies in Chapters 6, 7, 8 and 21. The topic of inheritance
is simple to explain, but has many subtle points that can easily trap the unwary. We will
example inheritance in detail in Chapters 8 through 11. The AWT will be examined in more
detail in Chapter 13.
Study Questions
1. How would you change the color of the ball in our example application to yellow?
2. How would you change the size of the application window to 500 by 300 pixels?
3. What does the modier keyword nal mean when applied in a data eld declaration?
4. Why do symbolic constants make it easier to read and maintain programs?
5. What two actions are tied together by the concept of a constructor?
6. What types of errors does the use of constructors prevent?
7. What does it mean to say that a new class inherits from an existing class?
8. What methods inherited from class Frame are used in our example application?
9. What methods provided by our example program are invoked by the code inherited
from class Frame?
10. What abstraction does the Java library class Rectangle represent?
11. What are some reasons that data elds should be declared as private or protected, and
access provided only through member functions?
12. In Java, what are the steps involved in creating an array of objects?
5.7. CHAPTER SUMMARY 87
Exercises
1. The function Math.random returns a random oating point value between 0 and 1.0.
Using this function, modify the example program shown in Figure 5.1 so that the ball
will initially move in a random direction.
2. Modify the MultiBallWorld so that the colors of the various balls created are selected
randomly from the values red, blue and yellow. (Hint: call Math.random() and test
the resulting value for various ranges, selecting red if the value is in one range, blue if
it is in another, and so on).
3. Modify the MultiBallWorld so that it will produce balls of dierent radiuses, as well as
dierent colors.
4. Rather than testing whether or not a ball has hit the wall in our main program,
we could have used inheritance to provide a specialized form of Ball. Create a class
BoundedBall that inherits from class Ball. The constructor for this class should provide
the height and width of the window, which should subsequently be maintained as data
elds in the class. Rewrite the move function so that if the ball moves outside the
bounds, it automatically reverses direction. Finally, rewrite the BallWorld class to use
an instance of BoundedBall, rather than an ordinary Ball, and eliminate the bounds
test in the main program.
5. Our Ball abstraction is not as simple as it could have been. Separate the Ball class into
two separate classes. The rst, the new class Ball, knows only a location, its size, and
how to paint itself. The second class, MovableBall, extends the class Ball and adds all
behavior related to motion, such as the data elds dx and dy, the functions setMotion
and move, and so on. Rewrite the MultiBallWorld to use instances of class MovableBall.
88 CHAPTER 5. BALL WORLDS
Chapter 6
A Cannon Game
In this chapter we will examine an implementation of a classic \shooting cannon" game. In
this simple game there is a cannon on the left portion of the users window, and a target
on the right portion. The user can control the angle of elevation for the cannon, and re a
cannon ball. The objective of the game is, of course, to hit the target.
As with all the case studies, our objective is not so much the cannon application itself,
which is only moderately interesting, but the use of a simple program to illustrate a number
of dierent features of the Java language. In particular, we will develop two variations on
this game:
The rst version is the simplest. The user enters the angle of the cannon from the
command argument line, the cannon res once, and the program halts.
In the second version, we improve user interaction, by providing both a slider with
which the angle of the cannon can be changed, and a button to re the cannon. Thus,
89
90 CHAPTER 6. A CANNON GAME
multiple attempts to hit the target can be made during one execution of the program.
// data elds
private int angle = 45
private String message = ""
private CannonBall cannonBall = null
// constructor
public CannonGame (Integer theta) f
(0, 0) (500, 0)
However, most people prefer to think in a coordinate system where the 0,0 location is
the bottom left corner, and y values increase as they move up.
(0, 0) (500, 0)
One way to handle this is to perform a coordinate transformation as the very last opera-
tion before any drawing command. This is the task of the function dy, shown in Figure 6.1.
By subtracting a value from the maximum window size, we can take a value in the more
natural coordinate system, and convert it into a value in the upside down coordinate sys-
tem. An advantage of the function dy is that it is self-inverting applying the function twice
returns the original value. We will use this observation by expressing all our drawing oper-
ations in the zero-centered form, while allowing the ball itself to work in the Java window
coordinates.
6.1. THE SIMPLE CANNON BALL GAME 93
The method to draw the elements in the cannon world is shown in Figure 6.2. Recall
from the previous chapter that drawing is performed by the method paint, which will be
invoked implicitly when the application is shown, and can be requested explicitly by invok-
ing the method repaint. Also recall that drawing commands are provided by the library
class Graphics, an instance of which is supplied to the paint method. The cannon itself
is represented by a rectangle, ten pixels by thirty, with a circular wheel. A bit of simple
math is used to tilt the cannon to the appropriate angle. One complicating factor is that
the application is representing angles in degrees using an integer value, while the sine and
cosine functions in the Math library want a double precision oating point value in radians.
A simple algorithm is used to convert between the two. The target is represented by a red
rectangle. If a cannon ball exists, it is asked to move itself, paint itself at the transformed
location, and if not at the nal target, schedule the picture for another repainting.1 Finally,
the message is printed in the middle of the playing area.
public CannonBall (int sx, int sy, int r, double dx, double dy) f
super (sx, sy, r)
setMotion (dx, dy)
g
1 We remind the reader once more that we are using the paint procedure in this manner merely as a simple
means of animation. Later chapters will demonstrate how to move the control over the animation out of
the paint routine.
94 CHAPTER 6. A CANNON GAME
class CannonGame f
public void paint (Graphics g) f
int x = 20 // location of cannon
int y = 5
double radianAngle = angle Math.PI / 180.0
int lv = (int) (30 Math.sin(radianAngle))
int lh = (int) (30 Math.cos(radianAngle))
int sv = (int) (10 Math.sin(radianAngle + Math.PI/2))
int sh = (int) (10 Math.cos(radianAngle + Math.PI/2))
// draw cannon
g.setColor(Color.green)
g.drawLine(x, dy(y), x+lh, dy(y+lv))
g.drawLine(x+ln, dy(y+lv), x+lh+sh, dy(y+lv+sv))
g.drawLine(x+lh+sh, dy(y+lv+sv), x+sh, dy(y+sv))
g.drawLine(x+sh, dy(y+sv), x, dy(y))
g.drawOval(x-8, dy(y+10), 12, 12)
// draw target
g.setColor(Color.red)
g.fillRoundRect(FrameWidth-100, dy(12), 50, 10, 6, 6)
// draw cannon ball
if (cannonBall != null) f
cannonBall.move()
cannonBall.paint(g)
if (dy(cannonBall.y()) > 0)
repaint()
else f
int targetX = FrameWidth - 100
if ((cannonBall.x() > targetX) &&
(cannonBall.x() < (targetX + 50)))
message = "You Hit It!"
else
message = "Missed!"
cannonBall = null
g
g
// draw message
g.drawString(message, FrameWidth/2, FrameHeight/2)
g
g
We have not yet encountered the pseudo-variable super, shown here in both functions.
When a method overrides (that is, replaces) a similarly named function in the parent class,
a technique must be provided to indicate that the function should invoke the procedure
inherited from the parent class. The function cannot simply be named, as the name in the
child class and the parent class are the same. Thus, for example, if one was to try to invoke
the move function in class Ball by simply executing the function move, the result would be
an innite series of recursive function calls which is not the outcome we wish.
The pseudo-variable super is used to represent the receiver, but viewed as an instance of
the parent class, not the current class. Thus, by invoking super.move(), the procedure move
is asking that the move function from the parent class be executed, and not the version
overridden by the class CannonBall.
Similarly, the use of the name super as a function in a constructor is used to indicate
that the constructor for the parent class should be invoked, using the arguments shown.
Note how the class CannonBall is invoked with a slightly dierent set of arguments than
were used for the class Ball.
The result produced by the message valueOf is a new instance of class Integer, initialized
to the indicated value. The conversion from Integer to int is performed using the message
intValue:
angle = theta.intValue()
interaction by providing the ability to dynamically set the angle of the cannon, and re
several times during one execution.
The conventional way to set a varying quantity, such as the angle of the cannon, is with a
scrollbar. The normal way to indicate that an action should commence, such as the cannon
should be red, is with a button. In our revised game we will incorporate both these items,
placing the button on the top of the screen, and the scroll bar to the right of the playing
area:
The revised game, now named CannonWorld, is shown in Figure 6.3. One feature to
note is that we must now import the Java library java.awt.Event.*, in order to include the
denitions of the Event-handling routines for the Java system. This is in addition to the
java.awt.* library we have been including from the start. Although in code length the amount
of change from the rst version of our program is relatively small, there are a number of
important features that distinguish this program. We will explore these in the following
sections:
public CannonWorld () f
setSize (FrameWidth, FrameHeight)
setTitle ("Cannon Game")
// add the scroll bar and button
Button fire = new Button("fire")
fire.addActionListener(new FireButtonListener())
add ("North", fire)
slider = new Scrollbar(Scrollbar.VERTICAL, angle, 5, 0, 90)
slider.addAdjustmentListener(new ScrollBarListener())
add ("East", slider)
g
g
...
g
Inner classes are allowed to access their surrounding environment. That is, methods
in an inner class can use data elds declared in the surrounding outer class, as well as
invoke methods from the surrounding context. We see this in the method dened in class
ScrollBarListener, which modies both the data elds angle and message.
6.2.2 Interfaces
Both the inner classes created in this example use the keyword implements in their header.
The implementation of an interface is yet another program structuring mechanism, one
that can be understood by comparison to the technique of inheritance we have been using
previously.
An interface in Java is a description of behavior. It is written in a fashion that appears
similar to a class denition, however there are no implementations (function bodies) associ-
ated with methods, and the only data elds permitted must be declared static. An interface
for ActionListener, used in our sample program, might be written as follows:
interface ActionListener f
public void actionPerformed (ActionEvent)
g
The Java library, particularly in those sections that relate to the handling of events (such
as pressing buttons or moving sliders), makes extensive use of interfaces. When a class is
declared as implementing an interface, it is a guarantee (one that is checked by the compiler)
that the class must provide a certain behavior. In this case, an assertion that a class is an
ActionListener means that the class must provide a function named actionPerformed.
The reader should consider carefully the dierence between this and inheritance. Using
inheritance, functions and data elds that are declared in the parent class may be used in
the child class. Thus, the child class inherits the structure of the parent, as well as being
able to mimic the parent behavior. Using an interface, on the other hand, there is no
implementation of the functions in the \parent interface" at all. Instead, the parent simply
denes the names of the functions, which must then be dened in the child class.
Despite the fact that they have no implementation, an interface can be used as a type
name in an argument declared in a function header. The matching parameter value must
6.2. ADDING USER INTERACTION 99
then be an instance of a class that implements the interface. In our example program,
the addActionListener method in class Button expects an argument that implements the
ActionListener interface, and the addAdjustmentListener method in class ScrollBar expects an
argument that implements the AdjustmentListener interface.
When the button is pressed, the message actionPerformed will be passed to the listener.
In this case, this message will be handled by the one method in the class body:
private class FireButtonListener implements ActionListener f
public void actionPerformed (ActionEvent e) f
double radianAngle = angle Math.PI / 180.0
double sinAngle = Math.sin(radianAngle)
double cosAngle = Math.cos(radianAngle)
// create the cannon ball
cannonBall = new CannonBall (
20 + (int) (30 cosAngle), dy(5+(int) (30 sinAngle)),
5, 12 cosAngle, -12 sinAngle)
repaint()
g
g
there is only one event a button can perform that is of any interest, namely the event that
occurs when it is pressed. The action when this occurs is to convert the angle of elevation
for the cannon into radians, create a new cannon ball for ring, and schedule the window
for repainting.
The slider that is used to control the elevation of the cannon is created in a similar
fashion. The constructor for class ScrollBar takes as argument an indication whether the
slidebar is horizontal or vertical, an initial value, and the range of accepted values. The
constructor for our application creates both a new slider and a new listener:
slider = new Scrollbar(Scrollbar.VERTICAL, angle, 5, 0, 90)
slider.addAdjustmentListener(new ScrollBarListener())
The listener must implement the AdjustmentListener interface. When the slider is moved,
the listener is given the message adjustmentValueChanged. Note that, unlike the situation
involving the button, the slide bar must be made available to the listener, so that the current
value of the slide bar can be determined (using the message getValue). It is for this reason
that the slide bar is saved in a data eld, but the button need not be. Once the value of
the slide bar has been determined, the angle and message can be changed, and the window
scheduled for repainting.
private class ScrollBarListener implements AdjustmentListener f
public void adjustmentValueChanged (AdjustmentEvent e) f
angle = slider.getValue()
message = "Angle: " + angle
repaint()
g
g
The graphical component classes Button and Slider, which simplify the creation of
graphical features in a user interface.
The idea of a window layout manager. In our application program we used the default
layout manager, which is an instance of the class BorderLayout.
Note that as our application has become more complex, we have moved closer to the
idea that an object oriented programming is a \community" of agents that interact with
each other to produce the desired behavior. Instances of following categories of objects are
all used in this example program:
The class CannonWorld, which inherits from the class Frame provided by the Java
library.
The class CannonBall, built as an extension of the earlier class Ball developed in Chap-
ter 5.
The class Integer, used here for its ability to translate a number in text into a numeric
quantity.
The graphical component classes Button and ScrollBar, and their listener classes Fire-
ButtonListener and ScrollBarListener, the latter two constructed as inner classes within
our application class.
Instances of the class ActionEvent and AdjustmentEvent, which are created when an
event occurs and carry information to the event listener.
The layout manager, an instance of class BorderLayout.
Study Questions
1. What is the parent class for class CannonGame?
2. In the rst cannon game, how is the angle of the cannon determined?
3. What transformation is performed by the member function dy?
6.4. CROSS REFERENCES 103
Exercises
1. Change the CannonGame so that the message being displayed provides not only the
angle of the cannon, but also the current position of the cannon ball. This value should
change as the cannon ball moves through the air.
2. Modify the class CannonBall so that the ball is colored blue when the ball is moving
upwards, and colored red when the ball is descending. Will this change have any
impact on the rest of the program?
3. Modify the CannonWorld program so that it maintains both a count of the number of
balls red and the number of times the target was hit. Display both of these values
in the message area, as well as the angle of the cannon.
4. On some platforms it may be dicult to halt the cannon application once it has
nished. Add a button labeled \Quit" to the bottom (south) part of the application
window. When pressed, this button should execute the method System.exit(0).
5. Create a simple program that draws a window with a colored ball in the center. Place
a button at the top of the window. When the user presses the button, the color of the
ball will change from red to yellow, or from yellow to green, or from green to red.
6. Create a simple program that draws a window with a colored ball in the center. Place
a slider on the right side of the window. As the user moves the slider, move the ball
up and down the window.
104 CHAPTER 6. A CANNON GAME
7. The constructor for class Color can also take three integer arguments, which represent
the saturation values for red, blue and green. The arguments must be integers between
0 and 255. Create a simple program that draws a window with a colored ball in the
center. Place sliders on three sides. As the user moves the sliders, the saturation
values change for one of these arguments, and the ball changes color.
Chapter 7
The application we will develop simulates a pin ball game. Users can re a ball from the
small square in the right corner of the bottom of the screen. Balls rise, then encounter a
105
106 CHAPTER 7. PIN BALL GAME CONSTRUCTION KIT
variety of dierent types of targets as they fall back to the ground. The user scores points
that depend upon the type and number of targets encountered as the ball descends. The
objective of the game is to score as many points as possible.
As we did with the cannon ball application in Chapter 6, we will develop this program in
a sequence of stages, each stage emphasizing a small number of new programming concepts.
Our intent here is to simply introduce these concepts in the context of a relatively simple
and easy to understand program. Many of the major ideas we introduce will subsequently
be discussed in more detail in later chapters.
public PinBallGame () f
setTitle ("Pin Ball Construction Kit")
setSize (FrameWidth, FrameHeight)
To use a vector, the programmer must rst import the vector class denition from the
standard library:
import java.util.Vector
Note, in particular, that unlike an array it is not necessary to state the type of values that a
Vector will hold. For technical reasons having to do with their internal structure, a vector is
restricted to holding only objects. Thus, for example, one cannot create a vector of integer
values (ints) but one can create a vector of instances of class Integer. This is one reason for
the existence of \wrapper" classes, such as Integer and Float.
Just as an array in Java separates the declaration of the array name and the allocation
of space for the array, the space for a Vector must be similarly created and assigned. In
our example program this occurs in the constructor for the class PinBallGame. Note that
no xed limit is set for the space:
balls = new Vector()
Although we have not seen it yet, a new element will be inserted into the vector by the
method newElement:
balls.addElement (newBall)
The number of values stored in a Vector can be determined by invoking the method size.
for (int i = 0 i < balls.size() i++)
Finally, values are accessed in a vector using the function elementAt. Like an array, the
set of legal index values range from zero to one less than the number of elements in the
collection. The compiler only knows that the accessed element is a value of type object it
must be cast to the appropriate type before it can be used. Here we cast the value into the
type Ball. A run-time check is performed to ensure that the conversion is actually valid:
Ball aBall = (Ball) balls.elementAt (i)
The reader should note how the paint procedure in Figure 7.1 cycles over the collection
of balls, asking each to paint itself.
7.1. FIRST VERSION OF GAME 109
Often a programmer is interested in only one or two of these ve. However, to im-
plement an interface the Java language insists that the programmer provide a denition
for all operations. To simplify such cases, the Java library provides a simple class named
MouseAdapter. The class MouseAdapter implements the MouseListener interface, but uses
an empty procedure for each member function. That is, a MouseAdapter does nothing in
response to any mouse event. However, the programmer can write a new class that inherits
from MouseAdapter, and overrides (or redenes) the procedures of interest.
That is what we do in our example program. An inner class denes a MouseListener by
extending MouseAdapter. An instance of this class is created, and passed as argument to
the method addMouseListener, which is inherited from class Frame.
addMouseListener (new MouseKeeper())
The class MouseKeeper inherits all ve methods dened by MouseAdapter, and redenes
only one. The other four messages will be handled by the methods inherited from the parent
class, which will do nothing.
private class MouseKeeper extends MouseAdapter f
The argument passed to each procedure in the MouseListener interface is a value of type
MouseEvent. The mouse event encodes certain information relating to the type of event
that occurred. If our case, the most important information is the position (or coordinate)
of the mouse at the moment the button was pressed. This information can be derived from
the mouse event object using the methods getX and getY. With these values, a new ball is
created, added to the list of balls, and placed into motion.
The constructor for the thread is given the ball it will be controlling. The actions for
a new thread are those provided by the method named run. In this case the actions of a
pin ball thread will be to move the ball slightly, schedule the window for repainting, then
sleep for 10 milliseconds. The latter action is performed by the method sleep inherited
from class Thread, and is designed to keep the simulation from moving too quickly. We will
subsequently add more work to the loop controlling the life of a PinBall.
When the programmer hits the re button, a new PinBall is created, and a new instance
of the class PinBallThread is created to manage the new ball. The method start, inherited
from class Thread, arranges the thread for execution, and begins processing.
PinBall newBall = new PinBall(x, y)
balls.addElement (newBall)
Thread newThread = new PinBallThread (newBall)
newThread.start()
1 This is not the only way. In Chapter 21 will present an alternative way to create a thread.
112 CHAPTER 7. PIN BALL GAME CONSTRUCTION KIT
Note carefully that to start a thread the programmer should execute the inherited method
start. This, in turn, will eventually execute the method run that the programmer provides.
You should never directly execute the run method as there are a number of actions that
the Thread manager must perform before the actions of a new thread can be initiated.
In this case, the potential source of exception is the fact that a thread could be inter-
rupted while it is sleeping, for example (on some operating systems) by the user entering
the \interrupt" key while the program is running. If such a condition occurs, the sleep state-
ment will be halted before it can complete, and control will transfer to the statement in the
closing block that matches the condition of the interrupt. In this case, we will terminate the
program by invoking the function System.exit. In subsequent programs we will encounter
many more statements that can throw a variety of dierent exceptional conditions.
forms of Ball up to this point. Inheritance is a mechanism for sharing structure a PinBall,
for example, is simply a type of Ball that has the same structure and behavior as a Ball,
adding a few new features (such as being able to run as a separate thread), but maintaining
all the characteristics of the original. There is little in the way of common structure between
a Peg (a target that when hit by a ball scores a number of points and moves the ball in a
new direction) and a Wall (a target that when struck simply re ects the motion of the ball).
What is needed in this case is the ability to state that the two concepts (Peg and Wall,
in this case), share the same behavior, although they have nothing in common in structure.
As we saw in our earlier case study, in Java, this is accomplished by describing the common
behavior as an interface, and declaring that both objects implement the same interface. An
interface for our pin ball targets might be described as follows:
interface PinBallTarget f
public boolean intersects (Ball aBall)
public void moveTo (int x, int y)
public void paint (Graphics g)
public void hitBy (Ball aBall)
g
The interface in this case is declaring that there are four characteristics of interest in
a pin ball target. Each target can tell if it has been hit by a ball that is, if it intersects
the region occupied by a ball. Each target can be moved to a specic point on the playing
surface, each can paint itself, and each provides some response when it has been hit by a
given ball. However, the means by which each of these behaviors will be achieved is left
unspecied, and dierent targets are free to implement the interface in dierent fashions.
An examination of a few dierent targets will help illustrate the point. Our rst type of
target will be a Spring. When hit by a falling ball, a Spring rebounds the ball back into the
playing area, moving it upwards where it hopefully will encounter further targets. A spring
is represented graphically by a small horizontal box, and a series of zig-zag lines, such as
the following:
h hh
hhhh
hh
( (
(( ( ((((
hhhh
hhhh
(h(
( ( ((((
(
The class description for Spring is shown in Figure 7.2. Note how the class Spring must
explicitly state that it implements the PinBallTarget interface, and must provide a specic
meaning for each of the four elements of that interface. In this case, we will state that a
spring intersects a ball if the rectangle surrounding the ball intersects with the rectangle
114 CHAPTER 7. PIN BALL GAME CONSTRUCTION KIT
representing the spring platform. When the spring is hit by the ball, it reverses the vertical
direction of movement for the ball. (In actual fact, it simply guarantees the ball is moving
upward. In rare situations, a spring could possibly be hit from below, although we don't
expect this to be the norm). It then gives the ball a slight boost in the vertical direction.
We have added one slight element of interest to the drawing of the Spring object. We have
provided two dierent graphical representations for the Spring object, selected by an integer
variable named state. Normally, a spring will be held in state 1. When struck, the value of
state is changed to 2, and the next time the spring is redrawn it will present an alternative
image, one in which the spring has been elongated. Drawing this second image changes the
state back to state 1, and a subsequent redraw will display the original. The eect is a
simple form of animation, where a moving spring will appear to stretch momentarily, then
return to a ready state.
A second type of target is a Wall. A Wall (Figure 7.3) is a rectangular region. A
ball intersects a wall if their regions overlap, and if so the ball is simply re ected back, in
eect bouncing o the wall. The bounce is either along the horizontal or vertical direction,
depending upon which side of the wall has been hit.
The advantage of declaring these two dierent structures as both implementing an in-
terface is that an interface name can be used as a type. That is, we can declare a variable
as holding a value of type PinBallTarget. In much the same way that a variable declared as
maintaining a value of type Ball could, in fact, be holding a cannon ball, a pin ball, or any
other value derived from a class that extends the original class Ball, a variable declared as
maintaining a PinBallTarget could, in fact, be holding either a Spring a Wall, or any of the
other varieties of target we will subsequently describe. (This is one aspect of polymorphism,
a topic we will return to in more detail in Chapter 12). We will shortly make use of this
property, by storing all the targets in our game in a single data structure, and testing the
motion of the ball against the location of each target in turn.
Consider now a third type of target, a Hole. A Hole (Figure 7.4) consumes any ball it
comes in contact with, removing the ball from the playing surface. A Hole is represented by
a circular colored image, just like a ball. A Hole has a location on the playing surface, just
like a Ball. In fact, because a hole is structurally similar to a Ball, we can use inheritance to
simplify the implementation of the Hole abstraction.
This illustrates the important dierence between the use of inheritance and the use of
interfaces. The mechanism of inheritance should be used when two (or more) concepts have
a structural relationship. Note that with objects, a structural relationship almost always
implies at least some behavioral relationship. In contrast, the interface mechanism should
be used with two (or more) concepts having a behavioral relationship, but no structural
relationship. We will explore these ideas in more detail in Chapter 8.
Note how a Hole uses both inheritance and an interface. The hole inherits much of its
behavior from the class Ball, including the methods paint and moveTo. The Hole declares
that it implements the PinBallTarget interface, and to do so must provide a method to see
if the hole has intersected with a ball, and the actions to be performed when such an event
occurs. In the case of a hole, the ball is moved clear o the playing surface, and motion of
7.2. ADDING TARGETS: INHERITANCE AND INTERFACES 115
class Spring implements PinBallTarget f
private Rectangle pad
private int state = 1
the ball is halted. Eventually the ball will note that its location exceeds the window size,
and the tread controlling the ball will halt.
A class that inherits from an existing class that implements an interface must of necessity
also implement the interface. We will use this property in dening the next two types of
targets in our pin ball game. A ScorePad is, like a hole, represented by a circular region.
When struck by a ball the score pad has no eect on the ball (the ball simply moves over it),
however the score pad adds a certain amount to the player's score. The particular amount
to add is dened as part of the state for the score object.
Note how the ScorePad class (Figure 7.5) inherits the intersects behavior from class Hole
and the moveTo behavior from class Ball, but overrides the paint and hitBy methods that
would otherwise be inherited from class Hole. The rst now draws a colored circle with the
scoring amount in the middle, while the latter adds the given value to the player score.
Because a ScorePad inherits from class Hole, which implements the PinBallTarget inter-
face, the class ScorePad is also said to implement the interface. This means, for example,
that a ScorePad could be assigned to a variable which was declared to be a PinBallTarget.
public PinBallGame () f
...
score = 0
scoreLabel = new Label ("Score: 0")
add ("North", scoreLabel)
...
g
the text of the label is updated. Note that a ScorePad refers back to the application object
through the variable world.
A feature of the addScore method deserves note. In the revised form of the pin ball
game application class, the method addScore is declared as synchronized. Recall that balls
move independently of each other, and so in theory two balls could roll over two dierent
score pads at much the same time. Two attempts could then be made to update the player
score at once. The resulting actions could easily be unpredictable, and almost certainly
wrong. By declaring the function that updates the score value as synchronized, the Java
language will guarantee that two threads cannot be executing this function at once. If a
thread tries to execute a synchronized method that is currently being executed by another
thread, the second thread is suspended until the rst thread exits the synchronized routine.
Synchronization and threads will be discussed in more detail in Chapter 21.
A Peg is similar to a ScorePad, however it sticks up above the playing surface. Thus,
when a Peg is struck, it re ects the ball o in a new direction, depending upon the angle
of the ball and the point it encounters the peg. (The algorithm used here is not exactly
correct as far as actual physics is concerned, but it does have the advantage of being easy
to compute). The ball is then updated until it no longer intersects with the Peg, thereby
avoiding having the procedure executed multiple times for a single encounter. We have once
again added a simple animation to the class Peg, so that the rst time a peg is redrawn after
120 CHAPTER 7. PIN BALL GAME CONSTRUCTION KIT
it has been struck the circle surrounding the peg will appear to enlarge, and then return to
a normal size.
To create the second version of our game (Figure 7.8), we simply create a Vector of
targets, along with the vector of balls. We initialize the targets in the constructor for the
game, including placing walls on the sides and top of the playing area, to re ect wayward
balls. The user res balls as before, which then proceed to interact with the various targets
as the balls move down the playing surface. Each time a ball moves, a loop is executed to
determine if the new location of the ball has struck a target. If so, the target is informed,
and the location of the ball potentially updated. Finally, the entire screen is repainted,
which involves repainting both the targets and the collection of balls.
Although the second version of pin ball game is certainly more interesting than the rst,
it is still limited by the fact that the layout of the various targets is determined by the
original programmer. To create a dierent layout, the program must be changed, and then
recompiled and executed. In our nal version, we will show how this limitation can be over-
come, by providing a pallet of target elements from which the user can select, dynamically
constructing the pin ball game while the program is executing.
In appearance, our revised game will move the playing area slightly to the right, placing
a sequence of potential target components along a strip in the far left. The user can click
the mouse down in one of these alternatives, then slide the mouse (still down) over into the
playing area. When the user releases the mouse, the selected target element will be installed
into the new location.
122 CHAPTER 7. PIN BALL GAME CONSTRUCTION KIT
public class PinBallGame extends Frame f
public PinBallGame () f
...
// create the targets
targets = new Vector()
targets.addElement(new Wall(30, 50, 2, 350))
targets.addElement(new Wall(30, 50, 360, 2))
targets.addElement(new Wall(390, 50, 2, 380))
targets.addElement(new Hole(100, 100))
targets.addElement(new ScorePad(150, 220, 100, this))
targets.addElement(new Peg(300, 140, 200, this))
targets.addElement(new Spring(120, 350))
g
The eect is produced by overriding both the mousePressed and the mouseReleased meth-
ods inherited from the mouse adapter (Figure 7.9). The two methods communicate with
each other by means of a variable named element. The mousePressed procedure creates a
potential target, determined by the coordinates of the point at which the mouse goes down.
Note that we have not eliminated the original use of the mouseDown procedure, simply
added a new condition. The MouseReleased procedure checks the location of the release,
and if it is in the playing area and if a target item was previously selected (both conditions
must be true), then a new target is added to the game.
Other changes needed to provide our nal version of the pin ball construction kit simply
involve repositioning the left wall, and drawing the images of the selection pallet.
The use of collection classes, in particular the container class Vector. We will discuss
containers in more detail in Chapter 20.
We have expanded the discussion we started in Chapter 6 of the Java listener event
model. In particular, we here describe how to create objects that will listen for mouse
events.
We introduced the concept of a program having multiple threads of execution. In
particular, while the main thread of our program listens for events and paints the
windows, each ball in the simulation is being controlled by an independent routine.
We saw our rst example of a statement that could potentially produce an exception,
and how the Java language permits the programmer to specify what actions to take
when an exception occurs.
We returned to the discussion of interfaces, and contrasted the use of the interface
mechanism with the use of inheritance.
We were introduced to one aspect of the important concept of polymorphism. In
particular, a variable declared as an instance of a parent class (such as Ball) can,
in fact, be holding a value derived from a child class (such as PinBall). Similarly, a
variable declared as an interface value (such as PinBallTarget) can, in fact, hold any
object that implements that interface (such as Peg). This property allows us to create
arrays of dierent objects, such as an array of pin ball targets, and process them in a
uniform fashion.
Cross References
The distinction between interfaces and inheritances is explored in more detail in Chapter 8.
Collection classes will be investigated in detail in Chapter 20. Chapter 13 presents a more
systematic investigation of the services provided by the AWT. Chapter 21 explores the
multithreading features of Java.
Study Questions
1. Why must the variable world be declared static?
2. In what ways is a Vector object similar to an array? In what ways is it dierent?
3. What command is used to determine the number of elements held in a Vector? What
method is used to access the values? What method is used to insert a new value into
the collection?
126 CHAPTER 7. PIN BALL GAME CONSTRUCTION KIT
4. What is the relationship between MouseAdapter and MouseListener? In what ways are
they dierent?
5. What is a thread? What are the tasks assigned to the dierent threads in our appli-
cation?
6. How is a thread started? How the programmer specify the actions a thread should
perform?
7. What is an exception?
8. What action is performed by the function System.exit? Under what circumstances in
our program will this function be called?
9. When should two software components be tied together through the use of inheritance
rather than a common interface?
10. What type of objects can be held by a variable declared using the interface PinBall-
Target?
11. In what ways does the class Hole modify the behavior inherited from class Ball?
12. What is a Label? How is a label attached to a window? What methods are used to
change the text of a label?
13. What does it mean to say that a method is synchronized?
Exercises
1. The class Peg inherits from ScorePad, which in turn inherits from Hole, which in turn
inherits from Ball. For each of these classes, describe all the methods dened in the
class or inherited from parent classes, and for each of the latter indicate in which
parent class the method denition occurs.
2. The pin ball game as presented allows the user an unlimited number of balls. Change
the program to re only a xed number of balls, disallowing ring once the supply
is exhausted. Change the display at the top of the screen so that it will indicate the
number of remaining balls, as well as the score.
3. Add a \reset" button to the bottom of the screen. When pressed, the reset button sets
the score back to zero and, if you implemented the suggestion in previous question,
resets the number of balls in play.
4. On some platforms it may be dicult to halt the PinBall application once it has
nished. Add a button labeled \Quit" to the bottom (south) part of the application
window. When pressed, this button should execute the method System.exit(0).
7.4. CHAPTER SUMMARY 127
5. In the nal program, the items in the pallet are still stored on the targets vector, so
that they will be redrawn, even though they can never be hit by a ball. A better
solution would have been to create a new vector pallet that will hold these items,
redrawing both the pallet and the targets on a repaint. Modify the program in this
fashion.
6. Currently balls do not test to see if they intersect with other balls. We could support
this modication by making PinBall implement the PinBallTarget interface, and adding
balls to the list of targets as well as the list of balls. Describe what changes would
need to be added to modify the program in this fashion.
7. Another change could allow the programmer to reposition items even after they have
been placed in the playing area. If a mouse click occurs on the playing surface over
a target, select the target and move it to the location given by the associated mouse
up. Be careful that you don't end up placing the element in the target vector twice.
8. Create a program that opens a window, listens for mouse clicks, and when a mouse is
released will display the distance (in pixel units) between the location the mouse was
pressed and the location it was released.
9. Write a program that places a red circle in the middle of the window. The circle should
change color to blue when the mouse enters the window, then return to red when the
mouse leaves the window. When the mouse is clicked inside the window, the circle
should change color to green and remain green for 1000 milliseconds, before returning
to blue. Finally, if the mouse is clicked within the bounds of the circle and released
outside the circle, the circle should be moved so as to be centered on the location of
the mouse release.
10. Develop a \paddle" target object. When the user clicks the mouse over the paddle,
the paddle should move back and forth (perhaps only once). If a paddle encounters a
ball, the ball is re ected o the paddle.
128 CHAPTER 7. PIN BALL GAME CONSTRUCTION KIT
Part III
Understanding Inheritance
129
Chapter 8
Understanding Inheritance
The rst step in learning object-oriented programming is understanding the basic philosophy
of organizing a computer program as the interaction of loosely coupled software components.
This idea was the central lesson in the case studies presented in the rst part of the book.
The next step in learning object-oriented programming is organizing classes into a hierar-
chical structure based on the concept of inheritance. By inheritance, we mean the property
that instances of a child class (or subclass) can access both data and behavior (methods)
associated with a parent class (or superclass).
Although in Java the term inheritance is correctly applied only to the creation of new
classes using subclassing (the extends keyword), there are numerous correspondences be-
tween subclassing and the designation that classes satisfy an interface (the implements key-
word). The latter is sometimes termed \inheritance of specication," contrasted with the
\inheritance of code" provided by subclassing. In this chapter we will use the word in a
general fashion, meaning both mechanisms.
While the intuitive meaning of inheritance is clear, and we have used inheritance in many
of our earlier case studies, and the mechanics of using inheritance are relatively simple,
there are nevertheless subtle features involved in the use of inheritance in Java. In this and
subsequent chapters we will explore some of these issues.
The class Object provides minimal functionality guaranteed to be common to all objects.
These include the following methods:
equals (Object obj) Determine whether the argument object is the same as the receiver. This
method is often overridden to change the equality test for dierent classes.
getClass () Returns the name of the class of the receiver as a string.
hashCode () Returns a hash value for this object (see Section 20.7). This method should
also be overridden when the equals method is changed.
8.3. SUBCLASS, SUBTYPE, AND SUBSTITUTABILITY 133
notify() Notify a thread waiting for this object. Used by the threads system, to be described
in Chapter 21.
toString () Converts object into a string value. This method is also often overridden.
wait () Temporarily halt the current thread until it is subsequently notied. Used by the
threads system, to be described in Chapter 21.
Substitutability can also occur through the use of interfaces. An example is the instance
of the class FireButtonListener created in the Cannon-ball game (Chapter 6). The class from
which this value was dened was declared as implementing the interface ActionListener.
Because it implements the ActionListener interface, we can use this value as a parameter to
a function (in this case, addActionListener) that expects an ActionListener value.
class CannonWorld extends Frame f
...
private class FireButtonListener implements ActionListener f
public void actionPerformed (ActionEvent e) f
...
g
g
public CannonWorld () f
...
fire.addActionListener(new FireButtonListener())
g
g
134 CHAPTER 8. UNDERSTANDING INHERITANCE
Because Object is a parent class to all objects, a variable declared using this type can
hold any non-primitive value. The collection class Vector makes use of this property, holding
its values in an array of Object values. Because the array is declared as Object, any object
value can be stored in a Vector.
When new classes are constructed using inheritance from existing classes, the argument
used to justify the validity of substitutability is as follows:
Instances of the subclass must possess all data areas associated with the parent class.
Instances of the subclass must implement, through inheritance at least (if not explicitly
overridden) all functionality dened for the parent class. (They can also dene new
functionality, but that is unimportant for the argument).
Thus, an instance of a child class can mimic the behavior of the parent class and
should be indistinguishable from an instance of the parent class if substituted in a
similar situation.
We will see later in this chapter, when we examine the various ways in which inheritance
can be used, that this is not always a valid argument. Thus, not all subclasses formed using
inheritance are candidates for substitution.
The term subtype is used to describe the relationship between types that explicitly rec-
ognizes the principle of substitution. That is, a type B is considered to be a subtype of A if
two conditions hold. The rst is that an instance of B can legally be assigned to a variable
declared as type A. And the second is that this value can then be used by the variable with
no observable change in behavior.
The term subclass refers merely to the mechanics of constructing a new class using
inheritance, and is easy to recognize from the source description of a program by the presence
of the keyword extends. The subtype relationship is more abstract, and is only loosely
documented directly by the program source. In the majority of situations a subclass is also
a subtype. However, later in this chapter we will discover ways in which subclasses can be
formed that are not subtypes. In addition, subtypes can be formed using interfaces, linking
types that have no inheritance relationship whatsoever. So it is important to understand
both the similarities and the dierences between these two concepts.
It is only the child class that provides an implementation. In such cases the parent class is
sometimes known as an abstract specication class.
There are two dierent mechanisms provided by the Java language to support the idea
of inheritance of specication. The most obvious technique is the use of interfaces. We
have seen examples of this in the way that events are handled by the Java library. For
instance, the characteristics needed for an ActionListener (the object type that responds to
button presses) can be described by a single method, and the implementation of that method
cannot be predicted, since it diers from one application to another. Thus, an interface is
used to describe only the necessary requirements, and no actual behavior is inherited by a
subclass that implements the behavior.
interface ActionListener f
public void actionPerformed (ActionEvent e)
g
When a button is created, an associated listener class is dened. The listener class
provides the specic behavior for the method in the context of the current application.
class CannonWorld extends Frame f
...
// a re button listener implements the action listener interface
private class FireButtonListener implements ActionListener f
public void actionPerformed (ActionEvent e) f
... // action to perform in response to button press
g
g
g
Subclassing for specication can also take place with inheritance of classes formed using
extension. One way to guarantee that a subclass must be constructed is to use the keyword
abstract. A class declared as abstract must be subclassed it is not possible to create an
instance of such a class using the operator new. In addition, individual methods can also be
declared as abstract, and they, too, must be overridden before instances can be constructed.
An example abstract class in the Java library is Number, a parent class for the numeric
wrapper classes Integer, Long, Double and so on. The class description is as follows:
public abstract class Number f
Subclasses of Number must override the methods intValue, longValue, oatValue and
doubleValue. Notice that not all methods in an abstract class must themselves be declared
abstract. Subclasses of Number need not override byteValue or shortValue, as these methods
are provided with an implementation that can be inherited without change.
In general, subclassing for specication can be recognized when the parent class does
not implement actual behavior but merely denes the behavior that must be implemented
in child classes.
Another example of inheritance for construction occurs in the Java Library. There, the
class Stack is constructed using inheritance from the class Vector:
class Stack extends Vector f
As abstractions, the concept of the stack and the concept of a vector have little in
common however from a pragmatic point of view using the Vector class as a parent greatly
simplies the implementation of the stack.
Inheritance for construction is sometimes frowned upon, since it often directly breaks
the principle of substitutability (forming subclasses that are not subtypes). On the other
hand, because it is often a fast and easy route to developing new data abstractions, it
is nevertheless widely used. In Chapter 10 we will discuss the construction of the Stack
abstraction in more detail.
for extension in the Java library is the class Properties, which inherits from class HashTable.
A hash table is a dictionary structure (see Section 20.7). A dictionary stores a collection
of key/value pairs, and allows the user to retrieve the value associated with a given key.
Properties represent information concerning the current execution environment. Examples
of properties are the name of the user running the Java program, the version of the Java
interpreter being used, the name of the operating system under which the Java program
is running, and so on. The class Properties uses the parent class, HashTable, to store and
retrieve the actual property name/value pairs. In addition, the class denes a few methods
specic to the task of managing properties, such as reading or writing properties to or from
a le.
class Properties extends Hashtable f
...
As the functionality of the parent remains available and untouched, subclassing for
extension does not contravene the principle of substitutability and so such subclasses are
always subtypes.
generate an exception.1
class Set extends Vector f
// methods addElement, removeElement, contains
// isEmpty and size
// are all inherited from vector
public int indexOf (Object obj)
f throw new IllegalOperation("indexOf") g
Subclassing for limitation is characterized by the presence of methods that take a pre-
viously permitted operation and makes it illegal. Because subclassing for limitation is an
explicit contravention of the principle of substitutability, and because it builds subclasses
that are not subtypes, it should be avoided whenever possible.
...
g
It is also possible for classes to implement more than one interface, and thus be viewed
as a combination of the two categories. Many examples occur in the input/output sections
of the Java Library. A RandomAccessFile, for example, implements both the DataInput and
DataOutput protocols.
A public feature (data eld or method) can be accessed outside the class denition. A
public class can be accessed outside the package in which it is declared.
A protected feature can be accessed only within the class denition in which it appears,
or within the denition of subclasses.
A private feature can be accessed only within the class denition in which it appears.
We have seen from our rst case studies how both methods and data elds can be
declared as static. A static eld is shared by all instances of a class. A static method can be
invoked even when no instance of the class has been created. Static data elds and methods
are inherited in the same manner as non-static items, except that static methods cannot be
overridden.
Both methods and classes can be declared to be abstract. An abstract class cannot be
instanciated. That is, it is not legal to create an instance of an abstraction class using the
operator new. Such a class can only be used as a parent class, to create a new type of object.
Similarly, an abstract method must be overridden by a subclass.
An alternative modier, nal, is the opposite of abstract. When applied to a class, the
keyword indicates that the class cannot be subclassed. Similarly, when applied to a method,
the keyword indicates that the method cannot be overridden. Thus, the user is guaranteed
that the behavior of the class will be as dened and not modied by a later subclass.
final class newClass extends oldClass f
...
g
We have seen that program constants are generally dened by variables that are both
static and nal:
class CannonGame extends Frame f
...
public static final int FrameWidth = 600
public static final int FrameHeight = 400
...
g
Optimizing compilers can sometimes make use of the fact that a data eld, class or
method is declared as nal, and generate better code than would otherwise be possible.
eort. A programmer may operate both as the developer of new abstractions, and as the
user of a software system created by an earlier programmer. The reader should not confuse
the term user when applied to a programmer with the same term denoting the application
end-user. Similarly, we will often speak of the organization of several objects by describing
a client object, that is requesting the services of a provider. Again, the client in this case
is likely a programmer (or the code being developed by a programmer) making use of the
services developed by an earlier programmer. This should not be confused with the idea of
client/sever computing, as described in Chapter 2.
low-level parts. The Java AWT is an example of a large software framework that relies on
inheritance and substitutability for its operation.
Study Questions
1. Give an intuitive description of inheritance.
2. What does it mean for a method to override an inherited method?
3. What is the name of the root class for all objects in Java?
4. What behavior is provided by the root class in Java?
5. What does it mean to say that child classes are substitutable for parent classes in
Java?
6. What is the dierence between a subclass and a subtype?
7. What are the characteristics of inheritance for specialization?
8. What are the characteristics of inheritance for specication? How does this dier from
inheritance for specialization?
9. What are the characteristics of inheritance for construction? Why is this not generally
considered to be a good use of inheritance?
10. What are the characteristics of inheritance for extension?
11. What are the characteristics of inheritance for limitation? Why is this not generally
considered to be a good use of inheritance?
12. Why would it not make sense for a method in Java to be declared both abstract and
nal ?
13. What are some of the benets of developing classes using inheritance, rather than
developing each new class from scratch?
14. What are some of the costs of using inheritance for software development?
Exercises
1. Suppose you were required to program a project in a non-object oriented language,
such as Pascal or C. How would you simulate the notion of classes and methods? How
would you simulate inheritance? Could you support multiple inheritance? Explain
your answer.
2. We noted that the execution overhead associated with message passing is typically
greater than the overhead associated with a conventional procedure call. How might
you measure these overheads? For a language that supports both classes and proce-
dures (such as C++ or Object Pascal), devise an experiment to determine the actual
performance penalty of message passing.
148 CHAPTER 8. UNDERSTANDING INHERITANCE
3. Consider the three geometric concepts of a line (innite in both directions), a ray
(xed at a point, innite in one direction), and a segment (a portion of a line with
xed end points). How might you structure classes representing these three concepts
in an inheritance hierarchy? Would your answer dier if you concentrated more on
the data representation or more on the behavior? Characterize the type of inheritance
you would use. Explain the reasoning behind your design.
4. Why is the example used in the following explanation not a valid illustration of inher-
itance?
Perhaps the most powerful concept in object-oriented programming sys-
tems is inheritance. Objects can be created by inheriting the properties of
other objects, thus removing the need to write any code whatsoever! Sup-
pose, for example, a program is to process complex numbers consisting of
real and imaginary parts. In a complex number, the real and imaginary
parts behave like real numbers, so all of the operations (+, -, /, *, sqrt,
sin, cos, etc.) can be inherited from the class of objects call REAL, instead
of having to be written in code. This has a major impact on programmer
productivity.
Chapter 9
import java.awt.
// constructor
Card (int sv, int rv) f s = sv r = rv faceup = false g
Note that many of the methods in the Card abstraction have been declared as nal. This
modier serves two important purposes. First, it is a documentation aid, signaling to the
reader of the listing that the methods cannot be overridden by subclasses. Second, in some
situations the Java compiler can optimize the invocation of nal methods, creating faster
code than could be generated for the execution of non-nal methods.
The only other actions a card can perform, besides setting and returning the state of
the card, are to ip over and to display itself. The function ip() is a one-line function
that simply reverses the value held by an instance variable. The drawing function is more
complex, making use of the drawing facilities provided by the Java standard application
library. As we have seen in the earlier case studies, the application library provides a data
type called Graphics that provides a variety of methods for drawing lines and common shapes,
as well as for coloring. An argument of this type is passed to the draw function, as are the
integer coordinates representing the upper left corner of the card.
The card images are simple line drawings, as shown below. Diamonds and hearts are
drawn in red, spades and clubs in black. The hash marks on the back are drawn in yellow.
A portion of the procedure for drawing a playing card is shown in Figure 9.2.
A;@ ;@
3 A
; @; @
JJ A
A
J A
J D A
J D
The most important feature of the playing-card abstraction is the manner in which each
card is responsible for maintaining within itself all card-related information and behaviors.
The card knows both its value and how to draw itself. In this manner the information is
encapsulated and isolated from the application using the playing card. If, for example, one
were to move the program to a new platform using dierent graphics facilities, only the draw
method within the class itself would need to be altered.
The layout of the game is shown in Figure 9.3. A single standard pack of 52 cards is
used. The tableau, or playing table, consists of 28 cards in 7 piles. the rst pile has 1 card,
the second 2, and so on up to 7. The top card of each pile is initially face up all other cards
are face down.
Suit Piles
Discard Deck
Table Piles
card or if the foundation is empty and the card is an ace. Spaces in the tableau that arise
during play can be lled only by kings.
The topmost card of each tableau pile and the topmost card of the discard pile are always
available for play. The only time more than one card is moved is when an entire collection
of face-up cards from a tableau (called a build) is moved to another tableau pile. This can
be done if the bottommost card of the build can be legally played on the topmost card of
the destination. Our initial game will not support the transfer of a build, but we will discuss
this as a possible extension. The topmost card of a tableau is always face up. If a card is
moved from a tableau, leaving a face-down card on the top, the latter card can be turned
face up.
From this short description, it is clear that the game of solitaire mostly involves manip-
ulating piles of cards. Each type of pile has many features in common with the others and
a few aspects unique to the particular type. In the next section, we will investigate in detail
how inheritance can be used in such circumstances to simplify the implementation of the
various card piles by providing a common base for the generic actions and permitting this
base to be redened when necessary.
import java.util.Stack
import java.util.EmptyStackException
CardPile (int xl, int yl) f x = xl y = yl thePile = new Stack() g
card piles, but they dier in details in each case. For example, the function canTake(Card)
asks whether it is legal to place a card on the given pile. A card can be added to a foundation
pile, for instance, only if it is an ace and the foundation is empty, or if the card is of the
same suit as the current topmost card in the pile and has the next-higher value. A card
can be added to a tableau pile, on the other hand, only if the pile is empty and the card is
a king, or if it is of the opposite color as the current topmost card in the pile and has the
next lower value.
The actions of the ve non-nal functions dened in CardPile can be characterized as
follows:
includes {Determines if the coordinates given as arguments are contained within the bound-
aries of the pile. The default action simply tests the topmost card this is overridden
in the tableau piles to test all card values.
canTake {Tells whether a pile can take a specic card. Only the tableau and suit piles can
take cards, so the default action is simply to return no this is overridden in the two
classes mentioned.
addCard {Adds a card to the card list. It is redened in the discard pile class to ensure that
the card is face up.
display {Displays the card deck. The default method merely displays the topmost card of
the pile, but is overridden in the tableau class to display a column of cards. The top
half of each hidden card is displayed. So that the playing surface area is conserved,
only the topmost and bottommost face-up cards are displayed (this permits us to give
denite bounds to the playing surface).
select {Performs an action in response to a mouse click. It is invoked when the user selects
a pile by clicking the mouse in the portion of the playing eld covered by the pile. The
default action does nothing, but is overridden by the table, deck, and discard piles to
play the topmost card, if possible.
The following table illustrates the important benets of inheritance. Given ve oper-
ations and ve classes, there are 25 potential methods we might have had to dene. By
making use of inheritance we need to implement only 13. Furthermore, we are guaranteed
that each pile will respond in the same way to similar requests.
CardPile SuitPile DeckPile DiscardPile TableauPile
includes
canTake
addCard
display
select
9.3. CARD PILES{INHERITANCE IN ACTION 157
class SuitPile extends CardPile f
potentially be negative, the math library function abs is called to make it positive. The
modular division operation is nally used to produce a randomly selected integer value
between 0 and 51.
A subtle feature to note is that we are here performing a random access to the elements
of a Stack. The conventional view of a stack does not allow access to any but the topmost
element. However, in the Java library the Stack container is constructed using inheritance
from the Vector class. Thus, any legal operation on a Vector, such as the method elementAt(),
can also be applied to a Stack.
The method select is invoked when the mouse button is used to select the card deck. If
the deck is empty, it does nothing. Otherwise, the topmost card is removed from the deck
and added to the discard pile.
Java does not have global variables. Where a value is shared between multiple instances
of similar classes, such as the various piles used in our solitaire game, an instance variable
can be declared static. As we will noted in Chapter 4, one copy of a static variable is created
and shared between all instances. In our present program, static variables will be used to
maintain all the various card piles. These will be held in an instance of class Solitaire, which
we will subsequently describe. To access these values we use a complete qualied name,
which includes the name of the class as well as the name of the variable. This is shown in
the select method in Figure 9.6, which refers to the variable Solitare.discardPile to access the
discard pile.
public Solitare () f
window = new SolitareFrame()
init()
window.show()
g
routine is to allocate space for the three arrays (the suit piles, the tableau, and the array
allPiles we will discuss shortly). The new command allocates space for the arrays, but does
not assign any values to the array elements.
The next step is to create the deck pile. Recall that the constructor for this class creates
and shu"es the entire deck of 52 cards. The discard pile is similarly constructed. A loop
then creates and initializes the four suit piles, and a second loop creates and initializes the
tableau piles. Recall that as part of the initialization of the tableau, cards are removed from
the deck and inserted in the tableau pile.
The inner class SolitareFrame, used to manage the application window, is shown in Fig-
ure 9.11. In addition to the cards, a button will be placed at the bottom of the window.
Listeners are created both for mouse events (see Chapter 7) and for the button. When
pressed, the button will invoke the button listener method. This method will reinitialize the
game, then repaint the window. Similarly, when the mouse listener is invoked (in response
to a mouse press) the collection of card piles will be examined, and the appropriate pile will
be displayed.
Study Questions
1. What data values are maintained by class Card? What behaviors can a card perform?
(That is, what methods are implemented by the class Card?)
2. Explain why the suit and rank data elds are declared as private.
3. What is a default constructor? What is a copy constructor?
4. What is an accessor function? What is the advantage of using an accessor function as
opposed to direct access to a data member?
5. What are the 13 dierent card piles that are used in the solitaire game?
6. What does it mean when a function is declared as nal?
7. Describe the ve non-nal functions implemented in class CardPile and overridden in
at least one child class.
8. How does the use of inheritance reduce the amount of code that would otherwise be
necessary to implement the various types of card piles?
9. Explain the dierence between overriding used for replacement and overriding used
for renement. Find another example of each in the methods associated with class
CardPile and its various subclasses.
10. Explain how polymorphism is exhibited in the solitaire game application.
Exercises
1. The solitaire game has been designed to be as simple as possible. A few features are
somewhat annoying, but can be easily remedied with more coding. These include the
following:
(a) The topmost card of a tableau pile should not be moved to another tableau pile
if there is another face-up card below it.
(b) An entire build should not be moved if the bottommost card is a king and there
are no remaining face-down cards.
For each, describe what procedures need to be changed, and give the code for the
updated routine.
EXERCISES 169
2. The following are common variations of klondike. For each, describe which portions
of the solitaire program need to be altered to incorporate the change.
(a) If the user clicks on an empty deck pile, the discard pile is moved (perhaps with
shu"ing) back to the deck pile. Thus, the user can traverse the deck pile multiple
times.
(b) Cards can be moved from the suit pile back into the tableau pile.
(c) Cards are drawn from the deck three at a time and placed on the discard pile in
reverse order. As before, only the topmost card of the discard pile is available
for playing. If fewer than three cards remain in the deck pile, all the remaining
cards (as many as that may be) are moved to the discard pile. (In practice, this
variation is often accompanied by variation 1, permitting multiple passes through
the deck).
(d) The same as variation 3, but any of the three selected cards can be played. (This
requires a slight change to the layout as well as an extensive change to the discard
pile class).
(e) Any royalty card, not simply a king, can be moved onto an empty tableau pile.
3. The game \thumb and pouch" is similar to klondike except that a card may be built
on any card of next-higher rank, of any suit but its own. Thus, a nine of spades can be
played on a ten of clubs, but not on a ten of spades. This variation greatly improves
the chances of winning. (According to Morehead Morehead 1949], the chances of
winning Klondike are 1 in 30, whereas the chances of winning thumb and pouch are
1 in 4.) Describe what portions of the program need to be changed to accommodate
this variation.
4. The game \whitehead" is supercially similar to klondike, in the sense that it uses the
same layout. However, uses dierent rules for when card can be played in the tableau:
(a) A card can be moved onto another faceup card in the tableau only if it has the
same color and is one smaller in rank. For example, a ve of spades can be played
on either a six of clubs or a six of spades, but not on a six of diamonds or a six
of hearts.
(b) A build can only be moved if all cards in the build are of the same suit.
Describe what portions of the program need to be changed to accommodate this
variation.
170 CHAPTER 9. A CASE STUDY: SOLITAIRE
Chapter 10
10.1 Substitutability
The concept of substitutability fundamental to many of the most powerful software devel-
opment techniques in object-oriented programming. You will recall that substitutability
referred to the situations that occurs when a variable declared as one type is used to hold
a value derived from another type.
In Java, substitutability can occur either through the use of classes and inheritance, or
through the use of interfaces. We have seen examples of both in our earlier case studies. In
the Pin Ball game program described in Chapter 7, the variable targets was declared as a
PinBallTarget, but in fact held a variety of dierent types of values that were created using
subclasses of PinBallTarget. In the Solitaire program from Chapter 9, the variable allPiles
was declared as holding a CardPile, but in fact held values that were subclasses of CardPile,
such as DeckPile and DiscardPile:
171
172 CHAPTER 10. MECHANISMS FOR SOFTWARE REUSE
public CannonWorld () f
...
fire.addActionListener(new FireButtonListener())
g
g
We will return to the distinction between inheritance of classes and inheritance of inter-
faces in Section 10.1.2.
relationship.
The is-a relationship holds between two concepts when the rst is a specialized instance
of the second. That is, for all practical purposes the behavior and data associated with the
more specic idea form a subset of the behavior and data associated with the more abstract
idea. For example, all the examples of inheritance we described in the early chapters satisfy
the is-a relationship (a Florist is-a Shopkeeper, a Dog is-a Mammal, a PinBall is-a Ball,
and so on). The relationship derives its name from a simple rule of thumb that tests the
relationship. To determine if concept X is a specialized instance of concept Y, simply form
the English sentence \An X is a Y". If the assertion \sounds correct," that is, if it seems to
match your everyday experience, you may judge that X and Y have the is-a relationship.
The has-a relationship, on the other hand, holds when the second concept is a component
of the rst but the two are not in any sense the same thing, no matter how abstract the
generality. For example, a Car has-a Engine, although clearly it is not the case that a Car
is-a Engine or that an Engine is-a Car. A Car, however, is-a Vehicle, which in turn is-a
MeansOfTransportation. Once again, the test for the has-a relationship is to simply form the
English sentence \An X has a Y", and let common sense tell you whether the result sounds
reasonable.
Most of the time, the distinction is clear-cut. But, sometimes it may be subtle or may
depend on circumstances. In Section 10.2 we will use one such indenite case to illustrate
the two software development techniques that are naturally tied to these two relationships.
On the other hand, the characteristics needed for an ActionListener (the object type that
responds to button presses) can be described by a single method, and the implementation
of that method cannot be predicted, since it diers from one application to another. Thus,
174 CHAPTER 10. MECHANISMS FOR SOFTWARE REUSE
an interface is used to describe only the necessary requirements, and no actual behavior is
inherited by a subclass that implements the behavior.
class CannonWorld extends Frame f
...
// a re button listener implements the action listener interface
private class FireButtonListener implements ActionListener f
public void actionPerformed (ActionEvent e) f
...
g
g
g
In general, the class-subclass relationship should be used whenever a subclass can usefully
inherit either code, data values, or behavior from the parent class. The interface mechanism
should be used when the child class inherits only the specication of the expected behavior,
but no actual code.
...
g
A stack is an abstract data type that allows elements to be added or removed from one
end only. If you think about a stack of dishes sitting on a counter you can get a good
intuition. It is easy to access the topmost dish, or to place a new dish on the top. It is much
more dicult to access any dish other than the topmost dish. In fact, it might be that the
only way to do this is to remove dishes one by one until you reach the dish you want.
The Stack abstractions dened here will be slightly simpler than the version provided by
the Java library. In particular, the library abstraction will throw an exception if an attempt
is made to access or remove an element from an empty stack, a condition we will ignore.
The Java library stack routine names the empty test method empty, instead of the method
isEmpty from class Vector, and nally the Stack abstraction provides a method to search the
stack to determine if it includes a given element. We will not describe this method here.
class Stack f
private Vector theData
public Stack ()
f theData = new Vector() g
the task is already provided by the lastElement operation in the Vector class. Similarly, the
push operation is simply performed by executing an addElement on the vector.
The only operation that is slightly more complex is popping an element from the stack.
This involves using two methods provided by the Vector class, namely obtaining the topmost
element, and removing it from the collection. Notice that to remove the element we must
rst determine its index position, then remove the element by naming its position.
The important point to emphasize is the fact that composition provides a way to leverage
o an existing software component in the creation of a new application. By use of the
existing Vector class, the majority of the dicult work in managing the data values for our
new component have already been addressed.
On the other hand, composition makes no explicit or implicit claims about substitutabil-
ity. When formed in this fashion, the data types Stack and Vector are entirely distinct and
neither can be substituted in situations where the other is required.
intermediate values directly using an index is in this version possible with a stack, but not
permitted in the abstraction created using composition.
does not immediately indicate that the size method can be legally applied to stacks. It
is only by examination of the declaration for the earlier Vector data abstraction that
the entire set of legal operations can be ascertained.
The diculty that occurs when, to understand a class constructed using inheritance,
the programmer must frequently ip back and forth between two (or more) class
declarations has been labeled the \yo-yo" problem Taenzer 1989].
The brevity of data abstractions constructed with inheritance is, in another light, an
advantage. Using inheritance it is not necessary to write any code to access the func-
tionality provided by the class on which the new structure is built. For this reason,
implementations using inheritance are almost always, as in the present case, consid-
erably shorter in code than are implementations constructed with composition, and
they often provide greater functionality. For example, the inheritance implementation
makes available not only the size test for stacks but also the index related operations
(inserting, modifying or removing elements by giving their index locations).
Inheritance does not prevent users from manipulating the new structure using methods
from the parent class, even if these are not appropriate. For example, when we use
inheritance to derive the class Stack from the class Vector, nothing prevents users
from adding new elements to the stack using the inherited method insertElementAt,
and thereby placing elements in locations other than the top of the stack.
In composition the fact that the class Vector is used as the storage mechanism for
our stack is merely an implementation detail. With this technique it would be easy
to reimplement the class to make use of a dierent technique (such as a linked list),
with minimal impact on the users of the Stack abstraction. If users counted on the
fact that a Stack is merely a specialized form of Vector, such changes would be more
dicult to implement.
A component constructed using inheritance has access to elds and methods in the
parent class that have been declared as protected. A component constructed using
composition can only access the public portions of the parent class.
Inheritance may allow us to use the new abstraction as an argument in an existing poly-
morphic function. We will investigate this possibility in more detail in Chapter 12.
Because composition does not imply substitutability, it usually precludes polymor-
phism.
Understandability and maintainability are dicult to judge. Inheritance has the ad-
vantage of brevity of code but not of protocol. Composition code, although longer, is
the only code that another programmer must understand to use the abstraction. A
programmer faced with understanding the inheritance version needs to ask whether
any behavior inherited from the parent class was necessary for proper utilization of
the new class, and would thus have to understand both classes.
180 CHAPTER 10. MECHANISMS FOR SOFTWARE REUSE
Data structures implemented through inheritance tend to have a very small advantage
in execution time over those constructed with composition, since one additional func-
tion call is avoided (although optimization techniques, such as inline functions, can in
theory be used to eliminate much of this overhead).
Of the two possible implementation techniques, can we say which is better in this case?
One answer involves the substitution principle. Ask yourself whether, in an application that
expected to use a Vector data abstraction, it is correct to substitute instead an instance of
class Stack.
The bottom line is that the two techniques are very useful, and an object-oriented
programmer should be familiar with both of them.
ByteArrayInputStream
FileInputStream
PipedInputStream
SequenceInputStream
StringBuerInputStream
stream of byte values, without regard to where the values originate (whether in memory, or
from an external le, or from another process).
However, there is an additional source of variation among input streams. Or rather,
there is additional functionality that is sometimes required when using an input stream.
Furthermore, this functionality is independent of the source for the byte values. One example
is the ability to keep track of line numbers, so that the programmer can determine on which
line of the input the current byte originates. Another useful function is the ability to buer
input, so as to have the possibility of rereading recently referenced bytes once again.
These features are provided by dening a subclass of InputStream, named FilterInput-
Stream. A FilterInputStream is formed as a subclass of InputStream. Thus, using the prin-
ciple of substitutability, a FilterInputStream can be used in places where an InputStream is
expected. On the other hand, a FilterInputStream holds as a component another instance
of InputStream, which is used as the source for data values. Thus, the class InputStream is
both parent and component to FilterInputStream. As requests for values are received, the
FilterInputStream will access the InputStream it holds to get the values it needs, performing
whatever additional actions are required (for example, counting newline characters in order
to keep track of the current line number).
class FilterInputStream extends InputStream f
Because the component held by the FilterInputStream can be any type of InputStream, this
additional functionality can be used to augment and type of InputStream, regardless of where
the byte values originate. This idea of lters (sometimes called wrappers in other object-
oriented literature) can be quite powerful when there are orthogonal sources of variation.
Here the two sources of variation are the source of the input values, and the additional
functionality that may or may not be needed in any particular application.
public Frog () f
behavior = new TadpoleBehavior()
g
older abstraction is created at run-time, and is therefore much weaker, since it can also be
changed at run time. This is sometimes called dynamic composition.
To illustrate, imagine a class that is simulating the behavior of a Frog. Although the
frog interface can be xed throughout its life, the actual actions it performs might be very
dierent when the frog is a tadpole or when it is an adult. One way to model this is to
create a class Frog that uses composition to hold a value of type FrogBehavior (Figure 10.3).
The Frog class is largely a facade, invoking the FrogBehavior object to do the majority of
the real work.
The novel idea is that the variable holding the instance of FrogBehavior can actually
be polymorphic. There might be more than one class that implements the FrogBehavior
specication, such as TadpoleBehavior and AdultFrogBehavior Figure 10.4 illustrates these
classes. The parent class FrogBehavior is here declared abstract, which means that it must
be overridden before any instances can be created. As the frog \grows", it can dynamically
change behavior by reassigning the value behavior to a dierent value (for example, moving
from a TadpoleBehavior to an AdultFrogBehavior). The user of the Frog abstraction need not
know about this change, or even be aware when it occurs.
Dynamic composition is a useful technique if the behavior of an object varies dramatically
according to some internal concept of \state", and the change in state occurs infrequently.
The classes MouseKeeper and PinBallThread are each constructed using inheritance. Each
are then used to create a new component, that will be held as part of the state of the pin
ball game. When used in this fashion, inner classes combine aspects of both inheritance and
composition.
public CannonWorld () f
fire.addActionListener(new FireButtonListener())
...
g
g
Note how the constructor for the class CannonWorld creates an instance of the inner class
FireButtonListener. This is the only instance of this class created. An alternative way to
achieve the same eect would be as follows:
10.6. CHAPTER SUMMARY 185
public CannonWorld () f
fire.addActionListener(new ActionListener()f
public void actionPerformed (ActionEvent e) f
...
g
g)
...
g
g
Notice that in this example the object being created is declared only as being an instance
of ActionListener. However, a class denition follows immediately the ending parenthesis,
indicating that a new and unnamed class is being dened. This class denition would have
exactly the same form as before, ending with a closing curly brace. The parenthesis that
follows this curly brace ends the argument list for the addActionListener call. (The reader
should carefully match curly braces and parenthesis to see how this takes place).
An advantage to the use of the class denition expression in this situation is that it avoids
the need to introduce a new class name (in this case, the inner class name FireButtonListener).
A disadvantage is that such expressions tend to be dicult to read, since the entire class
denition must be wrapped up as an expression, and the close of the expressions occurs
after the end of the class denition.
Study Questions
1. Explain in your own words the principle of substitutability.
2. What is the is-a rule? What is the has-a rule? How are these two rules related to
inheritance and composition?
3. How are interfaces and inheritance related?
4. What are some of the advantages of composition over inheritance?
5. What are some of the advantages of using inheritance that are not available when
composition is used?
6. How does a FilterStream combine inheritance and composition?
Exercises
1. A set is simply an unorganized collection of values. Describe how one could use a
Vector to implement a set. Would inheritance or composition be the more appropriate
mechanism in this case?
2. Modify the Stack data abstractions given in this chapter so that they will throw a
EmptyStackException if an attempt is made to read or remove a value from an empty
stack.
Chapter 11
Implications of Inheritance
The decision to support inheritance and the principle of substitutability in a language sets
o a series of chain reactions that end up impacting almost every aspect of a programming
language. In this chapter, we will illustrate this point by considering some of the implications
of the decision to support in a natural fashion the idea of the polymorphic variable.
The links between inheritance and other language features can be summarized as follows:
In order to make the most eective use of object-oriented techniques, the language
must support the polymorphic variable. A polymorphic variable is a variable that is
declared as one type but actually maintains a value derived from a subtype of the
declared type.
Because at compile time we cannot determine the amount of memory that will be
required to hold the value assigned to a polymorphic variable, all objects must reside
on the heap, rather than on the stack.
Because values are heap resident, the most natural interpretation of assignment and
parameter passing uses reference semantics, rather than copy semantics.
Similarly, the most natural interpretation of equality testing is to test object identity.
However, since often the programmer requires a dierent meaning for equality, two
dierent operators are necessary.
Because values reside on the heap there must be some memory management mecha-
nism. Because assignment is by reference semantics it is dicult for the programmer
to determine when a value is no longer being used. Therefore a garbage collection
system is necessary to recover unused memory.
Each of these points will be more fully developed in the following sections.
187
188 CHAPTER 11. IMPLICATIONS OF INHERITANCE
class Shape f
protected int x
protected int y
0 n: 1
4 r: 1
8 c: 0
0 n: 2
4 r: ?
8 c: 1
0 n: 3
4 r: ?
8 c: 2
The snapshot is taken after the procedure has recursed three times, just as the innermost
procedure is starting to return. The data values for three procedures are shown. In the
innermost procedure the variable r has been assigned the value 1, while the two pending
procedures the value of r has yet to be determined.
There are a number of advantages of stack based memory allocation. All local variables
can be allocated or deallocated as a block, for example, instead of one by one. This block
is commonly called an activation record. Internally, variables can be described by their
numeric oset within the activation record, rather than by their symbolic address. These
numeric osets have been noted in Figure 11.2. Most machines are much more ecient at
dealing with numeric osets than with symbolic names. Notice that each new activation
record creates a new set of osets, so that the oset is always relative to the activation frame
in which a variable appears.
11.2. MEMORY LAYOUT 191
There is one serious disadvantage to stack based allocation. This is that these numeric
osets associated with variables must be determined at compile time, not a run time. In
order to do this, the compiler must know the amount of memory to assign to each variable.
In Figure 11.2, the compiler only knows that variable c can be found at address 8 because
it knows that variable r, which starts at location 4, requires only four bytes.
But, this is exactly the information we do not know for a polymorphic variable. The
storage requirements for a polymorphic variable value are determined when the value is
created at run-time, and can even change during the course of execution. Recall the classes
shown in Figure 11.1, and the memory requirements for the procedure main in the sample
program described earlier. Here the variable form, which is declared as holding a Shape, can
at one moment be holding a Circle, at another a Square, and so on. Both the subclasses
add additional data elds that are not found as part of the parent class. Thus the compiler
cannot know, at compile time, exactly how much memory will be required to hold the
variable form.
In Java, the solution to this problem is that objects are not stored on the activation record
stack, but are instead stored on the heap. A heap is an alternative memory management
system, one that is not tied to procedure entry and exit. Instead, memory is allocated on
the heap when explicitly requested (to create a new object, using the new operator), and is
freed, and recycled, when no longer needed. At run-time, when the memory is requested, the
Java system knows precisely how much memory is required to hold a value. In this fashion
the Java language avoids the need to predict, at compile time, the amount of memory that
will be needed at run-time.
The code generated by the compiler, however, must still be able to accesses variables
through numeric osets, even through the actual heap addresses will not be known until
run time. The solution to this dilemma is to use one level of indirection. Local variables are
represented on the stack as pointer values. The size of a pointer is known at compile time,
and is independent of the size of the object it points to. This pointer eld is lled when an
object is created.
It is said that the programming language Java has no pointers. This is true as far as the
language the programmer sees is concerned. But ironically, this is only possible because all
object values are, in fact, represented internally by pointers.
longer a Circle. For this reason, when we try to execute a member function, such as the
describe function, the code executed will be that associated with class Shape, not the value
associated with class Circle, as in Java. The programmer who uses both C++ and Java
should be aware of this subtle, but nevertheless important dierence.
11.3 Assignment
In Section 11.2 we described why values in Java are most naturally maintained on the
heap, rather than being held in the activation record stack. Because to the compiler the
underlying \value" of a variable is simply a pointer into the heap, the most natural semantics
for assignment simply copy this pointer value. In this manner, the right and left sides of an
assignment statement end up referring to the same object. This is often termed reference
semantics (sometimes also called pointer semantics). The consequences of this interpretation
of assignment are subtle, but are again a key point for Java programmers to remember.
Suppose we create a simple class Box as follows:
public class Box f
private int value
Now imagine that we create a new box, assign it to a variable x, and set the internal
value to 7. We then assign the box held by x to another variable named y. Since both x
and y now hold non-null values of type Box, the programmer might assume that they are
distinct. But, in fact, they are exactly the same box, as can be veried by changing the
value held in the y box and printing the value held by the x box:
public class BoxTest f
static public void main (String ] args) f
g
g
The key observation is that the two variables, although assigned separate locations on
the activation record stack, nevertheless point to the same location on the heap:
x HH
HH
HH
j
a box
*
y
11.3.1 Clones
If the desired eect of an assignment is indeed a copy, then the programmer must indicate
this. One way would be to explicitly create a new value, copying the internal contents from
the existing value:
// create new box with same value as x
Box y = new Box (x.getValue())
There is no general mechanism in Java to copy an arbitrary object, however the base
class Object does provide a protected method named clone() that creates a bit-wise copy of
the receiver, as well as an interface Cloneable that represents objects that can be cloned.
Several methods in the Java library require that arguments be values that are cloneable.
To create a class that is cloneable, the programmer must not only override the clone
method to make it public, but also explicitly indicate that the result satises the Cloneable
interface. The following, for example, shows how to create a cloneable box.
public class Box implements Cloneable f
private int value
The clone method is declared as yielding a result of type Object. This property cannot
be modied when the method is overridden. As a consequence, the result of cloning a value
must be cast to the actual type before it can be assigned to a variable.
public class BoxTest f
static public void main (String ] args) f
As always, there are subtleties here that can trap the unwary programmer. Consider
the object that is being held by our box. Imagine, instead of simply an integer, that it is
something more complex, such as a Shape. Should a clone also clone this value, or just copy
it? A copy results in two distinct boxes, but ones that share a common value. This is called
a shallow copy.
x - a box HH
HH
HH
j
a shape
*
y - a box
Cloning the contents of the box (which must therefore be itself a type that is cloneable)
results in two box values which are not only themselves distinct, but which point to values
that are also distinct. This is termed a deep copy.
x - a box - a shape
y - a box - a shape
Whether a copy should be shallow or deep is something that must be determined by the
programmer when they override the clone interface.
sneeky (x)
A programmer who passes a box to this function, as shown in the main procedure, could
subsequently see the resulting change in a local variable.
A Java programmer should always keep in mind that when a value is passed to a pro-
cedure, a certain degree of control over the variable is lost. In particular, the procedure is
free to invoke any method applicable to the parameter type, which could result in the state
of the variable being changed, as in this example.
When the concept of equality testing is expanded to include objects, the most natural
interpretation becomes less obvious. In Section 11.3 it was argued that because objects are
11.4. EQUALITY TEST 197
The Java compiler does apply type checking rules to the two arguments, which will help
detect many programming errors. For example, although a numeric value can be compared
to another numeric, a numeric cannot be compared to a dierent type of object (for example,
a String). Two object values can be compared if they are the same type, or if the class of
one can be converted into the class of the second. For example, a variable that was declared
to be an instance of class Shape could be compared with a variable of type Circle, since a
Circle would be converted into a Shape. A particular instance of the conversion rule is one
of the more frequent uses of the == operator namely, any object can be compared to the
constant null, since the value null can be assigned to any object type.
Often object identity is not the relation one would like to test, and instead one is in-
terested in object equality. This is provided by the method equals, which is dened by the
base class Object and redened by a number of classes. The following, for example, would
return true using the equals function, but would not be true using the == operator:
String a = "abc"
String b = "abc"
Integer c = new Integer(7)
Integer d = new Integer(3 + 4)
if (a.equals(b))
System.out.println("strings are equal")
if (c.equals(d))
System.out.println("integers are equal")
Because the equals function is dened in class Object, it can be used with any object
type. However, for the same reason, the argument is declared only as type Object. This
198 CHAPTER 11. IMPLICATIONS OF INHERITANCE
means that any two objects can be compared for equality, even if there is no possible way
that for either to be assigned to the other:
if (a.equals(c)) // can never be true
System.out.println("string equal to integer")
The developer of a class is free to override the equals operator and thereby allow com-
parison between objects. Since the argument is an Object it must rst be tested to ensure it
is the correct type. By convention, the value false is returned in cases where the type is not
correct. The following, for example, would be how one could dene a function to compare
two instances of class Circle (Figure 11.1).
class Circle extends Shape f
...
public boolean equals (Object arg) f
if (arg instanceof Circle) f
// convert argument to circle
Circle argc = (Circle) arg
if (radius == argc.radius)
return true // just test radius
g
return false // return false otherwise
g
g
Because the type of the argument is not necessarily the same as the type of the receiver,
unusual situations can occur if the programmer is not careful. For example, suppose we
dened equals in class Shape from Figure 11.1 to test equality of the x and y values, but
forgot to also override the function in class Square. It could happen in this situation that if
we tried to compare a square and a circle, the comparison would be true one way and false
the other.
Square s = new Square(10, 10, 5)
Circle c = new Circle(10, 10, 5)
if (s.equals(c)) // true, since method in shape is used
System.out.println("square equal to circle")
if (c.equals(s)) // false, since method in circle is used
System.out.println("circle equal to square")
When overriding the equals method the programmer should be careful to avoid this
problem, and ensure that the resulting functions are both symmetric (if x is equal to y, then
y is equal to x) and associative (if x is equal to y and y is equal to z , then x is equal to z ).
11.5. GARBAGE COLLECTION 199
A good rule of thumb is to use == when testing numeric quantities, and when testing an
object against the constant null. In all other situations the function equals should be used.
values are being accessed and, more importantly, which heap values are no longer being
referenced by any variable and can therefore be recovered and recycled. This mechanism is
known as the garbage collection system.
The use of a garbage collection system in Java is a compromise. The task of garbage
collection does exact a toll in execution time. However, in return a garbage collection system
greatly simplies the programming process, and eliminates several categories of common
programming errors. For most programs, the improvements in reliability are well worth the
execution time overhead.
Study Questions
1. What is a polymorphic variable?
2. From the language implementation point of view, what are the two major categories
of memory values?
3. How does the idea of a polymorphic variable con ict with the ability to determine
memory requirements at compile time?
4. What does it mean to say that Java uses reference semantics for assignment?
5. What must a programmer do to create a class that supports the Cloneable interface?
6. What is the dierence between a deep and shallow copy?
7. In what way is passing a parameter similar to an assignment?
8. What is the dierence between the == operator and the equals() method?
9. What task is being performed by the garbage collection system in the Java run-time
library?
10. What are some advantages of a language that uses garbage collection? What are some
disadvantages?
11.6. CHAPTER SUMMARY 201
Exercises
1. Rewrite the Shape classes shown in Figure 11.1 so that they support the cloneable
interface.
2. Rewrite the class Box so that it holds values that are cloneable, and when cloned it
created a deep copy.
202 CHAPTER 11. IMPLICATIONS OF INHERITANCE
Part IV
Understanding Polymorphism
203
Chapter 12
Polymorphism
The term polymorphic has Greek roots and means roughly \many forms." (poly = many,
morphos = form. Morphos is related to the Greek god Morphus, who could appear to
sleeping individuals in any form he wished and hence was truly polymorphic.) In biology, a
polymorphic species is one, such as Homo Sapiens, that is characterized by the occurrence
of dierent forms or color types in individual organisms or among organisms. In chemistry,
a polymorphic compound is one that can crystallize in at least two distinct forms, such as
carbon, which can crystallize both as graphite and as diamond.
205
206 CHAPTER 12. POLYMORPHISM
12.3 Overloading
We say a function name is overloaded if there are two or more function bodies associated
with it. Note that overloading is a necessary part of overriding, which we and will describe
12.3. OVERLOADING 207
in the next section, but the two terms are not identical and overloading can occur without
overriding.
In overloading, it is the function name that is polymorphic{it has many forms. Another
way to think of overloading and polymorphism is that there is a single abstract function
that takes various types of arguments the actual code executed depends on the arguments
given. The fact that the compiler can often determine the correct function at compile time
(in a strongly typed language), and can therefore generate only a single code sequence are
simply optimizations.
All object-oriented languages permit the occurrence of methods with similar names in
unrelated classes. In this case the resolution of overloaded names is determined by obser-
vation of the class of the receiver for the message. Nevertheless, this does not mean that
functions or methods can be written that take arbitrary arguments. The statically typed
nature of Java still requires specic declarations of all names.
There are six dierent constructor functions in this class, all with the same name. The
compiler decides which function to execute based on the number and type of arguments
used with the function call.
Overloading is a necessary prerequisite to the other forms of polymorphism we will
consider: overriding, deferred methods, and pure polymorphism. It is also often useful in
reducing the \conceptual space," that is, in reducing the amount of information that the
programmer must remember. Often, this reduction in programmer-memory space is just as
signicant as the reduction in computer-memory space permitted by code sharing.
12.4 Overriding
In Chapter 8 we described the mechanics of overriding, so it is not necessary to repeat that
discussion here. Recall, however, the following essential elements of the technique. In one
class (typically an abstract superclass), there is a general method dened for a particular
210 CHAPTER 12. POLYMORPHISM
message that is inherited and used by subclasses. In at least one subclass, however, a method
with the same name is dened, that hides access to the general method for instances of this
class (or, in the case of renement, subsumes access to the general method). We say the
second method overrides the rst.
Overriding is often transparent to the user of a class, and, as with overloading, frequently
the two functions are thought of semantically as a single entity.
Constructors, on the other hand, always use renement semantics. A constructor for a
child class will always invoke the constructor for the parent class. This invocation will take
place before the code for the constructor is executed. If the constructor for the parent class
requires arguments, the pseudo-variable super is used as if it were a function:
class DeckPile extends CardPile f
When used in this fashion, the call on the parent constructor must be the rst statement
executed. If no call on super is make explicitly and there exist two or more overloaded
forms of the constructor, the constructor with no arguments (sometimes called the default
constructor) will be the form used.
that matches the message selector. Suppose the programmer wishes to dene a polymorphic
variable of class Shape that will, at various times, contain instances of each of the dierent
shapes. Such an assignment is possible, according to our rule of substitutability neverthe-
less, the compiler will permit the message draw to be used with this variable only if it can
ensure that the message will be understood by any value that may be associated with the
variable. Assigning a method to the class Shape eectively provides this assurance, even
when the method in class Shape is never actually executed.
2 The extreme cases may be easy to recognize, but discovering the line that separates overloading from
polymorphism can be di cult. In both Java and ML a programmer can dene a number of functions, each
having the same name, but which take di erent arguments. Is it overloading in Java because the various
functions sharing the same name are not dened in one location, whereas in ML-style polymorphism they
must all be bundled together under a single heading?
12.7. EFFICIENCY AND POLYMORPHISM 213
The method intValue is abstract and deferred{each type of number must provide their
own implementation of this method. The method byteValue, on the other hand, is not
overridden. It is a purely polymorphic algorithm. Regardless of whether the receiver is an
integer, a double precision oating point value, or some other type of number, this is the
only denition that will be found. For all of these dierent types, when byteValue is invoked
this will be the algorithm that is executed.
The important dening characteristic of pure polymorphism, as opposed to overloading
and overriding, is that there is one function with the given name, used with a variety of
dierent arguments. Almost always, as in this case, the body of such an algorithm will make
use of other forms of polymorphism, such as the invocation of abstract functions shown here.
Study Questions
1. What does the term polymorphic mean in common usage?
2. What is a polymorphic variable?
3. How is the characterization of polymorphic variables dierent in dynamically typed
languages than in staticly typed languages?
4. What does it mean to say that a function name is overloaded?
5. What does it mean to say that a value has been coerced to a dierent type?
6. What is parameteric overloading?
7. What is overriding, and how is it dierent from overloading?
8. What is the dierence between overriding using replacement, and overriding using
renement?
9. What is the default semantics for overriding for methods? For constructors?
10. What is an abstract method?
11. How is an abstract method denoted?
12. What characterizes pure polymorphism?
13. Why should a programmer not be overly concerned with the loss of eciency due to
the use of polymorphic programming techniques?
Exercises
1. Describe the various types of polymorphism found in the Pinball game application
presented in Chapter 7.
2. Describe the various types of polymorphism found in the Solitare application presented
in Chapter 9.
Chapter 13
The AWT
The AWT, the Abstract Windowing Toolkit, is the portion of the Java run-time library
that is involved with creating, displaying, and facilitating user interaction with window
objects. The AWT is an example of a software framework. A framework is a way of
structuring generic solutions to a common problem, using polymorphism as a means of
creating specialized solutions for each new application. Thus, examining the AWT will
illustrate how polymorphism is used in a powerful and dynamic fashion in the language
Java.
Object
Component
A Component is something that can be displayed on a two dimensional screen and with
which the user can interact. Attributes of a component include a size, a location, foreground
and background colors, whether or not it is visible, and a set of listeners for events. Methods
dened in class Component include the following:
enable(), disable() enable/disable a component
setLocation(int,int), getLocation() set and get component location
setSize(int,int), getSize() set and get size of component
setVisible(boolean) show or hide the component
setForeground(Color), getForegound() set and get foreground colors
setBackground(Color), getBackground() set and get background colors
setFont(Font), getFont() set and get font
repaint(Graphics) schedule component for repainting
paint(Graphics) repaint component appearance
addMouseListener(MouseListener) add a mouse listener for component
addKeyListener(KeyListener) add a keypress listener for component
Besides frames, other types of components include buttons, checkboxes, scroll bars, and
text areas.
A Container is a type of component that can nest other components within it. A container
is the way that complex graphical interfaces are constructed. A Frame is a type of Container,
so it can hold objects such as buttons and scroll bars. When more complicated interfaces
are necessary, a Panel (another type of container) can be constructed, which might hold, for
example, a collection of buttons. Since this Panel is both a Container and a Component, it can
be inserted into the Frame. A container maintains a list of the components it manipulates,
as well as a layout manager to determine how the components should be displayed. Methods
dened in class Container include the following:
13.1. THE AWT CLASS HIERARCHY 217
setLayout (LayoutManager) set layout manager for display
add (Component), remove (Component) add or remove component from display
A Window is a type of Container. A window is a two-dimensional drawing surface that
can be displayed on an output device. A window can be stacked on top of other windows,
and moved either to the front or back of the visible windows. Methods dened in class
Window include the following:
show() make the window visible
toFront() move window to front
toBack() move window to back
Finally, a Frame is a type of window with a title bar, a menu bar, a border, a cursor,
and other properties. Methods dened in class Frame include the following:
setTitle(String), getTitle() set or get title
setCursor(int) set cursor
setResizable() make the window resizable
setMenuBar(MenuBar) set menu bar for window
If we consider a typical application, such as the CannonWorld application of Chapter 6,
we see that it uses methods from a number of dierent levels of the class hierarchy:
setTitle(String) inherited from class Frame
setSize(int, int) inherited from class Component
show() inherited from class Window
repaint() inherited from class Component
paint() inherited from Component, overridden in application class
The power of the AWT, indeed the power of any framework, comes through the use of
a polymorphic variable. When the method show in class Window is invoked, it calls the
method setVisible in class Component. This method calls repaint, which in turn calls paint.
The code for the algorithm used by setVisible and repaint resides in class Component. When
it is being executed, the framework \thinks" that it is dealing only with an instance of
Component. However, in actuality the method paint that is being executed is the version
that has been overridden in the application class. Thus, there are two views of the function
being executed, as described in Figure 13.2.
The code in the parent classes (Component, Container, Window and Frame) can all be
written without reference to any particular application. Thus, this code can be easily carried
from one application to the next. To specialize the design framework to a new application
it is only necessary to override the appropriate methods (such as paint or event listeners) to
dene application specic behavior. Thus, the combination of inheritance, overriding, and
polymorphism permits design and software reuse on a grand scale.
218 CHAPTER 13. THE AWT
class Container extends Object f sm AWT
void paint (Graphics g) ...
g
view
@
@
programmers
ms @
class CannonWorld extends Frame f
view void paint (Graphics g) ...
g
Figure 13.2: Two views of a component
holds
Container LayoutManager
inherits implements
Application GridLayout
methods in the application class that override methods in the parent class (paint(), for ex-
ample). The fact that composition is used to link the container with the layout manager
makes the link between these two items very dynamic{the programmer can easily change
the type of layout manager being employed by a container. This dynamic behavior is very
dicult to achieve using inheritance alone, since the inheritance relationship between a par-
ent and child is established at compile time. Finally, the fact that LayoutManager is simply
and interface, and that various dierent classes of objects implement this interface, means
that the programmer is free to develop alternative layout managers using a wide variety of
techniques. (This freedom would be much more constrained if, for example, LayoutManager
was a class which alternative layout managers needed to extend).
The next most common type of layout is the GridLayout. The manager for this layout
creates rectangular array of components, each occupying the same size portion of the screen.
220 CHAPTER 13. THE AWT
Using arguments with the constructor, the programmer species the number of rows and
the number of columns in the grid. Two additional integer arguments can be used to specify
a horizontal and vertical space between the components. An example of a panel formatted
using a GridLayout is shown in Figure 13.8. The section of code for that application that
creates the layout manager is as follows:
Panel p = new Panel()
// make a 4 by 4 grid,
// with 3 pixels between each element
p.setLayout (new GridLayout(4, 4, 3, 3))
A FlowLayout manager places components in rows left to right, top to bottom. Unlike the
layout created by a GridLayout manager, the components managed by a ow layout manager
need not all have the same size. When a component cannot be completely placed on a row
without truncation, a new row is created. The ow manager is the default layout manager
for the class Panel (as opposed to Frame, where the default manager is a BorderLayout).
A CardLayout manager stacks components vertically. Only one component is visible at
any one time. The components managed by a card layout manager can be named (using
the string argument to the add method). Subsequently, a named component can be made
the visible component. This is one of the few instances where the programmer would have
direct interaction with the layout manager.
CardLayout lm = new CardLayout()
Panel p = new Panel (lm)
p.add ("One", new Label ("Number One"))
13.3. USER INTERFACE COMPONENTS 221
The most general type of layout manager is the GridBagLayout manager. This manager
allows the programmer to create a non-uniform grid of squares, and place components in
various positions within each square. However, the details of the use of this manager are
complex, and will not be described here.
13.3.1 Labels
The simplest type of user interface component is a Label. A label has only the text it will
display. It will display as much of the text as it can in the area it is given.
Label lab = new Label("score: 0 to 0")
add ("South", lab) // put label on top of window
Unlike other components, a label does not respond to any type of event, such as a mouse
click or a key press. However, the text of the label can be changed using the function
setText(String), and the current text of a label can be retrieved using getText().
13.3.2 Button
A Button is a labeled component, usually represented by a rounded box, that can respond
to user interaction. As we have seen in earlier programs, interaction with a button is
achieved by attaching an ActionListener object to the button. The ActionListener object is
then notied when the button is pressed.
Button b = new Button ("do it!")
222 CHAPTER 13. THE AWT
A useful trick is to combine the button object and the button listener in one new class.
This new class both subclasses from the original Button class and implements the ActionLis-
tener interface. For example, in the case study that is presented in Section 13.5, we create
a set of buttons for dierent colors. Each button holds a color value, and when pressed
invokes a method using the color as argument. This class is written as follows:
private class ColorButton extends Button implements ActionListener f
private Color ourColor
Notice how the object registers itself as a listener for button actions. The pseudo-variable
this is used when an object needs to denote itself. When pressed, the button will invoke the
method actionPerformed, which will then invoke the procedure setFromColor that is found in
the surrounding class.
We can even take this trick one step further, and dene a generic ButtonAdaptor class
that is both a button and a listener. The actions of the listener will be encapsulated by an
abstract method, which must be implemented by a subclass:
abstract class ButtonAdaptor extends Button implements ActionListener f
public ButtonAdaptor (String name) f
super (name)
addActionListener (this)
13.3. USER INTERFACE COMPONENTS 223
To create a button using this abstraction, the programmer must subclass and override
the method run. This, however, can be done easily using a class denition expression. The
following, for example, creates a button that when pressed will halt the application.
Panel p = new Panel()
13.3.3 Canvas
A Canvas is a simple type of component, having only a size and the ability to be a target
for drawing operations. Among other uses, the class Canvas is often subclassed to form
new types of components. We will illustrate one use of a Canvas when we discuss the class
ScrollPane (Section 13.4.1).
The text in a text component can be set or accessed by the program using the functions
setText(String) and getText(). Additional text can be added to the text area using the
method append(String). Various other methods can be used to indicate whether or not the
text is editable, and to select a subportion of the text. A TextListener can be attached to a
text component. The listener must implement the TextListener interface:
interface TextListener extends EventListener f
public void textValueChanged (TextEvent e)
13.3. USER INTERFACE COMPONENTS 225
13.3.6 Checkbox
A Checkbox is a component that maintains and displays a labeled binary state. The state
described by a check box can be either on or o. The current state of the Checkbox can be
set or tested by the programmer. A Checkbox is typically used in an application to indicate
a binary (on/o, yes/no) choice.
Both the label and the state of the Checkbox can be set by the programmer, using
the functions getLabel, setLabel, getState and setState. Changing the state of a check box
creates an ItemEvent, that is registered with any ItemListener objects. The following simple
application illustrates the use of these methods:
class CheckTest extends Frame f
private Checkbox cb = new Checkbox ("the checkbox is off")
public CheckTest () f
setTitle("Check box example") setSize(300, 70)
cb.addItemListener (new CheckListener())
add ("Center", cb)
g
A Checkbox group should be used when the number of alternatives is small. A choice
or a list should be used if the number of alternatives is ve or more. A choice takes up less
space in the display, but makes it more dicult to view all the alternatives.
To create a Choice or a List object, the programmer species each alternative using the
method addItem. An ItemListener can be attached to the object. When a selection is made,
the listener will be informed using the method itemStateChanged. The text of the selected
item can be recovered using the method getSelectedItem.
To structure a group of check boxes as a group, the programmer rst creates a Check-
boxGroup. This value is then passed as argument to each created check box, along with a
third argument that indicates whether or not the check box should be initially active. If
more than one button is made active (as here) only the last button will remain active. The
current check box can be accessed using the method getSelectedCheckbox.
As a check box group is constructed out of several components, it is almost always laid
out on a Panel. The Panel is then placed as a single element in the original layout. This is
shown in Figure 13.5. Here a ve by two grid is used as layout for the ten check boxes.
13.3. USER INTERFACE COMPONENTS 227
public ChoiceTest () f
setTitle ("selection example ")
setSize (300, 300)
for (int i = 0 i < 10 i++) f
theChoice.addItem (choicesi])
theList.addItem (choicesi]) g
theChoice.addItemListener (theListener)
theList.addItemListener (theListener)
add ("West", makeCheckBoxes()) add ("North", theChoice)
add ("East", theList) add ("South", display)
g
13.4 Panels
A Panel is a Container that acts like a Component. A panel represents a rectangular region
of the display. Each panel holds its own layout manager, which can dier from the layout
manager for the application display. Items can be inserted into the panel. The panel, as a
single unit, it then inserted into the application display.
The use of a panel is illustrated by the application described in Figure 13.5. Here the
method makeCheckBoxes creates a panel to hold the ten check boxes that make up the check
box group. This panel is structured, using a GridLayout as a ve by two element matrix.
This group of ten components can then be treated as a single element, and is placed on the
left side of the application layout.
More examples of the use of panels will be provided by the application that will be
described in the next section. A snapshot of the window for this application is shown in
Figure 13.8. The three scroll bars on the left are placed on a Panel. This panel is laid out
using a BorderLayout manager. The procedure to create and return this panel is described
as follows:
private Panel makeScrollBars () f
Panel p = new Panel()
p.setLayout (new BorderLayout())
p.add("West", redBar)
p.add("Center", greenBar)
p.add("East", blueBar)
return p
g
The panel returned as the result of this method is then placed on the left side of the
application window.
13.4.1 ScrollPane
A ScrollPane is in many ways similar to a Panel. Like a panel, it can hold another component.
However, a ScrollPane can only hold one component, and it does not have a layout manager.
If the size of the component being held is larger than the size of the ScrollPane itself, scroll
bars will be automatically generated to allow the user to move the underlying component.
We illustrate the use of a ScrollPane with a simple test program, shown in Figure 13.6.
The application window in this program will be set to 300 by 300 pixels, but a scroll pane
is created that holds a canvas that has been sized to 1000 by 1000 pixels. Scroll bars
will therefore be added automatically that allow the user to see portions of the underlying
canvas. As mouse events are detected by the canvas, points will be added to a Polygon. To
paint the application window, the canvas simply draws the polygon values.
13.4. PANELS 229
public BigCanvas () f
setSize (300, 300)
setTitle ("Scroll Pane Test")
// make canvas larger than window
cv.setSize (1000, 1000)
cv.addMouseListener (new MouseKeeper())
// make scroll pane to manage canvas
ScrollPane sp = new ScrollPane()
sp.add(cv)
add("Center", sp)
g
public ColorTest () f
setTitle ("color test") setSize (400, 600)
add("North", colorDescription)
add("East", makeColorButtons())
add("Center", colorField)
add("West", makeScrollBars())
setFromColor (current)
g
buttons and background for the scroll bar. You will recall that when adjusted, the scroll
bar will invoke its listener, which will execute the method adjustmentValueChanged. This
method will then execute the procedure setFromBar.
A method makeScrollBars, used to create the panel that holds the three scroll bars, was
described earlier in Section 13.4.
The idea of combining inheritance and implementation of an interface is used in creating
the buttons that represent the thirteen predened colors. Each instance of ColorButton,
shown earlier in Section 13.3.2, both extends the class Button and implements the Action-
Listener interface. When the button is pressed, the method setFromColor will be used to set
the color of the middle panel using the color stored in the button.
The class BrightenButton is slightly more complex. An index value is stored with the
button. This value indicates whether the button represents the \brighten" button or the
\darken" button. When pressed, the current color is modied by the appropriate method,
and the new value used to set the current color.
private class BrightenButton extends Button implements ActionListener f
private int index
public BrightenButton (int i) f
super ( i == 0 ? "brighter" : "darker")
index = i
addActionListener(this)
g
if (index == 0)
setFromColor (current.brighter())
else
setFromColor (current.darker())
g
g
A panel is used to hold the sixteen button values. In this case the layout is described
by a 4 by 4 grid pattern. Thirteen represent the predened buttons. Two represent the
brighter and darker buttons. And the nal creates a button that when pressed exits the
application.
private Panel makeColorButtons () f
Panel p = new Panel()
p.setLayout (new GridLayout(4,4,3,3))
p.add (new ColorButton(Color.black, "black"))
p.add (new ColorButton(Color.blue, "blue"))
p.add (new ColorButton(Color.cyan, "cyan"))
p.add (new ColorButton(Color.darkGray, "darkGray"))
p.add (new ColorButton(Color.gray, "gray"))
p.add (new ColorButton(Color.green, "green"))
p.add (new ColorButton(Color.lightGray, "lightGray"))
p.add (new ColorButton(Color.magenta, "magenta"))
p.add (new ColorButton(Color.orange, "orange"))
p.add (new ColorButton(Color.pink, "pink"))
p.add (new ColorButton(Color.red, "red"))
p.add (new ColorButton(Color.white, "white"))
p.add (new ColorButton(Color.yellow, "yellow"))
p.add (new BrightenButton(0))
p.add (new BrightenButton(1))
p.add (new ButtonAdaptor("Quit")f
public void run() f System.exit(0) gg)
return p
g
13.6 Dialogs
A Dialog is a special purpose window that is displayed for a short period of time during
the course of execution, and thereafter disappears. Dialogs are often used to notify the
user of certain events, or to ask simple questions. A dialog must always be attached to an
234 CHAPTER 13. THE AWT
instance of Frame, and disappears automatically when the frame is hidden (such as when
the application halts).
Dialog windows can be modal or nonmodal. A modal dialog must be handled, and pre-
vents the user from performing any further action until the dialog is dismissed. A nonmodal
dialog, sometimes called a modeless dialog, can be ignored by the user. The processing of
actions for a nonmodal dialog is often placed in a separate Thread (See Chapter 21), so that
the actions produced by the dialog will not disrupt the continuing processing of the rest of
the application. Whether or not a dialog is modal is determined when the dialog is created.
The two arguments used in the constructor for the dialog are the application Frame and a
boolean value that is true if the dialog is modal.
// create a new nonmodal dialog in current application
Dialog = new Dialog (this, false)
Because a Dialog is a type of Window, graphical components can be placed in the dialog
area, just as in a Frame or Panel. The default layout manager for a dialog is BorderLayout,
the same as with Frame.
The most common functions used with a dialog are not actually dened in the class
Dialog, but are inherited from parent classes. These include the following:
setSize(int, int) set window size
show() display window
setVisible(false) remove window from display
setTitle(String), getTitle() set or get title of window
For modal dialogs, the show method does not return until the dialog is dismissed. Such
dialogs must therefore invoke the setVisible(false) method sometime during their processing.
Individual menus are named, and are placed on the menu bar using the method add:
...
Menu helpMenu = new Menu ("Help")
bar.add (helpMenu)
...
Menu items are created using the class MenuItem. Each menu item maintains a list of
ActionListener objects, the same class used to handle Button events. The listeners will be
notied when the menu item is selected.
236 CHAPTER 13. THE AWT
public DialogTest () f
setTitle ("Dialog Test Program")
setSize (300, 220)
...
MenuItem quitItem = new MenuItem ("Quit")
quitItem.addActionListener (new QuitListener())
helpMenu.add (quitItem)
...
There are a number of techniques that can be used to create special-purpose menus, such
as tear-o menus, cascading menus, and so on. However, these will not be described here.
13.7.1 A Quit Menu Facility
On many platforms it is sometimes dicult to stop a running Java application. For this
reason, it is useful to dene a general purpose Quit menu bar facility. The class QuitItem
(Figure 13.11) creates a listener that will halt the running application when the associated
menu item is selected. By overloading the constructor, we make it trivial to add this
functionality to any application.
The constructor for QuitItem can be given a MenuItem as argument. In this case it
merely attaches itself as a listener to the menu item. Alternatively, it can be given a Menu,
in which case it creates a menu item labeled \Quit". Or it can be given a MenuBar, in which
case it creates a new menu labeled \Quit" that contains only the quit menu item. Finally,
the constructor can be given an application as argument, in which case it creates a new
menu bar containing only the one menu which contains only the single quit item. Using the
application constructor, a quit menu selection can be added to an application by placing
only a single line in the constructor for the application:
class ColorTest extends Frame f
...
public ColorTest () f
...
// add quit menu item to application
new QuitItem (this)
...
g
g
Study Questions
1. What do the letters AWT stand for?
2. What are the parent classes of class Frame?
238 CHAPTER 13. THE AWT
Exercises
1. Add a menu bar to the Solitare program described in Chapter 9. Then, add two menu
items, one to quit the application, and one to reset the application for a new game.
2. Using a text box and a grid of buttons, create a simple calculator application. Buttons
correspond to digits and the four arithmetic functions +, ;, and =, as well as the
equals sign.
240 CHAPTER 13. THE AWT
Chapter 14
InputStream
Each of the input stream classes support the common InputStream protocol. Some of
the classes augment this with additional methods. For example, a StringBuerInputStream
can be reset () back to the beginning of the underlying string.
Note that for simple reading and writing, a FileInputStream or FileOutputStream can be
manipulated without rst creating a File object. Generally, a File is necessary only if one is
doing operations to the le itself, such as renaming or removing the le. Another reason for
creating a File object would be to test whether a le is readable or writable before beginning
a sequence of input/output operations.
way to envision these classes is as an adapter, or lter, that sits between the client (the code
making the request for values) and the physical input stream producing the values.
client
?read ()
lter
?read ()
InputStream
Because they support the interface common to all input streams, such lters can be
easily added or removed as needed.
Perhaps the easiest lter to understand is the class LineNumberInputStream. The under-
lying input stream must be given as an argument to the constructor when an instance of
this class is created. The lter simply scans the input for newline characters as values are
read. Each time a newline character is found a counter is incremented. The value of this
counter can be retrieved by the method getLineNumber ().
The PushbackInputStream allows a single character to be unread. A value pushed back
into the input stream will subsequently be returned as the result of the next read() operation.
This facility is useful when scanning textual input. Imagine, for example, reading the textual
representation of a numeric value, such as 456. It is only after the rst non-digit character
is read that one knows that all of the digits of the number have been seen. But the last
character, the non-digit, should not be considered part of the number. Thus, this value is
\pushed back" into the input, to be read again later.
The PushbackInputStream only allows a single character to be reprocessed. The Buered-
InputStream is a more general facility, allowing the input operations to be backed up over a
larger range. The method mark() tells the stream to begin saving the values of characters
as they are read. A subsequent reset() then resets the input back to the marked location.
All characters between the mark and the reset will then be read again. The standard input
stream System.in is an example of a buered input stream. On most platforms, characters
cannot be read from this input stream until an entire line of text has been entered.
The input lter that adds the most new functionality is the class DataInputStream. In
this class, methods are provide to read the binary representation all of the primitive data
types:
class DataInputStream extends FilterInputStream implements DataInput f
...
public boolean readBoolean () throws IOException
Note that these methods read a binary representation, not a textual representation
of the values. Most generally, the input stream being processed was produced using a
DataOutputStream. However, DataInputStreams are also useful with purely textual les. In
particular, the method readLine () can be used when textual input must be processed in a
line by line fashion. An example was shown in Section 20.7.1. The DataInput interface is
also used by the class RandomAccessFile.
default:
System.out.println("token " + (char) tok.ttype)
break
g
g
g catch (IOException e) f g
g
Giving this program the input \23-skido, kid!" yields the output:
number 23.0
token -
word skido
token ,
word kid
token !
// close stream
public void close () throws IOException
g
As we did with input streams, we can divide the description of output streams into two
major categories, those classes that characterize the physical location of the output, and
those classes that add additional behavior to an output stream.
In the rst group are the three classes ByteArrayOutputStream, FileOutputStream, and
PipedOutputStream. The rst writes values into an in-memory byte array, the second on to
an external le, and the third to a pipe (see Section 14.3).
The second category is represented by the class FilterOutputStream and its subclasses.
Just as FilterInputStream provided an orthogonal way of adding additional functionality to an
input stream regardless of the physical source of the data, a ltered output stream adds new
functionality to an output operation. Whereas a ltered input stream generally performs
new operations after reading from the underlying stream, a ltered output stream generally
performs some task before sending the (perhaps transformed) values to the underlying output
stream. There are three subclasses of FilterOutputStream. These are BueredOutputStream,
DataOutputStream and PrintStream.
A BueredOutputStream maintains an internal buer of values that have been output.
Rather than writing bytes one by one, values are written to the underlying output stream
only when the buer becomes full or when the output is ushed. This is useful if there
is a high overhead involved in writing an individual byte to the output stream, and this
overhead can be amortized if many characters are written at once.
A DataOutputStream is the output equivalent of DataInputStream. This class adds meth-
ods to write the binary values for each of the primitive data types. The output will be
subsequently read by a DataInputStream. A program in Section 14.3 will illustrate the use
of a DataOutputStream.
A PrintStream is similar, but generates a textual representation, rather than a binary
representation. The methods print() and println() are overloaded with functions specic
to each of the primitive data types. Typically, a print stream is used to generate output
that will be read by human users, as opposed to processing by another program. Both the
streams System.out and System.err are instances of PrintStream.
248 CHAPTER 14. INPUT AND OUTPUT STREAMS
The implementation of the method print() when used with an object as argument is
an example of parameteric polymorphism combined with an abstract, or deferred method.
Because all objects are subclasses of Object, any value can be used as argument with this
method. When executed, the procedure uses the function toString() to convert the object
into a string representation. The implementation of this method in class Object simply
returns the name of the class of the receiver. However, this method is overridden in many
classes to provide more meaningful output. The function executed will be determined by
the dynamic, run-time type of the argument, not by the static type Object. In this fashion,
whatever text the programmer has provided using the toString() method will be the output
produced.
Values can subsequently be written to the piped output stream as if it were any other type
of output stream, and these values can then be read, in the same order they were inserted,
from the corresponding input stream.
We can illustrate the use of pipes by means of a program designed to nd all the integers
smaller than 100,000 that are both prime numbers and Fibonocci numbers. A prime number,
you will recall, is a value with no divisors other than 1 and itself. A Fibonocci number 1 is
dened by the recurrence relation f0 = 0, f1 = 1, fn = fn;2 + fn;1 .
A separate thread of control (see Chapter 21) is created to generate both sequences of
numbers. The thread, in fact, need not even know that it is dealing with a pipe. The
Fibonocci thread simply creates a sequence of values and writes them to an output stream.
Using a DataOutputStream makes it easier to write integer values. Although it looks as if
the thread produces all the values at once, a print() statement placed inside the loop will
demonstrate that this is not so, and that production of values will be delayed until they are
required.
class FibMaker extends Thread f
private DataOutputStream out
The main program shows how these are connected. The thread for each generator, as
well as the pipes, are created in the methods makeFibs() and makePrimes(). Note how all the
pipe mechanism is encapsulated in these two routines, and the remainder of the program
simply views input as coming from a DataInputStream. The main program simply reads
values as long as they are available, comparing them and outputting those that match.
class PipeTest f
static public void main (String ] args)
f PipeTest world = new PipeTest(System.out) g
14.3. PIPED INPUT AND OUTPUT 251
g
252 CHAPTER 14. INPUT AND OUTPUT STREAMS
An examination of the output will show that values are being generated on demand,
rather than being all computed at once.
writing new Fibonocci 1
writing new Fibonocci 2
writing new prime 2
writing new prime 3
writing new prime 5
writing new prime 7
writing new Fibonocci 3
writing new Fibonocci 5
writing new prime 11
writing new prime 13
writing new prime 17
writing new Fibonocci 8
writing new Fibonocci 13
writing new Fibonocci 21
integer 2 is both fib and prime
integer 3 is both fib and prime
integer 5 is both fib and prime
integer 13 is both fib and prime
writing new Fibonocci 34
...
writing new prime 19
writing new prime 23
...
writing new prime 31
writing new Fibonocci 233
...
integer 89 is both fib and prime
...
integer 233 is both fib and prime
input stream. An example of the latter is the class LineNumberInputStream, which adds the
ability to count line numbers to an existing input stream. The design of the subclasses of
FilterInputStream combine both the techniques of inheritance and composition.
Although not specically an input stream, the class StreamTokenizer provides a way to
break a stream into individual tokens. A similar facility for strings will be described in
Chapter 18.
Like input streams, the various subclasses of output stream dier in the physical location
to which the output is directed.
Pipes provide a mechanism for structuring programs that include both the production
and consumption of a given resource. The producer writes values to the pipe, while the
consumer reads values. The pipe facility will automatically suspect either the producer or
the consumer tasks, if values are not available or the pipe buer becomes full.
Study Questions
1. Describe the functions that are common to all subclasses of InputStream.
2. What are the dierent types of physical locations from which an input stream can
read?
3. Describe out a FilterInputStream combines both inheritance and composition.
4. What new functionality is provided by the class LineNumberInputStream?
5. What task is performed by a StreamTokenizer?
6. Describe the dierent targets to which an output stream can write.
7. In what ways is a pipe dierent from a le? In what ways are they the same?
Exercises
1. Create a new subclass of FilterInputStream that reads values from an input stream and
coverts all upper case characters to lower case. How would you test your program?
2. Using DataInputStream.readLine() and a StringTokenizer, write an application that will
count and display the number of lines, words and characters in a le. The name of
the le should be taken from the argument list for the application.
3. Write the class description for SequenceOutputStream, which is the output analog to
SequenceInputStream. The constructor for this class will take two output streams as
argument. Each write to the SequenceOutputStream will thereafter be translated into
a write on each of the argument streams.
254 CHAPTER 14. INPUT AND OUTPUT STREAMS
4. Extend the class you developed in the preceding exercise so that the constructor can
take an enumeration of output streams as argument.
5. Write a subclass of FilterInputStream that looks for positive integer digit characters,
such as \4231", and replaces them with the textual equivalent, in this example the
words \four thousand two hundred and thirty one". Do this in several steps:
(a) Convert the input stream into a PushbackInputStream.
(b) As long as the source input stream is not a digit character, return it.
(c) When a digit character is encountered, read the number until the end of digit is
found.
(d) Push the terminating non-digit character back into the input.
(e) Translate the number into its textual equivalent, stored in a String. Create a
StringBuerInputStream to read characters from this string.
(f) For subsequent requests, read from the string buer input stream until no fur-
ther characters remain, then revert to reading from the original push back input
stream.
Chapter 15
Design Patterns
Like most complex structures, good computer programs are often formed by imitating the
structure of older, similar programs that have already proven successful. The concept of a
design pattern is an attempt to capture and formalize this process of imitation. The basic
idea is to characterize the features of a proven solution to a small problem, summarizing the
essential elements and omitting the unnecessary detail. A catalog of design patterns is a
fascinating illustration of the myriad ways that software can be structured so as to address
dierent problems. Later, patterns can give insight into how to approach new problems that
are similar to those situations described by the pattern.
This chapter will introduce the idea of design patterns by describing several that are
found in the Java library. The terminology used in describing the patterns is adapted
from the book Design Patterns: Elements of Reusable Object-Oriented Software, by Erich
Gamma, Richard Helm, Ralph Johnson and John Vlissides Gamma 1995]. This was one of
the rst books to describe the concept of design patterns and provide a systematic cataloging
of patterns. Many more patterns than are described here can be found in this book, as well
as in the recent literature on design patterns.
The format used in describing each pattern is to rst characterize the problem the
pattern is addressing. Then, the essential features of the solution are summarized. In some
cases this is followed by a discussion that examines some of the context for the problem, or
contrasts alternative design possibilities. This is followed by a more detailed description of
the pattern as it is manifest in the Java Library. Finally, a sentence or two summarizes the
situations where the pattern is applicable.
15.1 Adapter
problem: How do you use an object that provides appropriate behavior but uses a dierent
interface than is required in some situation?
255
256 CHAPTER 15. DESIGN PATTERNS
solution: Dene an adapter class that acts as an intermediary. The adapter does little
work itself, but merely translates commands from one form into the other.
discussion: International travelers frequently overcome the problem of diering electrical
plug and voltage standards by using adapters for their appliances. These adapters
allow an electrical appliance that uses one type of plug to be modied so that it can
be used with a dierent type of plug. The software equivalent is similar. An adapter is
concerned mostly with changes in the interface to an object, and less with the actual
functionality being provided.
example: An example of adapters in the Java library are the \wrapper" classes, Boolean,
Integer, and so on. These adapt a primitive type (such as boolean or int) so that they
can be used in situations where an Object is required. For example, wrappers are
necessary to store primitive values as elements in a Vector.
Another form of adapter is the class MouseAdaptor used in the pin ball game described
in Chapter 7, as well as in the Solitare program presented in Chapter 9. Here the
adapter reduces the interface, by implementing default behavior for methods that are
unneeded in the current application. The client can therefore concentrate on the one
method that is used in the program.
An adapter can be used whenever there is the need for a change in interface, but no,
or very little, additional behavior beyond that provided by the worker.
15.2 Composition
problem: How do you permit the creation of complex objects using only simple parts?
solution: Provide a small collection of simple components, but also allow these components
to be nested arbitrarily. The resulting composite objects allow individual objects and
compositions of objects to be treated uniformly. Frequently, an interesting feature of
the composition pattern is the merging of the is-a relation with the has-a relation.
example: A good example of composition in the Java library is the creation of design
layouts through the interaction of Components and Containers. There are only ve
simple types of layouts provided by the standard library, and of these ve only two,
border layouts and grid layouts, are commonly used. Each item in a layout is a
Component. Composition occurs because Containers are also Components. A container
15.2. COMPOSITION 257
holds its own layout, which is again one of only a few simple varieties. Yet the container
is treated as a unit in the original layout.
The structure of a composite object is often described in a tree-like format. Consider,
for example, the layout of the window shown in Figure 13.8 of Chapter 13. At the
application level there are four elements to the layout. These are a text area, a simple
blank panel, and two panels that hold composite objects. One of these composite
panels holds three scroll bars, while the second is holding a grid of sixteen buttons.
Color = 40,60,50]
(
h
(((( Hhhhh
(((( HH hhhh
Color =
PP X
HX XXX
PP
P HH X
:::
By nesting panels one within another, arbitrarily complex layouts can be created.
Another example of composition is the class SequenceInputStream, which is used to
catenate two or more input streams so that they appear to be a single input source
(see Section 14.1.2). A SequenceInputStream is-a InputStream (meaning it extends the
class InputStream). But a SequenceInputStream also has-a InputStream as part of its
internal state. By combining inheritance and composition, the class permits multiple
sequences of input sources to be treated as a single unit.
This pattern is useful whenever it is necessary to build complex structures out of a few
simple elements. Note that the merging of the is-a and has-a relations is characteristic
of the wrapper pattern (Section 15.9), although wrappers can be constructed that are
not composites.
258 CHAPTER 15. DESIGN PATTERNS
15.3 Strategy
problem: How do you allow the algorithm that is used to solve a particular problem to be
easily and dynamically changed by the client?
solution: Dene a family of algorithms with a similar interface. Encapsulate each algo-
rithm, and let the client select the algorithm to be used in any situation.
discussion: If a complex algorithm is embedded in a larger application, it may be dicult
to extract the algorithm and replace it with another, alternative version. If several
alternative algorithms are included in the same object, both the complexity and the
code of the resulting object may be increased unnecessarily. By separating problem
and solution, it is easier for the client to select the solution (algorithm) appropriate
for any particular situation.
example: An example of the use of the Strategy pattern is the creation of layout managers
in the AWT. Rather than coding in the component library the details of how items
are laid out on the screen, these decisions are left to the layout manager. An interface
for LayoutManager is dened, and ve standard layout managers are provided. The
ambitious programmer is even allowed, should he or she choose, to dene a new object
that satises the LayoutManager interface.
holds
Container LayoutManager
inherits implements
Application GridLayout
15.4 Observer
problem: How do you allow two or more independent and loosely coupled objects to change
in synchrony with each other?
solution: Maintain a list of objects that are tied, or dependent, on another object. When
the target object changes, the dependents are notied that they should update them-
selves.
discussion: It is easy to maintain tightly coupled objects in synchrony. For example, if a
new class is dened as a subclass of an existing parent class, modications of the parent
that are made via method invocations can be monitored by simply overriding the
methods. It is much more dicult to keep objects in step with each other when links
are formed and broken dynamically at run time, or when no obvious class relationship
exists between the separate elements.
example: There are two good examples of the use of the observer pattern in the Java
library. The rst we have seen in many earlier case studies, such as the cannon
world examined in Chapter 6. Each of the user interface components that permits
interaction, such as buttons, scroll bars, and check boxes, maintains a collection of
listener objects. This list is dynamic listeners for any component can be easily added
or removed at run time. Furthermore, the structure of the listeners is not specied,
they are only required to satisfy the necessary interface. When the component changes
state (the button is pressed, the slider moved, the Checkbox changed), each of the
listeners is notied that a change has occurred. It is up to the listener to decide what
action should be taken as a result of the change.
The idea behind listeners is also found in a more general facility that can be used
by programmers for situations that do not involve user interaction. The library class
Observable represents objects that can be \observed", the equivalent of the components
in the AWT mechanism. Programmers can either subclass a new class from Observable,
or simply create an Observable eld within a class. Other objects can implement the
Observer interface. These correspond to \listener" objects. An instance of Observer
registers itself with the object being observed.
At any time, the Observable object can indicate that it has changed, by invoking
the message notifyObservers(). An optional argument can be passed along with this
message. Each observer is passed the message update(Observable, Object), where the
rst argument is the Observable that has changed, and the second is the optional
argument provided by the notication. The observer takes whatever action is necessary
to bring the state into synchrony with the observed object.
The Observer pattern is applicable whenever two or more objects must be loosely
coupled, but must still maintain synchronization in some aspect of their behavior or
state.
260 CHAPTER 15. DESIGN PATTERNS
15.5 Flyweight
problem: How can one reduce the storage costs associated with a large number of objects
that have similar state?
solution: Share state in common with similar objects, thereby reducing the storage required
by any single object.
example: With the exception of primitive values, all objects in Java are an instance of
some class. With each class it is necessary to associate certain information. Examples
of information is the name of the class (a String), and the description of the interface
for the class. If this information was duplicated in each object the memory costs would
be prohibitive. Instead, this information is dened once by an object of type Class,
and each instance of the class points to this object.
The objects that share the information are known as yweights, since their memory
requirements are reduced (often dramatically) by moving part of their state to the
shared value. The yweight pattern can be used whenever there are a large number
of objects that share a signicant common internal state.
characters, the distance characters extend above or below the baseline, and so on.
A FontMetric is an abstract class, one that cannot be instanciated directly by the
programmer using the new command. Instead, a value of type FontMetric is returned
by a Graphics object in response to the message getFontMetrics. Clearly, the graphics
object is returning a value derived from a subclass of FontMetric, but the particular
value returned is normally of no concern to the client.
A similar facility is used by class Applet, which can return an AppletContext that
describes the current execution environment.
The abstract factory pattern should be used whenever the type of the actual value
to be created cannot be predicted in advance, and therefore must be determined
dynamically.
15.8 Iterator
problem: How to provide a way to access elements of an aggregate object sequentially
without exposing the underlying representation.
262 CHAPTER 15. DESIGN PATTERNS
solution: Provide a mediator object for the sole purpose of sequential access. This mediator
can be aware of the representation of the aggregate, however the client using the object
need not be aware of these details.
example: The Enumeration interface for container access actually addresses two related
problems. It provides a uniform means of accessing elements from many dierent
types of container, and it hides the details of the underlying container representation.
It is the second aspect that makes the Enumeration a good example of the iterator
pattern.
Consider, for example, an enumeration that is generating elements from a Hashtable.
Internally, a hash table is implemented as an array, each element of the array being a
list. Values that hash into the same locations are found on the same list.
0 - 23 - 31
1
2 - 72 - 9 - 5 - 12
3
4
5 - 25 - 1
6 - 3
The programmer who uses a hash table and wishes to iterate over the values should not
be concerned with the representation, such as moving from one list to the next when
the elements in one hash location have been exhausted. The hash table enumeration
hides these diculties behind a simple interface. The programmer sees only the two
methods hasMoreElements() and nextElement(). With these, a loop can be written that
does not even hint at the complex actions needed to access the underlying elements.
HashTable htab = new HashTable()
...
for (Enumeration e = htab.elements() e.hasMoreElements() ) f
Object val = e.nextElement()
...
g
The fact that the method elements returns a value that is not directly an Enumeration,
but is rather a value from another class that implements the Enumeration interface, is
an example of the Abstract Factory pattern (Section 15.6).
15.9. DECORATOR (FILTER OR WRAPPER) 263
The iterator pattern is useful whenever an aggregate object is created that can hold
an arbitrary number of values, and it is necessary to provide access to values without
exposing the underlying representation.
Buered
InputStream
InputStream
example: The class InputStream provides a way to read bytes from an input device, such
as a le. The class BueredInputStream is a subclass of InputStream, adding the ability
to buer the input so that it can be reset to an earlier point and values can be reread
two or more times. Furthermore, a BueredInputStream can take an InputStream as
argument in its constructor.
Because a BueredInputStream both is an InputStream and has an input stream as
part of its data, it can be easily wrapped around an existing input stream. Due
to inheritance and substitutability, the BueredInputStream can be used where the
original InputStream was expected. Because it holds the original input stream, any
actions unrelated to the buering activities are simply passed on to the original stream.
264 CHAPTER 15. DESIGN PATTERNS
15.10 Proxy
problem: How do you hide details such as transmission protocols to remote objects?
solution: Provide a proxy that acts as a surrogate or placeholder for another object.
discussion: The idea of a proxy is that one object is standing in place of another. The
rst object receives requests for the second, and generally forwards the requests to the
second, after processing them in some fashion.
example: An example proxy in the Java Library is the RMI, or Remote Method Invocation
system. The RMI is a mechanism that can be used to coordinate Java programs
running on two or more machines. Using the RMI, a proxy object is created that runs
on the same machine as the client. When the client invokes a method on the proxy,
the proxy transmits the method across the network to the server on another machine.
The server handles the request, then transmits the result back to the proxy. The proxy
hands the result back to the client. In this fashion, the details of transmission over
the network are handled by the proxy and the server, and are hidden from the client.
15.11 Bridge
problem: How to decouple an abstraction from its implementation so that the latter can
vary independently.
solution: Remove implementation details from the abstraction, placing them instead in an
object that is held as a component in the abstraction.
example: Most of the component classes in the AWT make use of the bridge pattern. Fun-
damentally, this is because the actions necessary to implement a graphical component
vary in great detail from one platform to another. For example, the actions needed
to display a window are dierent depending upon whether the underlying display
is X-Windows/Motif, Windows-95, or the Macintosh. Rather than placing platform
specic details in the class Window, instead each window maintains a component of
15.12. CHAPTER SUMMARY 265
Further Reading
The most important reference for design patterns is the book of the same name Gamma 1995],
by Gamma, Helm, Johnson and Vlissides (commonly known as the Gang of Four, or GOF).
Another recent book on patterns is by Richard Gabriel Gabriel 1996].
Study Questions
1. In what ways is an adapter similar to a proxy? In what ways are they dierent?
2. In what way is the composition design pattern similar to the idea of composition
examined in Chapter 10?
3. In what ways is a strategy similar to a bridge? In what ways are they dierent?
4. In what ways is an iterator similar to an adapter?
Exercises
1. What design pattern is exhibited by the class PrintStream (see Section 14.2)? Explain
your answer.
266 CHAPTER 15. DESIGN PATTERNS
Part V
267
Chapter 16
Exception Handling
From the start, Java was designed with the understanding that errors occur, that unexpected
events happen, and that programmers should always be prepared for the worst. Part of this
outlook is the inclusion in the language of a simple yet powerful mechanism for handling
exceptions.
An exception is an event that occurs during the execution of a program that disrupts
the ow of instructions, and prevents the program from continuing along its normal course.
An example that is easy to understand is the exception that occurs when a le cannot be
opened. The programmer developing a le processing application starts out with a structure
that perhaps looks something like the following:
ask the user for the name of a file
open the file
read the contents
do something with the contents
close the file
The programmer probably develops the application using some simple test cases, and
might not even think about the possibility that the le cannot be opened. What happens
if the user enters incorrect values, a name that is not a valid le name? In most languages,
the likely answer is that the program will fail in totally unexpected and inexplicable ways.
In Java, the programmer cannot simply forget to think about this possibility, because
the language will not allow the programmer to write a statement that opens a le without
providing the code that will be executed should a failure occur. The le opening method is
declared as a function that can potentially throw an exception, and the compiler will refuse
to recognize any use of the method that does not handle the exception.
As we saw earlier in the case study described in Chapter 7, a method that can potentially
raise an exception must be invoked within the framework of a try/catch block. This is
269
270 CHAPTER 16. EXCEPTION HANDLING
written as a nested statement following the keyword try, and an associated set of statements
following the keyword catch:
try f
File fd = new File(filename)
g catch (fileOpenFailed e)
f System.err.println("Cannot open file " + filename) g
The exception mechanism is in fact dealing with an actual object, which is an instance
of class Throwable. When an error occurs, the value of this object is assigned to the variable
e in the statements shown above.
Multiple statements can be nested within the try block. In fact, often almost the entire
application will be held within a surrounding block.
try f
File fd = new File(filename)
processFile (fd)
fd.close()
g catch (fileOpenFailed e)
f System.err.println("Cannot open file " + filename) g
Exceptions are a useful programming construct because the location where an error is
detected is usually not the place where the appropriate solution is known. For example,
suppose you are the programmer developing the le processing library routines. That is,
you are the person developing the code for the class File. Certainly you are aware of the
fact that the string passed to the constructor for your class might not represent a valid le
name. But what should you do in this situation? Without knowledge of the surrounding
application, there is no good answer.
One common solution is to return a special value, such as the value null, is a command
cannot be processed. But constructors are not permitted to return a null value, furthermore
there might be multiple reasons for a failure. Does a null value returned by a le open
16.1. INFORMATION TRANSMITTED TO THE CATCH BLOCK 271
operation mean the le does not exist, or that it exists but cannot be read? Finally, what
if a null value is perfectly legal? How would one indicate an error in that case?
The exception mechanism not only allows the programmer who detects the message the
ability to return precise information, it also places responsibility for dealing with the error
on the shoulders of the programmer who knows the appropriate action to take.
Errors represent \hard" failures, such as the virtual machine detecting an error in the
bytecode representation. Processing will immediately halt once such an error is detected.
Fortunately, it is unlikely that a typical Java program will ever see or throw such an error.
Most programmers will write code to throw and catch objects that derive from the class
Exception. Once again, these can be divided into two categories, RuntimeException and all
others.
The subclasses of RuntimeException represent conditions that arise within the Java vir-
tual machine itself during the processing of the bytecodes that represent a program. Ex-
amples include the use of a variable that has not been initialized (NullPointerException), an
improper cast conversion, or an arithmetic operation that over ows. Because the source for
such an error could potentially be almost any Java statement, the compiler does not insist
that programmer test for or catch these errors. (Think about what a program would look
like if every variable reference needed to be surrounded by a try statement to detect null
pointer possibilities).
class Stack f
private int index
private Vector values
...
Here the IOException could be thrown by the method readLine. However, this method
really had no better way of dealing with this particular error than did the readLine routine
itself. Thus, the error is simply passed back to the caller of readLines, who could take the
appropriate action.
Utility Classes
The Java library provides a number of small utility classes that are useful in a wide variety
of situations. This chapter will discuss several of these, including Point, Dimension, Date,
Math, Random, Toolkit, and the data eld named System.
17.1 Point
A Point represents a location in two-dimensional space. The point is described by a pair of
integer values, called the x and y values. Points are used in conjunction with a number of the
AWT painting operations and with layout managers. An important feature to remember is
that in the AWT coordinate system, the y coordinates increase as locations move downward,
rather than decreasing as is true in classical geometry.
The following summarizes the characteristics of the class Point
class Point f
// constructor
public Point (int x, int y)
// operations
public void move (int x, int y) // move to given location
public void translate (int x, int y) // change by oset
public boolean equals (Object p) // compare two points
public String toString () // convert to string
275
276 CHAPTER 17. UTILITY CLASSES
17.2 Dimension
A dimension is used to represent a rectangular size. Dimensions are characterized by a width
and a height. Dimensions are used in many AWT methods, and returned as the result of
methods that need to characterize a size. The following summarizes the features of the class
Dimension:
class Dimension f
// constructors
public Dimension ()
public Dimension (int w, int h)
public Dimension (Dimension d) // make copy
// public accessible data elds
public int width
public int height
// operations
public String toString()
g
17.3 Date
The class Date is used to represent both data and time values. Two dates can be compared
to determine if one comes after the other. Once set, any of the elds in a date can be
changed. The following summarizes the methods provided by the class Date:
class Date f
// constructors
public Date () // return current date and time
public Date (int year, int month, int day)
public Date (int year, int month, int day, int hours, int minutes)
public Date (int year, int month, int day,
int hours, int minutes, int seconds)
// epoch methods
public long getTime () // returns milliseconds since epoch
public void setTime (long lval) // set time from epoch
// comparison methods
public boolean after (Date day)
public boolean before (Date day)
public boolean equals (Object day)
// output
public String toString ()
g
When provided with no constructors, the class Date returns the current time and day.
Otherwise, the date is set from the argument values given. The year value is given as the
year minus 1900, that is, 97 represents 1997, and 112 represents 2012.
Notice that the method equals overrides the similarly named method inherited from class
Object. Thus, the argument to this method must be simply Object. However, the methods
after and before, which are dened here for the rst time, can be restricted to working only
with Date objects.
This quantity is returned by the method getTime. Most often these values are used in pairs,
to obtain the amount of time used to perform a certain operation:
Date start = new Date() // starting time
int j = 0
for (int i = 0 i < 100000 i++)
j = j + 1
Epoch values for dates prior to January 1, 1970 are returned as negative numbers.
17.4 Math
The class Math provides a number of constants, as well as useful mathematical functions.
All values and functions are declared as static. Thus, these elements are accessible without
creating an instance of the class. The class can be summarized as follows:
final class Math f
// constants
public static final double E // 2.71828 ...
public static final double PI // 3.1415926 ...
// trigonometric operations, angles in radians
public static double sin (double num)
public static double cos (double num)
public static double tan (double num)
public static double asin (double num)
public static double acos (double num)
public static double atan (double num)
public static double atan2 (double s, double c)
// rounding operations
public static double ceil (double num)
public static double floor (double num)
public static double rint (double num)
public static int round (float num)
public static long round (double num)
17.5. RANDOM 279
// other operations
public static int abs (int num)
public static long abs (long num)
public static float abs (float num)
public static double abs (double num)
public static int max (int x, int y)
public static float max (float x, float y)
public static double max (double x, double y)
public static int min (int x, int y)
public static float min (float x, float y)
public static double min (double x, double y)
public static double random () // value between 0 and 1
g
The method random() returns a value that is larger than or equal to 0.0, and strictly
smaller than 1.0, uniformly distributed over the range. The following, for example, could
be used to return a random number between 1 and 10 (inclusive of both endpoints):
int val = (int) Math.floor(Math.random() 10 + 1)
17.5 Random
The function Math.random() can be used to generate random oating point values larger
than or equal to 0.0 and smaller than 1.0 with a uniform distribution. The class Random
provides more general facilities, allowing not only the generation of random integers, but
also the ability to reset the random number generator with a seed value. This latter feature
provides a way to recreate the same random sequence of values many times, a property that
is often useful in testing programs, as well as other situations. The facilities provided by
Random can be summarized as follows:
class Random f
// constructors
280 CHAPTER 17. UTILITY CLASSES
public Random ()
public Random (long seed)
// operations
public void setSeed (long seed)
public double nextDouble ()
public float nextFloat ()
// alternative distribution
public double nextGaussian ()
g
All methods use a uniform distribution, with the exception of nextGaussian, which uses
a Gaussian distribution. Other distributions can often be constructed from these. The
following function, for example, takes as argument an integer array of weights, and computes
a random number with weighted distribution. It sums the array of weights, computes a
random integer between 0 and the sum, then locates the integer in the array of weights:
static public int weightedDistribution (int ] weights) f
int sum = 0 // compute sum of weights
for (int i = 0 i < weights.length i++)
sum += weightsi]
// compute random value less than sum
int val = (int) Math.floor(Math.random() sum + 1)
// nd point in distribution
for (int i = 0 i < weights.length i++) f
val -= weightsi]
if (val < 0)
return i
g
return 0 // should never happen
g
Given an array of weights (1 3 2), for example, the value 0 would be returned 1/6 of the
time, the value 1 returned 1/2 of the time, and the value 2 returned 1/3 of the time.
17.6. TOOLKIT 281
17.6 Toolkit
The class Toolkit is mostly used to create the peer objects used in providing the device
independent aspects of the AWT (see Section 15.11). However, in addition to creating the
windows, buttons, menus and other features of a graphical interface, the class also provides
a few utilities useful to the programmer.
Toolkit is an abstract class, specialized for each type of platform on which a Java program
can be executed. The implementation of Toolkit appropriate to the current environment is
found by executing the method Toolkit.getDefaultToolkit().
The method getFontList() returns an array of string values, containing the names of the
fonts available on the current system.
The method getImage() takes as argument either a string or a URL (see Section 22.4.1).
If a string argument is used it should contain the name of a le. The image is loaded from
the le or the URL address, and returned as a value of type Image.
The methods getScreenSize() and getScreenResolution() together return the size of the
screen. The rst returns the number of pixels in the screen, both hight and width in a value
of type Dimension. The second returns the number of dots-per-inch. Dividing one by the
other will yield the physical size of the screen.
17.7 System
The class System, and the instance data eld of the same name provided by class Frame,
give access to several system-wide resources. The most commonly used values are the input
and output streams for the standard input, standard output and error output. These are
found at System.in, System.out and System.err, respectively.
The function System.exit(int) immediately halts the currently running program, yielding
to the operating system the integer status value given in the argument.
The method currentTimeMillis() returns the current time in milliseconds. The value is
returned as a signed long value, representing the number of milliseconds since January 1,
1970 (see Section 17.3.1). Since the value is returned an a long, over ow will occur sometime
in the year 292280995.
282 CHAPTER 17. UTILITY CLASSES
Chapter 18
The various constructors for string also allow a string to be created from another string,
from an array of characters or bytes, or from a string buer:
283
284 CHAPTER 18. STRINGS AND RELATED CLASSES
char data] = f q , e , d g
String quod = new String(data)
// quod erat demonstrandum
The addition operator, +, is overloaded with a new meaning when either the left or the
right argument is a string. In this case, the non-string argument (if any) is converted into a
string and a string catenation is performed. This is most often used to produce formatted
output:
System.out.println(" The answer is: " + answer)
Note that the addition operator groups left to right, so that the meaning of the addition
in the following two expressions is very dierent:
System.out.println("Catch-" + 2 + 2) // catch-22
System.out.println(2 + 2 + "warned") // be forewarned
The String class denes a number of methods for returning portions of a string, converting
values to a string, and comparing strings. These can be summarized as follows:
final class String f // declared nal so it cannot be subclassed
// constructors
public String (String src)
public String (char ] charArray)
public String (byte ] byteArray)
public String (StringBuffer buffer)
// comparison methods
// compare ordering, return negative, zero or positive
public int compareTo (String str)
// compare for equality
public boolean equals (String str)
public boolean equalsIgnoreCase (String str)
// test front or end of string
public boolean endsWith (String str)
public boolean startsWith (String str)
// nd rst occurrence of char or string
public int indexOf (char c)
public int indexOf (char c, int startingOffset)
public int indexOf (String str, int startingOffset)
public int lastIndexOf (char c)
public int lastIndexOf (char c, int startingOffset)
public int lastIndexOf (String str, int startingOffset)
g
There are a few subtle points that can trap the unwary programmer. Note that the
identity operator, ==, tests whether two variables refer to exactly the same value. This is
not the same as testing whether two string values have exactly the same character represen-
tation. In general, one should always use equals() to test the equality of objects, including
strings, and not use the == operator.
The method compareTo() returns an integer result. This value is negative if the current
string is lexicographically smaller than the argument, zero if they are equal, and positive if
the string is larger than the argument. The exact integer value returned is implementation
dependent, and should not be counted upon in any program.
The static method String.valueOf (Object obj) is a good example of a polymorphic func-
tion. The argument can be any type of object, including a null object. If it is not null, the
method toString is used to convert the object into a string value:
286 CHAPTER 18. STRINGS AND RELATED CLASSES
The method toString is dened in class Object (where it returns the class name of the
receiver as a string), and redened in many classes. The value yielded by toString(), and
hence by valueOf(), will be whatever method is appropriate for the dynamic, run-time type
of the argument.
This property of the == operator can be used to demonstrate one subtle dierence
between creating a new string using the String constructor, and creating a string using the
valueOf operator. One case generates a copy of the original string, while the other simply
returns a reference to the original.
String one = "One"
String two = new String(one)
String three = String.valueOf(one)
System.out.println(" is one == two " + (one == two)) // returns false
System.out.println(" is one == three " + (one == three)) // returns true
// misc methods
public int length ()
public void setLength (int length)
public void ensureCapacity ()
public String toString ()
g
Note that the methods append, insert and reverse both change the current string buer
and return a reference to the updated string buer. This is dierent from the transformation
methods in class String, which leave the receiver string unchanged, but return a new string
in which the transformations have been applied.
The append operator is used internally by the Java compiler to implement the + operator.
An statement such as:
System.out.println("answer: " + answer)
// enumeration protocol
public boolean hasMoreElements ()
public Object nextElement ()
public String nextToken ()
The enumeration protocol requires that the method nextElement() return a value of
type Object. In order to avoid the consequent casting of this value to a String, the equiv-
alent method nextToken() can be used instead. The concordance program described in
Section 20.7.1 illustrated the use of a string tokenizer in breaking a line into a sequence of
words:
class Concordance f
...
public void readLines (DataInputStream input) throws IOException f
String delims = " \t\n.,!?:"
for (int line = 1 true line++ ) f
String text = input.readLine()
if (text == null) return
text = text.toLowerCase()
Enumeration e = new StringTokenizer(text, delims)
while (e.hasMoreElements())
enterWord ((String) e.nextElement(), new Integer(line))
g
g
...
g
The class StreamTokenizer (Section 14.1.3) provides a similar facility to breaking an input
stream into tokens.
18.4. PARSING STRING VALUES 289
The wrapper classes also provide the reverse that is, a way to change a primitive value
into a string. Often there are a variety of dierent formats available. These facilities are
summarized in the following table:
class conversion from string conversion to string
Boolean new Boolean(str) toString()
Boolean.valueOf(Boolean bval)
Double new Double(str) toString()
Double.valueOf(double dval)
Float new Float(str) toString()
Float.valueOf(Float fval)
Integer new Integer(str) toString()
Integer.parseInt(String str, int radix) toBinaryString()
Integer.valueOf(int ival) toOcatalString()
toHexString()
Most of the conversion methods will throw a NumberFOrmatException if the characters
do not represent a value in the correct format.
Cross References
Study Questions
Exercises
290 CHAPTER 18. STRINGS AND RELATED CLASSES
Chapter 19
Understanding Graphics
The Java language provides one of the richest collections of graphical commands of any
general-purpose programming language. In this chapter we will explain some of the basic
aspects of the classes associated with graphical operations in Java. Topics discussed include
colors, fonts, images, and animation.
19.1 Color
The class Color is used to represent a color value. We know from optics that all colors can
be formed by combinations of red, green and blue. Color televisions use this principle, dis-
playing colors as combinations of red, green and blue dots. In order to more easily represent
colors in a computer, each of the three amounts of red, green and blue is represented by an
integer value between 0 and 255. (There is nothing magic about the value 255, it was simply
chosen so that each quantity could be stored in an eight-bit byte). For each quantity, the
larger the value, the brighter the component. A value of (0,0,0) is therefore black, while a
value of (255, 255, 255) is white.1 While in theory this encoding can represent 2512 dierent
colors (28 28 28 ), in practice most display devices can handle only a limited range. When
the exact color is unavailable, the actual color produced by a display device will usually be
the closest matching color.
The Java library class Color allows colors to be specied using three integer values. The
class also denes predened constants for a number of commonly used colors. These are
described in Figure 19.1. The constructor for color takes as argument the three integer values
representing the red, green and blue components. These values can subsequently be retrieved
from a color using the methods getRed, getGreen and getBlue. The methods brighter and
1 There is an alternative system that represents each color by a triple of oating point values that represent
the Hue, Saturation and Brightness of the color. The HSB system is not used as much as the RGB system,
and will not be described here. The class Color provides methods for converting between the two systems.
291
292 CHAPTER 19. UNDERSTANDING GRAPHICS
Predened Colors
Color.black Color.magenta
Color.blue Color.orange
Color.cyan Color.pink
Color.darkGray Color.red
Color.gray Color.white
Color.green color.yellow
Color.lightGray
Description of methods in class Color
new Color (int, int, int) constructor
brighter() create brighter version of color
darker() create darker version of color
getBlue() return blue component of color
getGreen() return green component of color
getRed() return red component of color
toString() return string representation of color
Figure 19.1: Methods for class Color
darker return brighter and darker versions of the current color. Finally, the method toString
returns a string representation of the current color. A program that illustrates the use of
many of the features of class Color is described in Section 13.5.
19.2 Rectangles
There are two classes in the Java library used for manipulating polygon shapes. The class
Rectangle represents a rectangular area on a two-dimensional plane. The class Polygon
represents more general polygon shapes.
We have used the class Rectangle already in the cannon world program described in
Chapter 6. In that program, every graphical object, each ball as well as each target, was
placed on top of a rectangle that represented the location of the item. The application used
the fact that a rectangle not only records a position on the two dimensional surface, but
can also be easily moved to a new position, and can tell whether or not it intersects with
another rectangle.
A new rectangle can be created in a variety of ways. If no arguments are provided with
the constructor, then an empty rectangle whose northwest corner is the origin is created.
If two integers are specied, they are taken to be a width and height for a rectangle with
northwest corner at the origin. If four integer arguments are specied, the rst two are the
locations of the northwest corner, and the remaining arguments are the width and height.
Rectangle r = new Rectangle ()
19.2. RECTANGLES 293
public RectTest () f
setSize (400, 400)
setTitle ("Rectangle test")
rects.addElement (new Rectangle(4, 5))
rects.addElement (new Rectangle(100, 100, 6, 7))
g
Figure 19.2:
19.3. FONTS 295
g
else f
r.translate (i, j)
if (r.x < 0)
r.setLocation (r.x + FrameWidth, r.y)
if (r.y < 0)
r.setLocation (r.x, r.y + FrameWidth)
if (r.x > FrameWidth)
r.setLocation (r.x - FrameWidth, r.y)
if (r.y > FrameWidth)
r.setLocation (r.x, r.y - FrameWidth)
g
g
g
The routine to test for intersections uses a doubly nested enumeration loop. If it locates
two intersecting rectangles, a new rectangle is created and placed in the upper corner. Only
one new rectangle is created each move, in order to slow the process of lling the window.
private void spawnNewRectangles() f
for (Enumeration e = rects.elements() e.hasMoreElements() ) f
Rectangle r1 = (Rectangle) e.nextElement()
for (Enumeration f = rects.elements() f.hasMoreElements() ) f
Rectangle r2 = (Rectangle) f.nextElement()
if (r1.intersects(r2) && ! r1.equals(r2)) f
Rectangle nr = r1.intersection(r2)
nr.setLocation (0, 0)
rects.addElement(nr)
return
g
g
g
g
19.3 Fonts
A Font object describes the characteristics used to display printed text. Features of a font
that the programmer can modify are the style, size, and font family (or logical name).
The logical font name describes the family of font styles being used. There are six rec-
ognized logical font names, Dialog, Helvetica, TimesRoman, Courier, DialogInput and Symbol.
296 CHAPTER 19. UNDERSTANDING GRAPHICS
The last is used to represent non-alphabetic symbols, and is seldom used. Courier is a
font with xed-width characters, much like a typewriter. Helvetica and Times Roman are
variable width fonts, which are the type normally used for printed text. An example of text
printed in each of the rst ve fonts is shown in Figure 19.3.
A font style describes the thickness and slant of the characters. In the Java library there
are two characteristics that describe a style. These are the Bold attribute and the Italic
attribute. Each is represented by an integer value, which can be combined. Thus, there
are four dierent representations for each font family: plain (neither bold nor italic), bold,
italic, and both bold and italic.
A font point size represents the size of the individual characters. Points are units used
in typesetting. One point is approximately 1/72 of an inch.
The following chart describes the most commonly used methods recognized by instances
of class Font.
Font(String name, int style, int size) construct new font
Font.PLAIN constant used to describe plain fonts
Font.BOLD constant used to describe bold fonts
Font.ITALIC constant used to describe italic fonts
getName() return logical name
getSize() return point size
getStyle() return style characteristics
isBold() determine if font is bold
isItalic() determine if font is italic
isPlain() determine if font is plain
toString() return string representation of font
19.3. FONTS 297
An instance of class Font can be created by providing the logical font name, a style, and
a size. The name must be one of the six names recognized family names (Dialog, Helvetica,
TimesRoman, Courier, DialogInput and Symbol). The style is formed using the class constants.
A font that is both bold and italic can be created by adding the two values Font.BOLD and
Font.ITALIC. The size can be any integer value, although not all sizes can be represented by
all font families on any particular output device. In general, the size used in a display will
be the closest available size to the one specied.
public FontTest () f
setTitle("Font Test") setSize(600, 150)
add("East", makeStyles())
add("South", makeNames())
g
that will set the size of the example text. The nal element is a quit button using the class
ButtonAdaptor dened earlier in Chapter 13.
private Panel makeStyles() f
Panel p = new Panel()
p.setLayout(new GridLayout(4,1))
p.add (new StyleBox(Font.ITALIC, "italic"))
p.add (new StyleBox(Font.BOLD, "bold"))
p.add (new SizeBox())
p.add (new ButtonAdaptor("Quit")f
public void run()fSystem.exit(0)gg)
return p
g
A StyleBox uses a trick we have seen earlier in Chapter 13. The class both extends the
library class Checkbox and implements the class ItemListener. Thus, the class can encapsulate
within itself both the creation of a Checkbox item and the task of listening when the
Checkbox has been selected. When each box is selected it either turns on or o the given
modier bits, depending upon the state of the box. Notice that when checkbooks are created
in this fashion, they are independent of each other, and can be set or unset individually.
(For example, both the bold and italic check box can be set, in order to display bold italic
output).
private class StyleBox extends Checkbox implements ItemListener f
private int modifiers
A SizeBox is a type of TextField, that when edited changes the size value in the application
class.
300 CHAPTER 19. UNDERSTANDING GRAPHICS
The method makeNames() illustrates the creation of a dierent type of check box. In
this form, only one of the collection can be set at any one time. Setting one item will
automatically unset all others. Such a group are sometimes referred to as radio buttons,
as they operation in a fashion similar to the buttons on a car radio. To create a radio
button collection, a CheckBoxGroup is created. This check box group is then passed with
the constructor to each check box that will be part of the group.
private class NameBox extends Checkbox implements ItemListener f
public NameBox (String name, CheckboxGroup cg)
f super(name, cg, false) addItemListener(this) g
When any button is pressed, the fontName eld will be changed, and the display method
activated.
19.4. IMAGES 301
19.4 Images
An image is really nothing more than a two dimensional collection of pixel values. Most
commonly images are created by some video device, just as a digital camera, and stored in
a le in a standard format, just as JPEG or GIF. A picture stored in such a format can be
read into a Java program by rst creating a URL (see Section 22.4.1), then using the toolbox
routine getImage. The following program illustrates this technique. The rst command line
argument is assumed to be a URL for a le stored in one of the standard formats. This
image is read from the le, and displayed as the value of the application window.
import java.awt.
import java.net.
19.4.1 Animation
Animation is simply the process of displaying a sequence of still pictures one after another.
Just as with a movie, the eye is fooled into linking the pictures together, giving the appear-
ance of smooth motion. The simplest animation program is shown below. Here a series of
302 CHAPTER 19. UNDERSTANDING GRAPHICS
GIF les are read into an array of images. The paint routine selects one of these for display,
then updates an index value so that the next image in sequence will be selected by the
following display. Calling repaint ensures that the next image will then be displayed.
class AnnTest extends Frame f
public AnnTest () f
setSize(300, 300)
setTitle("Simple Animation")
imageArray = new Image 17 ]
for (int i = 0 i < 17 i++) f
String name = "T" + (i+1) + ".gif"
try f
URL address = new URL (name)
imageArrayi] = getToolkit().getImage(address)
g catch (Exception e) f imageArrayi] = null g
g
g
In order to slow the animation down, the paint routine will sleep for 200 milliseconds after
drawing the image. On some platforms the animation will show an annoying icker. This
is because the procedure update, called by repaint, will redraw the screen in the background
19.5. GRAPHICS CONTEXTS 303
color before calling paint. This can sometimes be eliminated by simply overriding the method
update to avoid redrawing the background:
// override update to simply paint window
public void update (Graphics g) f
paint(g)
g
Shape, which will do double duty as both a button listener class, and a recording of the
currently selected shape. When pressed, the button will simply save its value in the variable
currentShape. In addition to representing a button, each shape will know how to draw itself
in a rectangular region (Figure 19.8). The class Shape, as well as the drawing method, have
been declared abstract. This means that it is not possible to create an instance of the class
without rst subclassing. Furthermore, each subclass must implement the method draw.
The rst time the application is asked to draw its window, it copies the Image associated
with the application component into a variable named image. Thereafter, to render the
application window it is only necessary to draw the contents of this image.
Most applications that interact with the mouse need to recognize the mouse moving
down. Of these, a few (such as the current application) need to dierentiate between the
mouse going down and the mouse going up. Fewer still need to also track the position of
the mouse as it is moving. Because the latter action is relatively infrequent, the Java event
library separates this task into a dierent listener. A MouseListener tracks only mouse presses
and releases. A MouseMotionListener also tracks mouse movements, either while pressed or
not. The mouse class we created for this class implements both interfaces, by extending the
MouseAdaptor, and implementing the MouseMotionListener interface (Figure 19.9).
When the mouse is initially pressed, the location of the mouse press is saved in a pair if
local integer variables. A second pair of integer variables records the new location, and is
initially the same as the source location. As the mouse moves, the method mouseDragged is
306 CHAPTER 19. UNDERSTANDING GRAPHICS
class Paint extends Frame f
public static void main (String ] args)
f Frame world = new Paint() world.show() g
public Paint () f
setTitle("Paint")
setSize(400, 300)
public abstract void draw (Graphics g, int a, int b, int c, int d)
repeatedly executed. This method sets the graphical display mode to XOR, then repaints the
current shape using the old coordinate locations. The eect will be the erase the previous
image. The ending point locations are then set to the current mouse position, and the shape
redrawn. The eect is that the shape is continually erased and redrawn as the mouse is
moved. When the mouse is nally released, the method mouseReleased is executed. This
erases the old image one last time, changes the mode to paint, and draws the shape in its
nal location.
Exercises
1. Add buttons to the painting program described in Section 19.6 to create lled rectan-
gles and ovals, as well as the outline rectangles and ovals it currently produces.
2. Add a panel with three sliders for selecting colors, similar to the panel described in
Chapter 13. Use the colors selected by these sliders for the ll color in the gures you
added in the previous question.
3. By adding a KeyListener object, add the ability to enter text and have it displayed at
the current mouse location.
4. Add menu items to change the font and style of text values.
310 CHAPTER 19. UNDERSTANDING GRAPHICS
Chapter 20
Collection Classes
Collections are classes designed for holding groups of objects. Almost all nontrivial programs
need to maintain one or more collections of objects. Although the Java library provides only
a few dierent forms of collection, the features provided by these classes are very general,
making them applicable to a wide variety of problems. In this chapter we will rst describe
some of the basic concepts common to the collection classes, then summarize the basic
collections provided by Java, and nally describe a few container types that are not provided
by the standard library, but which can be easily constructed by the programmer.
311
312 CHAPTER 20. COLLECTION CLASSES
Integer wrapper
new Integer(int value) build Integer from int
Integer(String value) parse integer in String
intValue() value of Integer as int
toString() return decimal string representation of Integer
toBinaryString() return binary representation
toOctalString() return octal representation
toHexString() return hex representation
Character wrapper
new Character(char value) convert char to Character
charValue() return char value of Character
isLetter() determine if character is letter
isDigit() true if character is digit
Boolean wrapper
new Boolean (boolean value) convert boolean to Boolean
booleanValue () retrieve boolean value from Boolean
toString() generate string representation of boolean
Double wrapper
new Double(double) convert double to Double
new Double(String) construct Double from string
doubleValue() return double value of Double
In addition, many wrapper classes provide other useful functionality, such as the ability
to parse string values. A common way to covert a string containing an integer value literal
into an int, for example, is to use an Integer as a middle step:
String text = "123" // example string value
Integer val = new Integer(text) // rst convert to Integer
int ival = val.intValue() // then convert Integer to int
Figure 20.1 summarizes the most common wrapper classes and a few of their more useful
behaviors.
20.2. ENUMERATORS 313
20.2 Enumerators
All collections can be envisioned as a linear sequence of elements, however the particular
means used to access each element diers from one collection type to another. For example,
a vector is indexed using an integer position key, while a hash table can use any type of
object as a key. It is frequently desirable to abstract away these dierences, and access the
elements of the collection in sequence without regard to the technique used to obtain the
underlying values. This facility is provided by the Enumeration interface, and its various
implementations. The Enumeration interface species two methods:
hasMoreElements() A boolean value that indicates whether
or not there are any more elements to be enumerated
nextElement() Retrieves the next element in the enumeration
These two operations are used together to form a loop. The following, for example,
shows how all the elements of a hash table could be printed:
for (Enumeration e = htab.elements() e.hasMoreElements() ) f
System.out.println (e.nextElement())
g
With the exception of the array, all the collections provided by the Java library provide
a function that generates an enumeration. In addition, several other classes that are not
necessarily collections also support the enumeration protocol. For example, a StringTokenizer
is used to extract words from a string value. The individual words are then accessed using
enumeration methods. In Section 20.6.1 we will describe how the programmer can create a
new type of enumeration.
314 CHAPTER 20. COLLECTION CLASSES
The brackets can be written either after the variable name, or after the type. The
following, for example, is an equivalent declaration:
static public CardPile ] allPiles
Note that the array is the only collection in the Java library that requires the programmer
to specify the type of elements that will be held by the container. An important consequence
of this is that the array is the only collection that can maintain non-object types, such as
integers, booleans, or characters. Other containers hold their values as instances of class
Object, and can therefore only hold primitive values if they are surrounded by wrapper
classes (Integer, Double, and so on).
An array value is created, as are all values, using the new operator. It is only when the
array value is created that the size of the array is specied.
allPiles = new CardPile 13 ] // create array of 13 card piles
Arrays can also be created as an initialization expression in the original declaration. The
initialization expression provides the values for the array, as well as indicating the number
of elements.
int primes ] = f2, 3, 5, 7. 11, 13, 17, 19g
Elements of an array are accessed using the subscript operator. This is used both to
retrieve the current value held at a given position, and to assign a position a new value:
primes3] = primes2] + 2
20.4. THE VECTOR COLLECTION 315
Legal index values range from zero to one less than the number of elements held by
the array. An attempt to access a value with an out of range index value results in an
IndexOutOfBoundsException being thrown.
The integer eld length describes the number of elements held by an array. The following
loop shows this value being used to form a loop to print the elements in an array:
for (int i = 0 i < primes.length i++)
System.out.println("prime " + i + " is " + primesi])
Arrays are also cloneable (see Section 11.3.1). An array can be copied, and assigned to
another array value. The clone operation creates a shallow copy.
int numbers ]
numbers = primes.clone() // creates a new array of numbers
Because objects held by a Vector must be subclasses of Object, a vector can not be used
to hold primitive values, such as integers or oats. However, wrapper classes can be used
to convert such values into objects.
Table 20.1 summarizes the most useful operations provided by the Vector data abstrac-
tion. The class as been carefully designed so that it can be used in a variety of dierent
ways. The following sections describe some of the more common uses.
Size Determination
size() returns number of elements in collection
isEmpty() returns true if collection is empty
capacity() return current capacity of vector
setSize() set size of vector, truncating or expanding as necessary
Element Access
contains() determines whether a value is in this vector
rstElement() returns rst element of collection
lastElement() returns last element of collection
elementAt(index) returns element stored at given position
Insertion and Modication
addElement(value) add new value to end of collection
setElementAt(value, index) change value at position
insertElementAt(value, index) insert value at given index
Removal
removeElementAt(index) remove element at index, reducing size of vector
removeElement(value) remove all instances of value
removeAllElements() delete all values from vector
Search
indexOf(value) return index of rst occurrence
lastIndexOf(value) return index of last occurrence
Miscellaneous
clone() return shallow copy of vector
toString() return string representation of vector
or by using setSize. In the latter case a null value will be stored in any index locations that
have not previously been assigned a value:
Vector aVec = new Vector () // create a new vector
aVec.setSize (20) // allocate 20 locations, initially undened
Once sized, the value stored at any position can be accessed using the method elementAt,
while positions can be modied using setElementAt. Note that in the latter, the index of
the position being modied is the second parameter, while the value to be assigned to the
location is the rst parameter. The following illustrates how these functions could be used
to swap the rst and nal elements of a vector:
Object first = aVec.elementAt(0) // store rst position
aVec.setElementAt(aVec.lastElement(), 0) // store last in location 0
aVec.setElementAt(first, aVec.size()-1) // store rst at end
For sets consisting of positive integer values, the BitSet class (Section 20.6 is often a
more ecient alternative.
1 The assertion concerning constant time operation of stack operations is true with one small caveat. An
insertion can, in rare occasions, result in a reallocation of the underlying vector bu er, and thus require
time proportional to the number of elements in the vector. Thus is usually, however, a rare occurrence.
20.5. THE STACK COLLECTION 319
The search method returns the index of the given element starting from the top of the
stack that is, if the element is found at the top of the stack search will return 0, if found one
element down in the stack search will return 1, and so on. Because the Stack data structure
is built using inheritance from the Vector class it is also possible to access the values of
the stack using their index. However, the positions returned by the search operation do
not correspond to the index position. To discover the index position of a value the Vector
operation indexOf can be used.
In Chapter 10 we described some of the advantages and disadvantages of creating the
stack using inheritance from class Vector.
The following table summarizes the operations used to set or test an individual position
in the bit set:
set a bit position bset.set (index)
test a bit position bset.get (index)
clear a bit position bset.clear (index)
The get method returns a boolean value, which is true if the given bit is set, and false
otherwise. Each of these operations will throw an IndexOutOfBoundsException if the index
value is smaller than zero.
A BitSet can be combined with another BitSet in a variety of ways:
Form bitwise union with argument set bset.or(setTwo)
Form bitwise intersection with argument set bset.and(setTwo)
Form bitwise symmetric dierence with argument set bset.xor(setTwo)
The method toString returns the string representation of the collection. This consists of
a comma-separated list of the indices of the bits in the collection that have been set.
20.7. THE DICTIONARY INTERFACE AND THE HASHTABLE COLLECTION 321
import java.util.
the collection, an integer value, called the hash value, is rst computed for the given key.
The method hashCode is used for this purpose. This method is dened in class Object,
and is therefore common to all object values. It is overridden in various classes to provide
alternative algorithms. Using this integer, one of the buckets is selected and the key/value
pair inserted into the corresponding collection.
In addition to the methods matching the Dictionary specication, the hash table provides
the method clear(), which removes all values from the container, contains(value), which
determines whether an element is contained in the collection, and containsKey(key), which
tests to see if a given key is in the collection.
The default implementation of the hashCode method, in class Object, should be applicable
in almost all situations, just as the default implementation of equals is usually adequate. If
a data type that is going to be used as a hash table key overrides the equals method, it is a
good idea to also override hashCode, so that two objects that test equal to each other will
also have the same hash value.
class Concordance f
private Dictionary dict = new Hashtable()
second exceptional condition, which will occur if the same word appears two or more times
on one line.) If not, the line is then added to the list.
Finally, once all the input has been processed, the method generateOutput is used to
create the printed report. This method uses a doubly-nested enumeration loop. The rst
loop enumerates the keys of the Dictionary, generated by the keys method. The value asso-
ciated with each key is a set, represented by a Vector. A second loop, using the enumerator
produced by the elements method, then prints the values held by the vector.
An easy way to test the program is to use the system resources System.in and System.out
as the input and output containers, as in the following:
20.7.2 Properties
The Java run-time system maintains a special type of hash table, termed the properties list.
The class Properties, a subclass of Hashtable, holds a collection of string key/value pairs.
These represent values the describe the current executing environment, such as the user
name, operating system name, home directory, and so on. The following program can be
used to see the range of properties available to a running Java program:
g
326 CHAPTER 20. COLLECTION CLASSES
One could then create a collection in which all values need to implement the Ordered
interface, rather than simply being Object. However, there are two major objections to
this technique. The rst is that since the argument is only known to be an object that
implements the Ordered interface, one must still decide how to compare objects of dierent
types (a Triangle and an Orange, for example). The second problem is that by restricting the
type of objects the collection can maintain to only those values that implement the Ordered
relation, one severely limits the utility of the classes.
Another possibility is to imagine an interface for an object that is used to create com-
parisons. That is, the object takes both values as arguments, and returns their ordering.
Such an interface could be written as follows:
interface ComparisonObject f
public boolean Compare (Object one, Object two)
g
20.8. WHY ARE THERE NO ORDERED COLLECTIONS? 327
The following program illustrates how such an object could be used. The static method
sort is an implementation of the insertion sort algorithm. The main method creates a vector
of integer values, then creates a comparison object to be passed as argument to the sort
algorithm. The sorting algorithm orders the elements in place, using the comparison object
to determine the relative placement of values.
class VectorSort f
public static void sort (Vector v, ComparisonObject test) f
// order a vector using insertion sort
int n = v.size()
for (int top = 1 top < n top++) f
for (int j = top-1 j >= 0 &&
test.Compare(v.elementAt(j+1), v.elementAt(j)) j--) f
// swap the elements
Object temp = v.elementAt(j+1)
v.setElementAt(v.elementAt(j), j+1)
v.setElementAt(temp, j)
g
g
public LinkedList ()
f firstLink = lastLink = new Link(null, null, null) g
yielded by nextElement) the programmer may wish to either insert a new value or remove
the current value. Thus, in this case the task of advancing to the next value is given to the
method hasMoreElements.
Study Questions
1. What are collection classes used for?
2. Because the standard library collection classes maintain their values as an Object,
what must be done to a value when it is removed from a collection?
3. What is a wrapper class?
4. What is an enumerator?
5. What is the protocol for the class Enumerator? How are these methods combined to
form a loop?
6. How is the Java array dierent from arrays in other languages?
7. What does it mean to say that the Vector data type is expandable?
8. How does the use of the Stack data type dier from the use of a Vector as a stack?
9. What concept does the class BitSet represent?
10. What is the relationship between the classes Dictionary and Hashtable?
11. Why are there no ordered collections in the Java library?
Exercises
1. Assume two sets are implemented using vectors, as described in Section 20.4.4. Write
a loop that will place the intersection of the two sets into a third set.
2. Assume two sets are implemented using vectors, as described in Section 20.4.4. Write
a loop that will place the symmetric dierence of the two sets into a third set. (The
symmetric dierence is the set of elements that are in one or the other set, but not
both).
3. Add the following methods to the LinkedList class described in Section 20.9:
4. Modify the LinkedList class of Section 20.9 so that linked lists support the cloneable
interface. (The cloneable interface is described in Section 11.3.1).
5. Write an OrderedList class. This class will be like a linked list, but will maintain a
comparison object, as described in Section 20.8. Using this object, elements will be
placed in sequence as they are inserted into the container.
Chapter 21
In Java, threads are created using the class Thread. There are two common ways that
this class is used. One way is to subclass from Thread, and override the method run, which is
the class that is executed to perform the task assigned to a thread. We could, for example,
modify the BallWorld application (Figure 5.1) and create a bouncing ball thread as follows:
public class ThreadedBallWorld extends Frame f
...
private class BallThread extends Thread f
public void run () f
while (true) f
aBall.move()
if ((aBall.x() < 0) jj (aBall.x() > FrameWidth))
aBall.setMotion (-aBall.xMotion(), aBall.yMotion())
if ((aBall.y() < 0) jj (aBall.y() > FrameHeight))
aBall.setMotion (aBall.xMotion(), -aBall.yMotion())
repaint()
try f
sleep(50)
g catch (InterruptedException e) f g
g
g
g
...
g
When started, the thread continually moves the ball, changing the direction of motion
when the sides of the window are hit. Each time the ball moves the window is repainted,
and the thread sleeps for 50 milliseconds.
The revised ball world application is shown in Figure 21.1. In the constructor for the
application ThreadedBallWorld a Ball is created, and then a BallThread is produced to control
the movement of the ball. Execution of the new thread is initiated by the call to start for the
thread object. To illustrate that the user can now interact with the application as the ball
moves, we have added a mouse listener object. When the mouse is clicked in the application
window, the ball is moved to the mouse location.
Platforms dier on how they assign time to threads. On some systems threads are run
until they sleep or until they yield to another thread. On other systems threads are given
a xed amount of time to execute, then halted automatically if they have not yet given up
control when their time unit is nished. In order to provide maximum portability, threads
should either sleep occasionally (as in done here) or periodically invoke the method yield
that is inherited from class Thread. Either of these actions will halt the current thread,
allowing other threads a chance to perform their actions.
21.1. CREATING THREADS 335
It is sometimes not convenient to create a thread class by subclassing from Thread. For
example, it can happen that the tread class is already inheriting from some other class.
Since in Java a class can not extend from two classes, the designers of the language have
provided an alternative technique. Instead of inheriting from Thread, the action portion of
a thread can be declared as implementing the interface Runable. The ball thread could be
rewritten in this form as follows:
Note the format used for the call on sleep. Because the new class is not tied to Thread,
the method sleep is not be automatically inherited. Instead, the class name Thread must be
explicitly provided in this case.
Starting a thread in this case involves creating two objects. The rst is the instance
of Runable, which describes the actions to be performed. The second is the Thread object,
which understands how to schedule the actions for execution. The Runable object is passed
as argument to the Thread, as in the following:
Assume that these same sequence of instructions are performed by two threads, and the
original value of a is 50. Assume further than the thread that is running the rst process is
stopped immediately after the rst push instruction above. The rst thread will push the
value 50 on its stack, then stop temporarily. The second thread will push the value 50 on its
stack, increment by ten, then store the resulting value of 60 on its stack. Suppose now the
rst thread is restarted. It will continue with its actions, pushing 10 on the stack, adding
the two values, and assigning the sum, 60, back to a. The end result will be that the value
a will ultimately hold 60, not the value 70 that it should have held.
Although it might seem that a problem such as this might be rare, the speed with which
computers execute means that a situation such as that described here, if possible at all, is
not at all uncommon. Such errors are also exceedingly dicult to uncover, since they occur
in such a rare situation. Fortunately, the designers of Java have foreseen this and provided a
simple and elegant solution. A method that is declared as synchronized cannot be executed
by two processes at the same time. That is, if one thread is executing a synchronized method
and a second thread tries to execute any other synchronized thread with the same object, the
second thread will be halted until the rst thread completes. The solution to the problem
just described is therefore to place the increment operation inside a method that is declared
as synchronized:
public synchronized void increment () f
// only one thread can execute this
// at any time
a = a + 10
g
We will illustrate the use of a synchronized method in the case study presented in
Section 21.2. There are many more advanced features of threads, however they are generally
338 CHAPTER 21. MULTIPLE THREADS OF EXECUTION
' $ ' $
& % & %
Of course, there must be some sort of communication between the two threads, and this
is where most of the complexity in multithreaded programming occurs. In the Tetris game
presented here, the communication consists only of one integer value, which maintains the
next command to be performed.
In addition to demonstrating multiple threads of control, the Tetris game presented in
this section will illustrate how to read keyboard events, and an important technique for
preventing ickering in graphical displays.
21.2. CASE STUDY: A TETRIS GAME 339
// data elds
public static final int FrameWidth = 300
public static final int FrameHeight = 400
private GamePlay player
public Tetris () f
setSize (FrameWidth, FrameHeight)
setTitle("Tetris")
As with mouse presses, the programmer can elect to either treat a key press and the key
release as independent events, or simply examine one event for both actions. Implementing
the KeyListener interface requires dening a procedure for all three methods. As normally
one is only interested in one of these, an adapter class, named KeyAdaptor, is provided that
implements a null procedure for each of the three functions. To create a listener one can
subclass from this adapter, and redene the meaning of one of the methods. This is how
key presses are handled in our application:
class Tetris extends Frame f
...
private class keyDown extends KeyAdapter f
public void keyPressed (KeyEvent e) f
char key = e.getKeyChar()
switch (key) f
case g : player.newGame() break
case j : getCommand(Piece.Left) break
342 CHAPTER 21. MULTIPLE THREADS OF EXECUTION
Avoiding Flicker
As the game is being played, the screen is constantly being updated. This update process
consists largely of drawing each individual square of the display. If this is done as separate
graphical commands, the result can be an annoying icker. There are several common ways
to avoid this. Perhaps one of the easiest is the technique shown here. The method update()
inherited from class Component normally rst redraws the entire screen in the background
color, then invokes paint to refresh the screen. If rather than overriding paint, one overrides
update, then the redrawing in the background color is avoided.
One often confusing feature to note is that although the update procedure invokes the
paint procedure in the class of the player object (namely, the class PieceMover) the resulting
actions are not performed by the piece mover thread. Updating the image is performed by
the rst thread, and is independent of the piece mover thread, which continues to run on
its own.
// other methods
public void newGame () f
for (int i = 0 i < 30 i++)
for (int j = 0 j < 15 j++)
tablej]i] = Color.white
g
The heart of the piece movement thread is the function dropPiece. This procedure creates
a new piece, selecting the type of piece randomly from among the seven possibilities. If the
piece cannot be moved downward once initially created at the top of the scene, the game is
over, and the procedure returns false. Otherwise, a loop then reads the commands placed
in the buer shared with the controller, and acts on them, passing the command value to
the individual piece for action. After every move the controller is asked to repaint, and
control of the processor is yielded, allowing the other process time to execute. When control
is returned, the piece movement process still sleeps for 100 milliseconds, before reading the
next command and moving once more.
private boolean dropPiece ()
f
int piecetype = 1 + (int) (7 Math.random ())
currentPiece = new Piece (piecetype)
if (! currentPiece.move (Piece.Down, table))
return false
int command = controller.getCommand (Piece.Down)
while (currentPiece.move (command, table)) f
controller.repaint ()
yield ()
try f
sleep (100)
g catch (InterruptedException e) f g
command = controller.getCommand (Piece.Down)
g
// piece cannot move, check score
checkScore()
return true
g
21.2. CASE STUDY: A TETRIS GAME 345
The while loop terminates when the piece can no longer move. At this point the procedure
checkScore is called to determine if any points have been scored. Points are scored by
completely lling a row. If such a row is found, the controller is notied that a score has
been made, and the entire image is moved downward.
private void checkScore()
f
for (int i = 0 i < 30 i++) f
boolean scored = true
for (int j = 0 j < 15 j++)
if (tablej]i] == Color.white)
scored = false
if (scored) f
score += 10
moveDown(i)
i = i - 1 // check row again
g
g
g
The procedure moveDown copies the colors from the row above into the current row,
copying white values into the topmost row.
class Piece f
// data elds
private int x]
private int y]
private Color color
// moves
public static final int Down = 1
public static final int Left = 2
public static final int Rotate = 3
public static final int Right = 4
// constructor
public Piece (int type)
f
switch(type) f
case 1: // s shaped piece
x = new int4]
y = new int4]
x0] = 7 y0] = 29
x1] = 7 y1] = 28
x2] = 8 y2] = 28
x3] = 8 y3] = 27
color = Color.green
break
...
g
g
...
g
given. The function returns false if the command is a move down and the piece cannot
move, which indicates that no further actions are possible.
class Piece f
...
public boolean move (int command, Color ]] table)
f
erase(table)
boolean canDoIt = false
switch (command) f
case Down: canDoIt = testDown(table) break
case Right: canDoIt = testMoveRight(table) break
case Left: canDoIt = testMoveLeft(table) break
case Rotate: canDoIt = testRotate(table) break
g
if (canDoIt)
switch (command) f
case Down: moveDown() break
case Right: moveRight() break
case Left: moveLeft() break
case Rotate: moveRotate() break
g
draw(table)
if (command == Down)
return canDoIt
return true
g
g
Erasing and redrawing the piece are performed by transferring colors to the color table:
class Piece f
...
private void erase (Color ]] table)
f
for (int i = 0 i < x.length i++)
tablexi]]yi]] = Color.white
g
tablexi]]yi]] = color
g
g
Before any command is performed, a test is conducted to see if the spaces the blocks
will occupy subsequent to the command are open. The following demonstrates one of these
routines, the others are similar. If the target locations are open, the corresponding move
routine performs the actual transformation.
class Piece f
...
private boolean testPosition (int x, int y, Color]] table)
f
if ((x < 0) jj (x > 14))
return false
if ((y < 0) jj (y > 29))
return false
if (tablex]y] != Color.white)
return false
return true
g
The only tricky procedure is the rotation. One square, the square at position 1, is des-
ignated the square around which rotation will be performed. The dierences in coordinate
from this square are computed, and the updated coordinates determined.
class Piece f
21.2. CASE STUDY: A TETRIS GAME 349
...
private boolean testRotate (Color ]] table)
f
for (int i = 0 i < x.length i++) f
int dx = xi] - x1]
int dy = yi] - y1]
int nx = x1] + dy
int ny = y1] - dx
if (! testPosition(nx, ny, table))
return false
g
return true
g
g
Cross References
The ball world case study appears originally in Chapter 5. Placing balls in their own thread
of control is also shown in the pin ball game application described in Chapter 7.
Study Questions
1. What is the dierence between multitasking and multithreading?
2. Describe the two ways to create a new thread.
3. What are the two ways described in this chapter to temporarily halt the execution of
a thread?
4. When used in a method heading, what does the keyword synchronized mean?
Exercises
1. Add a keyboard listener to the ball world application shown in Figure 21.1. When the
user types the keys u or d, change the ball direction to move upwards or downwards,
respectively. When the user types q quit the application.
2. Change the mouse down procedure so that when the user presses the mouse a new
ball is created and set in motion. To do this you will need to create a collection of ball
objects (see Chapter 5). Each new object should execute in its own separate thread.
350 CHAPTER 21. MULTIPLE THREADS OF EXECUTION
3. The Tetris game can be made to \speed up" by reducing the amount of time the piece
mover sleeps between commands. Change the code so that this time is reduced by 5
milliseconds for every 100 points the user scores.
4. Change the program so that instead of scoring 10 points for each lled row, the player
gets additional points for multiple rows scored with the name piece. For example, a
second row will get 20 points, a third row 30 points, and a fourth row 40 points.
5. Change the program to score 50 extra points if an entirely lled row is all one color.
Chapter 22
The <applet> tag indicates the address of the Java program. The codebase parameter
gives the URL web address where the Java program will be found, while the code parameter
provides the name of the class. The height and width attributes tell the browser how much
space to allocate to the applet.
351
352 CHAPTER 22. APPLETS AND WEB PROGRAMMING
Just as users can pass information into an application using command line arguments,
applets can have information passed into them using the <param> tags. Within an applet
the values associated with parameters can be accessed using the method getParameter().
Any code other than a <param> tag between the beginning and end of the <applet>
tag is displayed only if the program cannot be loaded. Such text can be used to provide the
user with alternative information.
Rather than starting execution with a static function named main, as applications do,
applets start execution at a function named init, which is dened in class Applet but can
be overridden by users. The procedure init is one of four routines dened in Applet that is
available for overriding by users. These four can be described as follows:
init() Invoked when an applet is rst loaded for example, when a web page containing the
applet is rst encountered. This method should be used for one-time initialization.
This is similar to the code that would normally be found in the constructor for an
application.
start() Called to begin execution of the applet. Called again each time the web page con-
taining the applet is exposed. This can be used for further initialization, or restarting
the applet when the page on which it appears is made visible after being covered.
stop() Called when a web page containing an applet is hidden. Applets that do extensive
calculations should halt themselves when the page on which they are located becomes
covered, so as to not occupy system resources.
destroy() Called when the applet is about to be terminated. Should halt the application
and free any resources being used.
For example, suppose a web page containing an applet as well as several other links
is loaded. The applet will rst invoke init(), then start(). If the user clicks on one of the
links, the web page holding the applet is overwritten, but it is still available for the user
to return to. The method stop() will be invoked to temporarily halt the applet. When the
user returns to the web page, the method start(), but not init(), will once again be executed.
This can happen many times before the user nally exits altogether the page containing the
applet, at which time the method exit() will be called.
Figure 22.1 shows portions of the painting application described in Section 19.6, now
written as an applet rather than as an application. In place of the main procedure, the applet
contains an init procedure. The init takes the place both of main and of the constructor
for the application class. Other aspects of the applet are the same. Because an applet
is a subclass of Panel, events are handed in exactly the same fashion as other graphical
components. Similarly, an applet repaints the window in exactly the same fashion as an
application. Because an applet is a panel, it is possible to embed components and construct
a complex graphical interface (see Chapter 13). Note, however that the default layout
manager for an Applet is a ow layout, rather than the border layout that is default to
applications.
import java.applet.
import java.awt.
import java.awt.event.
...
image stored in the given location. The URL must specify a le in jpeg or gif format. The
method getAudioClip(URL) similarly returns an audio object from the given location. The
audioClip can subsequently be asked to play itself. A shorthand method play(URL) combines
these two features.
The method getCodeBase() return the URL for the codebase specied for the applet
(see the earlier discussion on HTML tags). Since Java programs are often stored in the
same location as associated documents, such as gif les, this can be useful in forming URL
addresses for related resources.
The method getParameter() takes as argument a String, and returns the associated value
(again, as a string) if the user provided a parameter of the given name using a <param>
tag. A null value is returned if no such parameter was provided.
class ReadURL f
public static void main (String ] args) f
try f
URL address = new URL(args0])
DataInputStream in =
new DataInputStream(address.openStream())
String line = in.readLine()
356 CHAPTER 22. APPLETS AND WEB PROGRAMMING
If you run the program, you should see the HTML commands and textual content dis-
played for the web page given as argument.
Once should trace carefully the sequence of operations being performed here, and the
order that objects are created. Since the Frame is nested within the Applet, it is only possible
to create the frame (in the method application) after the applet has already been created.
Exercises
1. Convert the pin ball game described in Chapter 7 to run as an applet, rather than as
an application.
2. Convert the Tetris game described in Chapter 21 to run as an applet, rather than as
an application.
358 CHAPTER 22. APPLETS AND WEB PROGRAMMING
Glossary
abstract A keyword applied to either a class or a method. When applied to a class, the
keyword indicates that no instances of the class can be created, and the class is used
only as a parent class for subclassing. When applied to a method within an abstract
class, it indicates that the method must be overridden in subclasses before any instance
of the subclass can be created.
abstract class Syn. deferred class, abstract superclass. A class that has been declared
using the abstract keyword. Classes can be declared to be abstract even if they do not
contain any abstract methods.
abstract method A method that has been declared using the abstract keyword. Abstract
methods can only appear in classes that have themselves been declared as abstract.
abstraction A technique in problem solving in which details are grouped into a single
common concept. This concept can then be viewed as a single entity and nonessential
information ignored.
access specier A keyword (private, protected, or public) that controls access to data mem-
bers and methods within user-dened classes.
accessor function A function that is used to access the values of an instance variable.
By restricting access through a function, the programmer can ensure that instance
variables will be read but not modied (see mutator).
ad hoc polymorphism Syn. overloading. A procedure or method identier that denotes
more than one procedure.
agent Syn. object, instance. A nontechnical term sometimes used to describe an object
in order to emphasize its independence from other objects, and the fact that it is
providing a service to other objects.
argument signature An internal encoding of a list of argument types the argument sig-
nature is used to disambiguate overloaded function invocations, with that function
359
360 GLOSSARY
body being selected that matches most closely the signature of the function call. See
parameteric overloading.
automatic storage management A policy in which the underlying run-time system is
responsible for the detection and reclamation of memory values no longer accessible,
and hence of no further use to the computation. See garbage collection.
base class Syn. ancestor type, superclass, parent class. A class from which another class
is derived.
binding The process by which a name or an expression is associated with an attribute,
such as a variable and the type of value the variable can hold.
binding time The time at which a binding takes place. Early or static binding generally
refers to binding performed at compile time, whereas late or dynamic binding refers
to binding performed at run time.
bytecode The assembly language for an imaginary Java virtual machine. So-called because
most instructions can be encoded in a form that is one or two bytes in length.
cast A unary expression that converts a value from one type to another.
child class Syn. subclass, derived class. A class dened as an extension of another class,
which is called the parent class.
class Syn. object type. An abstract description of the data and behavior of a collection of
similar objects. The representatives of the collection are called instances of the class.
Class The class that maintains behavior related to class instance and subclass creation. See
metaclass.
class hierarchy A hierarchy formed by listing classes according to their class-subclass
relationship. See hierarchy.
client-side computing In a network environment, a program that is executed on the client
side rather than on the server side of the network. The Java programming language
is intended to perform client-side computing and so is more ecient than programs
that must wait for execution on the (generally more overloaded) server machine.
cohesion The degree to which components of a single software system (such as members
of a single class) are tied together. Contrast with coupling.
collaborator Two classes which dependend upon each other for the execution of their
behaviors are said to be collaborators.
collection classes Classes used as data structures that can contain a number of elements.
Examples include Vector, Stack, Hashtable and arrays.
GLOSSARY 361
composition The technique of including user-dened object types as part of a newly de-
ned object, as opposed to using inheritance.
constructor A method used to create a new object. The constructor handles the dual tasks
of allocating memory for the new object and ensuring that this memory is properly
initialized. The programmer denes how this initialization is performed. In Java a
constructor has the same name as the class in which it appears.
contravariance A form of overriding in which an argument associated with a method in
the child class is restricted to a less general category than the corresponding argument
in the parent class. Contrast with covariance. Neither covariant nor contravariant
overriding is common in object-oriented languages.
coupling The degree to which separate software components are tied together. Contrast
with cohesion.
covariance A form of overriding in which an argument associated with a method in the
child class is enlarged to a more general category than the corresponding argument in
the parent class. Contrast with contravariance. Neither covariant nor contravariant
overriding is common in object-oriented languages.
CRC card An index card that documents the name, responsibilities, and collaborators for
a class, used during the process of system analysis and design.
data hiding An encapsulation technique that seeks to abstract away the implementation
details concerning what data values are maintained for an object to provide a particular
service.
data member See instance variable.
deferred class See abstract class.
derived class Syn. descendant type, subclass, child class. A class that is dened as an
extension or a subclass of another class, which is called the base class.
descendant type Syn. subclass, child class. See derived class.
early binding See binding time.
encapsulation The technique of hiding information within a structure, such as the hiding
of instance data within a class.
event driven execution A style of programming where the program largely responds to
user generated events, such as a mouse click or a keypress.
362 GLOSSARY
exception An unusual condition that prevents the normal sequence of instructions from
going onwards. An example would be attempting to use a uninitialized value (a null
value) as the target of a message passing expression.
exception handler The portion of a Java program devoted to handling the processing of
exceptions.
extends A keyword used in forming a new class as a subclass of an existing class, or a new
interface as an extension of an existing interface.
nal A keyword used in forming either a nal class or a nal method within a class.
nal class A class declared using the keyword nal. This keyword indicates that the class
cannot be used as a base class for inheritance.
nal method A method declared using the keyword nal. This keyword indicates that the
method cannot be overridden in subclasses.
nalizer A method with the name nalize, no arguments, and no return type. This method
will be invoked automatically by the run-time system prior to the object in which it
is declared being recycled by garbage collection.
function member See method.
garbage collection A memory management technique whereby the run-time system de-
termines which memory values are no longer necessary to the running program, and
automatically recovers and recycles the memory for dierent use.
has-a relation The relation that asserts that instances of a class possess elds of a given
type. See is-a relation.
hierarchy An organizational structure with components ranked into levels of subordination
according to some set of rules. In object-oriented programming the most common
hierarchy is that formed by the class-subclass relationship.
immediate superclass The closest parent class from which a class inherits. The superclass
relationship is a transitive closure of the immediate superclass relationship.
immutable value A value that is not permitted to change once it has been set. Variables
that hold such values are sometimes called \single-assignment" variables. In Java
immutable values can be identied via the keywords nal and static.
implements A keyword used to indicate that a class provides the behavior described by an
interface.
GLOSSARY 363
information hiding The principle that users of a software component (such as a class)
need to know only the essential details of how to initialize and access the component,
and do not need to know the details of the implementation. By reducing the degree
of interconnectedness between separate elements of a software system, the principle of
information hiding helps in the development of reliable software.
inheritance The property of objects by which instances of a class can have access to
data and method denitions contained in a previously dened class, without those
denitions being restated. See ancestor class.
inheritance graph An abstract structure that illustrates the inheritance relationships
with a collection of classes.
inner class A class denition that appears inside another class. Inner classes are allowed
access to both the data elds and methods of the surrounding class. Inner classes are
used frequently in building listener objects for handling events.
instance Syn. object.
instance variable An internal variable maintained by an instance. Instance variables rep-
resent the state of an object.
interaction diagram A diagram that documents the sequence of messages that ow be-
tween objects participating in a scenario.
interface A description of behavior. Classes that claim to implement the interface must
provide the services described by the interface.
Internet A world-wide collection of machines that have agreed to communicate with each
other using a common protocol.
is-a relation The relation that asserts that instances of a subclass must be more specialized
forms of the superclass. Thus, instances of a subclass can be used where quantities of
the superclass type are required. See has-a relation.
interpreter A computer program that simulates the actions of the imaginary Java virtual
machine. The interpreter examines and executes the bytecode representation of a Java
program.
iterator A class that is used mainly to provide access to the values being held in another
class, usually a container class. The iterator provides a uniform framework for access-
ing values, without compromising the encapsulation of the container.
JIT An acronym for Just In Time compiling. A technique whereby immediately before
a program is execute the device independent bytecode representation of a Java pro-
gram is converted into machine code for a specic platform. The machine code rep-
resentation will often execute much faster than an interpreter running the bytecode
representation.
364 GLOSSARY
procedure call The transfer of control from the current point in execution to the code
associated with a procedure. Procedure calling diers from message passing in that
the selection of code to be transferred to is decided at compile time (or link time)
rather than run time.
protocol See class description protocol.
pseudo-variable A variable that is never declared but can nevertheless be used within
a method, although it cannot be directly modied (a pseudo-variable is therefore by
denition read-only). The most common pseudo-variable is used to represent the
receiver of a method. See this, and super.
public class A class that is global and can be accessed from other packages. One public
class may be declared in each compilation unit.
public method A method that can be invoked at any time from outside an object.
pure polymorphism A feature of a single function that can be executed by arguments of
a variety of types. See ad hoc polymorphism.
rapid prototyping A style of software development in which less emphasis is placed on
creation of a complete formal specication than on rapid construction of a prototype
pilot system, with the understanding that users will experiment with the initial system
and suggest modications or changes, probably leading to a complete redevelopment
of a subsequent system. See exploratory programming.
receiver The object to which a message is sent. The receiver is the object to the left of
the eld qualier (period). Within a method, the current receiver is indicated by the
variable this.
redenition The process of changing an inherited operation, to provide dierent or ex-
tended behavior.
renement A style of overriding in which the inherited code is merged with the code
dened in the child class.
replacement A style of overriding in which the inherited code is completely replaced by
the code dened in the child class.
responsibility-driven design A design technique that emphasizes the identication and
division of responsibilities within a collection of independent agents.
scope When applied to a variable identier, the (textual) portion of a program in which
references to the identier denote the particular variable.
selector See message selector.
GLOSSARY 367
shadowed name A name that matches another name in a surrounding scope the new
name eectively makes the surrounding name inaccessible. An example is a local
variable with the same name as that of a global or instance variable. Within the
procedure, the local variable will be attached to all references of the name, making
references to the surrounding name dicult. In Java access to such values can be
provided by a fully qualied name.
single-assignment variable A variable the value of which is assigned once and cannot be
redened. In Java single assignment variables can be created using the keyword nal.
static A declaration modier that, when applied to instances variables and functions, means
that the variables and functions are shared by all instances of a class, and exist even
when no instances have yet been created.
static method A method that is declared static. Since such functions exist even when no
instances have been created, they can be invoked using the class name as receiver.
strongly typed language A language in which the type of any expression can be deter-
mined at compile time.
subclass Syn. descendant type, derived class, child class.
subclass coupling The connection formed between a parent and child class. Subclass
coupling is a very weak form of coupling, since instances of the subclass can be treated
as though they were simply instances of the parent class. See coupling and cohesion.
substitutability, principle of The principle that asserts one should be able to substitute
an instance of a child class in a situation where an instance of the parent class is
expected. The principle is valid if the two classes are subtypes of each other, but not
necessarily in general.
subtype A type A is said to be a subtype of a type B if an instance of type A can be
substituted for an instance of type B with no observable eect. For example, a sparse
array class might be dened as a subtype of an array type. Subclasses need not be
subtypes, nor must subtypes be subclasses.
super When used inside a method, a synonym for self. However, when used as the receiver
for a message, the search for an appropriate method will begin with the parent class
of the class in which the current method is dened.
superclass Syn. ancestor class, base class. A class from which another class inherits
attributes.
this When used inside a method, a reference to the receiver for the message that caused
the method to be invoked.
368 GLOSSARY
virtual machine An imaginary Java machine. Java programs are translated into assembly
language instructions for this imaginary machine. To execute a Java program, an
actual computer must simulate the working of the virtual machine.
void A type name used to indicate a function returning no value{that is, a procedure.
World Wide Web A collection of machines on the Internet that have agreed to distribute
information according to a common protocol. This information is usually accessed
with a browser.
yo-yo problem Repeated movements up and down the class hierarchy may be required
when the execution of a particular method invocation is traced.
Bibliography
Actor 1987] Actor Language Manual, The Whitewater Group, Inc., Evanston, IL,
1987.
Beck 1989] Kent Beck and Ward Cunningham, \A Laboratory for Teaching
Object-Oriented Thinking," Proceedings of the 1989 OOPSLA|
Conference on Object-Oriented Programming Systems, Languages and
Applications Reprinted in Sigplan Notices, 24(10): 1{6, 1989.
Bellin 97] David Bellin and Susan Suchman Simone, The CRC Card Book,
Addison-Wesley, Reading, MA, 1997.
Budd 97] Timothy A. Budd, An Introduction to Object-Oriented Programming,
2nd Ed, Addison-Wesley, Reading, MA, 1997.
Cardelli 1985] Luca Cardelli and Peter Wegner, \On Understanding Types, Data
Abstraction, and Polymorphism," Computing Surveys, 17(4): 471{
523, 1985.
Chan 96] Patrick Chan and Rosanna Lee, The Java Class Libraries: An Anno-
tated Reference, Addison-Wesley, Reading, MA, 1996.
Cox 1986] Brad J. Cox, Object Oriented Programming: An Evolutionary Ap-
proach, Addison-Wesley, Reading, MA, 1986.
Cox 1990] Brad J. Cox, \Planning the Software Industrial Revolution," IEEE
Software, 7(6): 25{35, November 1990.
Dahl 1966] Ole-Johan Dahl and Kristen Nygaard, \Simula, An Algol-Based Sim-
ulation Language," Communications of the ACM, 9(9): 671-678,
September 1966.
Danforth 1988] Scott Danforth and Chris Tomlinson, \Type Theories and Object-
Oriented Programming," ACM Computing Surveys, 20(1): 29{72,
1988.
369
370 BIBLIOGRAPHY
Milner 1990] Robin Milner, Mads Tofte, and Robert Harper, The Denition of
Standard ML, MIT Press, Cambridge, MA, 1990.
Morehead 1949] Albert H. Morehead and Georey Mott-Smith, The Complete Book
of Solitaire and Patience Games, Grosset & Dunlap, New York, 1949.
Pinson 1988] Lewis J. Pinson and Richard S. Wiener, An Introduction to Object-
Oriented Programming and Smalltalk, Addison-Wesley, Reading, MA,
1988.
Sethi 1989] Ravi Sethi, Programming Languages: Concepts and Constructs,
Addison-Wesley, Reading, MA, 1989.
Stroustrup 1988] Bjarne Stroustrup, \What is `Object-Oriented Programming?' "
IEEE Software, 5(3): 10{20, May 1988.
Taenzer 1989] David Taenzer, Murthy Ganti, and Sunil Podar, \Object-Oriented
Software Reuse: The Yoyo Problem," Journal of Object-Oriented Pro-
gramming, 2(3): 30{35, 1989.
Wegner 1986] Peter Wegner, \Classication in Object-Oriented Systems," Sigplan
Notices, 21(10): 173{182, October 1986.
Wikstr%om 1987] &
Ake Wikstr%om, Functional Programming Using Standard ML,
Prentice-Hall International, London, 1987.
Wirfs-Brock 1989b] Rebecca Wirfs-Brock and Brian Wilkerson, \Object-Oriented De-
sign: A Responsibility-Driven Approach," Proceedings of the 1989
OOPSLA|Conference on Object-Oriented Programming Systems,
Languages and Applications Reprinted in Sigplan Notices, 24(10):
71{76, October 1989.
Wirfs-Brock 1990] Rebecca Wirfs-Brock, Brian Wilkerson, and Lauren Wiener, Design-
ing Object-Oriented Software, Prentice-Hall, Englewood Clis, NJ,
1990.
Wulf 1972] William A. Wulf, \A Case Against the GOTO," Proceedings of the
Twenty-Fifth National ACM Conference, 1972 Reprinted in Edward
Yourdon (Ed) Classics in Software Engineering, Prentice-Hall, En-
glewood Clis, NJ, 1979.