Course notes - Institut für Informatik

advertisement
Course notes
Programming
in Java
version September 2001
Jeroen Fokker
Department of Information
and Computer Sciences
Utrecht University
i
ii
1.
1.1
Programming 1
Computers and programs 1
Computer: processor plus memory 1
Instruction: direction to modify memory 1
Program: long sequence of instructions 1
Programming language: notation for programs 1
1.2
1.3
Order out of chaos 1
2.5
2.6
2.7
Programming paradigms 2
2.8
1.6
2.9
2.1
Java 8
Program environment 8
3.
3.1
3.2
2.3
2.4
3.3
Method definition 9
Method header and body 9
public: may be used by the environment 10
Variables 19
Calculations 20
Expressions having an int value 20
Use of variables and expressions 20
Operators 21
Operator precedence 21
Class definition 9
Class header and body 9
public: may be used by the environment 9
extends: extension of previous work 9
Graphics 18
Storage in memory 19
Assignment statement 19
Variable declaration 19
Location of declarations 19
The type int 20
Advantages of declarations 20
Program structure 8
Program: enumeration of classes 8
Class: enumeration of methods 9
Method: enumeration of statements 9
Calculated drawings 18
Graphic output 18
Methods in class Graphics 18
Classes describe object capabilities 18
The Color class 18
Java-applets 8
Java applications 8
JavaScript is not Java 8
2.2
Programming environments 12
Java applets on a web page 12
Source code, byte code and HTML code 12
Java2 Software Development Kit (SDK) 13
Edit-compile-run using SDK only 13
Integrated developing environments 13
Developing programs using JCreator 13
Interactive documentation 17
Using Wizards 17
In the small: Edit-Compile-Run 6
In the large: Model-Specify-Implement 7
2.
Library classes 11
Importing classes 11
Package: group of classes 12
Program translation 5
Programming 6
Names 11
Rules for naming 11
Conventions for naming 11
Programming languages 3
Assembler 5
Compiler 5
Interpreter 5
Compiler+interpreter 6
Methods and parameters 11
Parameters in a method definitions 11
Parameters in a method call 11
Objects of type Graphics 11
Imperative languages: Assembler, Fortran, Basic 3
Procedural languages: Algol, Pascal, C 4
Object-oriented languages: Simula, Smalltalk, C++, Java 4
1.5
Statements 10
Method call 10
Object treated 10
Method name 10
Method parameters 10
Size of memory 1
Variable: named memory location 2
Object: group of variables 2
Size of programs 2
Method: named group of instructions 2
Class: named group of methods 2
Imperative programming: instruction based 2
Declarative programming: function based 3
Procedural programming: imperative + methods 3
Object oriented programming: procedural + objects 3
1.4
void: has effects, but no calculation result 10
Method name 10
Method parameters 10
3.4
Program layout 21
Comments 21
Distribution over lines 22
White space 22
iii
4.
4.1
Method definition 24
Order out of chaos 24
New methods 24
Methods involve an object 25
Method parameters 25
The this object 25
4.2
Importing everything 35
Constructing and using Scollbar objects 35
Object variables 36
New methods 24
6.5
In search for parameters 26
Parameters make methods more flexible 26
Flexibility carried to extremes 26
Flexibility in the large 27
4.3
Methods having a result 27
Function calculation 27
A method’s result type 27
The return statement 27
Method calls 28
5.
5.1
7.
7.1
7.2
Class String 30
7.3
Utility classes 30
Calculations involving rectangles 30
Class Integer 30
Class Math 30
Type double 31
Static methods 31
Calculations with rectangles 31
6.
6.1
User interaction 33
Interaction via objects 33
A color mixer 33
Four ways to acquire an object 33
6.2
6.3
Interaction components 35
Class Button 35
Class Scrollbar 35
iv
The for statement 42
Special cases of iteration 43
Zero repetitions 43
Infinitely many repetitions 43
Iterated iteration 43
7.5
Case study: interest calculation 44
Interest on interest 44
Input via a TextField 44
8.
8.1
Choice 46
The if statement 46
Conditionally executing statements 46
An alternative part following else 46
Conditionally executing groups of statements 46
Many alternatives 46
Stop when found 47
8.2
The class Applet 34
Redefining method paint 34
Calling paint indirectly via repaint 34
Redefining method init 34
Calling method add 35
6.4
7.4
Creating new objects 33
Constructor methods and new 33
The new construction is an expression 33
New color objects 34
Boolean values 41
Shorthand of incrementing counters 42
Counting automatically 42
Declarations of object references 30
String expressions 30
5.3
The while statement 40
Comparison operators 41
Logic operators 41
The type boolean 41
Method paint has a single parameter 29
Class extensions inherit methods 29
Methods in class Applet 29
5.2
Iteration 40
Executing statements more than once 40
Repeating more than one statement 40
Repetition using a counter 40
Accumulation of a result 41
External input 29
Parameterizing applets 29
User interaction 36
Event: action by the user 36
Event listener: object which is informed 37
Event listeners are notified by a method call 37
Announcing methods using implements 37
Fulfilling the promise made by implements 37
Exploiting the promise made by implements 38
Reacting to Scrollbar events 38
The notion interface 38
Applications 47
Determining which button is pressed 47
Password checking 48
Minimum/maximum thermometer 49
8.3
Case study: Graph and zeroes of a parabola 50
Description of the case 50
Conversion if double-values 50
Structure of the program 52
Structure of the program 53
Finding the zeroes 53
Drawing the graph 53
Scaling 53
9.
9.1
Objects and classes 54
Special char values 70
Doing arithmetic with char 71
Example: counting words 71
11.2
Class: description of an object 54
Object: named group of variables 54
Class: declaration of variables plus method definitions 54
Objects and object references 54
Programs with multiple classes 56
9.2
Application: moving particles 56
Description of the case 56
Class Space 56
Class Particle 57
Design of the classes 57
The constructor method of Space 58
De methods of class Particle 58
Methods of class Simulation 59
Methods of class Space 60
9.3
Animation 61
Automatic movement 61
Class Thread 61
Method sleep 61
Calling sleep should be done in a try-catch statement 61
Controlling the animation 62
The value null 62
10. Inheritance 65
10.1
Subclasses 65
Subclass: defining additional variables/methods 65
extends generates subclasses 65
Inheritance of methods and variables 65
Redefinition of methods 66
The not-yet-extended object super 66
10.2
10.3
11.3
12. Designing the interface 77
12.1
12.2
Strings and characters 69
Class TextArea 69
Example: how many characters typed? 69
Class String 69
Primitive type char 70
History of char 70
Quote symbols 70
Example: Calculator 78
Description of the case 78
Division in classes 78
A.
Reserved words 80
B.
Operators and syntax 81
C.
Summary Java-packages 82
12.1
12.2
12.3
package java.lang 82
package java.util 82
package java.awt 83
Layout managers 83
Interaction-components 84
12.4
package java.awt.event 85
Event-listeners 85
Event-objects 85
12.5
12.6
package java.net 85
package java.io 86
Non-stream 86
Byte streams 86
Character streams 87
11. Strings and Arrays 69
11.1
Layout of the user interface 77
Layout managers 77
Available Layout managers 77
Class Panel 78
Class hierarchies in Java libraries 67
Interface components 67
Event-listeners 67
Events 68
Everything in one hierarchy 68
Example: Text analysis with letter frequencies 74
Counting of individual character frequencies 74
Separating contents from the user interface 74
Class hierarchies 66
Extends: “is a” 66
Object-variables: “has a” 67
Arrays 71
Array: many variables having the same type 71
Creation of arrays 72
Using array values 72
Arrays as a parameter 73
Arrays of objects 73
Arrays versus strings 74
12.7
12.8
Application 87
Primitive types 87
v
vi
1. Programming
1.1
Computers and programs
Computer: processor plus memory
A computer consists of many components, the architecture of which is a subject in
itself. But roughly speaking, the architecture of a computer can be described by
two words: processor and memory. Memory exists in many forms, varying in
access time and throughput rate. Some types of memory are both readable and
writable, some are readable and only writable with some more effort, and some are
only readable. Also, memory that is only writable can be imagined.
Input/output devices, (keyboard, mouse, CRT, printer etc.) may seem not to be
comprised in the category “processor” and “memory”. But when viewed
abstractly, they can be thought of as “memory”: a keyboard is “read only”
memory, and a CRT is “write only” memory. Modems, network adapters, and
even sound cards can all be regarded as memory.
The processor, however, is fundamentally different form memory. It is the
processor’s job to execute instructions. The effect of executing instructions is that
memory is modified. With our broad definition of “memory”, almost every
instruction has the effect of modifying memory.
Instruction: direction to modify memory
Thus, an instruction is a direction to modify memory. The instructions themselves
are stored in memory as well (on disk, and when they are about to be executed in
RAM memory as well). In theory a program could contain instructions to modify
the program itself. That idea has been quite fashionable for some time (and
expectations in the field of artificial intelligence were high), but programs like that
turned out to be very hard to write: the program changes before you notice!
Let’s therefore assume that the program is located in a part of memory that is
separate from the part of memory that is being modified. Of course, prior to
execution, the program is loaded into memory. Doing that is the task of a special
program, usually called an operating system (or, in some circumstances, a virus).
Program: long sequence of instructions
We’ve come to the definition of a program: a program is a (long) sequence of
instructions which, when executed by the processor, modify memory.
Programming is the task of writing a program. This requires some imagination, for
you need to imagine what will happen at the time the program is being executed.
Examples of “programs” in real life are numerous, if you widen the definition of
“memory” somewhat more: recipes, directions of use, legislation, the protocol of
visiting the queen: all of these are sequences of instructions, which when executed,
affect the world.
Programming language: notation for programs
De instructions comprising the program must be phrased in some way or another.
This could be done with diagrams or hand waiving, but in practice this is done by
coding the instructions in textual form. There are numerous formalisms to express
a program. Such a formalism is called a programming language. Quite many have
been designed is recent past, for each time someone designs yet another cute
notation for denoting programs, a new programming language is born.
In a recently published list of languages that have a name and to which at least one
publication is devoted, some 3000 were distinguished. The actual number varies
with your interpretation of what you count as a language and what you consider to
be a mere dialect. But in any case quite many languages exist.
Learning all these languages is futile. Fortunately, it isn’t necessary, because many
languages have many resemblances. However, languages have evolved over the
last 50 years. Initially, the use of new features available on new computers was
dominant; nowadays, controlling the complexity of programs is the main concern
of programming languages.
1.2
Order out of chaos
Size of memory
Few things have grown as spectacularly as computer memory size. In 1948, a
proposal by Alan Turing to build a single computer with 6 kilobytes of memory
was rejected (too ambitious and too expensive!). These days, that is the amount of
memory of the grocer’s chip card. Also, in recent history memory size in
increasing: ten years ago a typical PC was equipped with 640 kilobyte of memory,
instead of today’s 128,000 kilobyte. For disk drives, similar numbers apply: ten
years ago 20 megabyte was reasonable, these days 2,000 megabytes is called a
“budget model”. Ask yourself what we will think in ten years of today’s 640megabyte compact disks…
1
Variable: named memory location
For programs, memory is addressable in the form of variables. A variable is a
named memory location. An instruction could be to change some particular,
named variable. For small programs, this is feasible: a programmer can manage a
few dozens of variables. But if we would fill all these recently acquired megabytes
with variables, we would loose control.
That is why using old languages, it is next to impossible to comply to presentday’s program standards (window interface, fully configurable, what you see is
what you get, use of every imaginable peripheral, language independence,
independence of cultural background and alphabet, integrated online help, wizards
for frequently occurring chores…)
Object: group of variables
There is a well-known solution when things tend to grow too complex because of
their number: group items, and name the groups. The trick works for persons in
clubs, and for clubs in federations; it works for counties in provinces, for
provinces into states, for states into countries, for counties into unions; for
employees in departments, for departments in divisions, for divisions in
companies, and for companies in holdings; it works for professors in departments,
departments in faculties, faculties in universities, and universities in regional
clusters.
The trick should be applicable to variables as well. A group of variables,
belonging together and addressable by a name, is known as an object. In so-called
object oriented programming languages, objects can be stored in variables, an as
such be part of even bigger objects. This way, programs can manipulate greater
structures, without having to deal with the full complexity of details.
Size of programs
Programs are stored in memory as well, and because memory is so abundant,
programs tend to grow large. Fifteen years ago, operating system, programming
language and text processor together fitted in a ROM of 16 kilobyte; present-day
word processors come on three CDs 640 megabyte each.
There are so many instructions in a program, that for a single person it isn’t
possible to grasp all the details. Worse: even a team cannot handle the program,
because they have to discuss over and over the interaction of the instructions.
2
Method: named group of instructions
We can use the same solution as e used for variables: create order out of chaos by
grouping instructions, and referring to them by a name. By just mentioning a
single name, we can easily address large amounts of instructions, without facing
their full complexity over and over again. This is the only way to deal with
complexity with relative ease.
This principle has been in use since the beginning of programming, but is known
by many names (the name of each particular instruction group is established by the
programmer, but we are referring here to the name of the naming activity…).
In the 1950s a named group of instructions was known as a subroutine. In he
1960s it was called a procedure. In the 1980s the word function was in vogue, and
in the 1990s you should call it a method to be taken seriously.
We’ll stick to the word method, but by whichever name you refer to it: most
important is that long sequences of instructions become manageable by grouping
them, and naming the groups.
Class: named group of methods
For decades, procedures were quite adequate. But with ever expanding programs a
new problem arose: the number of procedures became too large to be manageable.
Again, we apply the same solution: group procedures that belong together, and
treat them as a whole such a group is called a class.
As if to stress this new point of view, the grouped sets of instructions that were
formerly called procedures where coined methods; the word “method” was
introduced together with the word “class”.
1.3
Programming paradigms
Imperative programming: instruction based
In the realm of programming languages, we could use some order out of chaos,
too. Programming languages sharing characteristics are said to belong to the same
programming paradigm. (The word “paradigm” is stolen from the field of
Philosophy of Sciences, where it denotes the common framework of theory in a
certain period; thus the term is quite apt).
A large number of languages belong to the imperative paradigm, and are therefore
called imperative programming languages. The word “imperative” refers to the
imperative verb form, using which you can issue commands. Imperative languages
are based on commands or instructions (which, however, are commonly called
statements) intended to change memory contents. Therefore, imperative languages
are directly based on the computer architecture model involving processor and
memory. In this course, an imperative language is used, which explains the name
of the course.
Declarative programming: function based
The very existence of the adjective “imperative” suggests that other paradigms
exist, where no commands or statements are involved. Would that be possible?
What’s the use of a processor, if it’s not executing commands?
The answer is that although a processor executes commands, this fact need not
necessarily be reflected in the programming language. Think of designing a
complicated spreadsheet, where relations between cells on a worksheet are made.
This activity could be called “programming”, and the blank spreadsheet can be
thought of as a “program”, ready to process input data. The “program” is based on
defining functional relations between cells, rather than on issuing commands.
Languages like the spreadsheet-language are called functional languages. Then we
have a third paradigm: languages that are based on predicate calculus are called
logic programming languages. Together, the functional and logic languages are
called declarative languages. Interesting as they might be, they are not the topic of
this course.
Imperative
Assembler
Declarative
Fortran
Basic
Functional
Lisp
Procedural
Algol
Excel
Haskell
Pascal
Objectoriented
C++
C
Simula
Java
Figuur 1.1: Programming paradigms
Logic
Prolog
Procedural programming: imperative + methods
Programming languages where procedures (or methods, as the fashionable term is)
play a role, are parts of the procedural paradigm. All procedural languages are
imperative: after all, procedures are groups of statements, and the presence of
statements is what makes a language imperative.
Object oriented programming: procedural + objects
Yet another extension of procedural languages is the paradigm of object oriented
languages. Here, not only statements are grouped into procedures (or rather:
methods), but also variables are grouped into objects.
Sometimes the procedural and object oriented paradigm are contrasted (“are you
in favor of procedural or object oriented languages?”). Such a question is beside
the point: the question should be: “are you in favor of object oriented languages as
well as procedural ones?”.
1.4
Programming languages
Imperative languages: Assembler, Fortran, Basic
The first computers were programmed by entering instructions, coded as numbers,
directly into memory. Soon, it turned out to be useful to use mnemonic names for
instructions rather than obscure numbers. This was the birth of the first real
programming language, around 1950. It was called Assembler, because you could
easily build (“assemble”) programs using it. Each processor has its own instruction
set, and that makes Assembler processor dependent. That’s why you can’t say “the
language Assembler”, but rather “a language belonging to the class of Assembler
languages”.
Of course, having a different language for each processor type is not convenient,
because the introduction of a new processor type makes existing programs
obsolete. In 1955, a new innovation was made: a language called Fortran (which is
an abbreviation of “formula translator”). De statements of Fortran are not targeted
at a particular processor, but could be translated (using a dedicated program) to
various processor types. The language was used a lot for technical and scientific
applications. It is still used in that field. Modern languages would also fit the
purpose, but over years, many Fortran programs have been developed, and people
tend to be conservative about the language they learned first.
Fortran is not really accessible for beginner programmers. Initially, this was no
problem, because beginners did not operate an expensive machine like a computer.
3
But over time (around 1965), the need arose for a language which was easier to
use. This was the birth of Basic (“Beginner’s All-purpose Symbolic Instruction
Code”). This language became immensely popular because it was the native
language for “personal” computers: the Apple II in 1978, the IBM-PC in 1979, en
all their successors. Unfortunately, the language was not standardized, and hence
each company used its own dialect, and programs were not exchangeable among
machines.
Procedural languages: Algol, Pascal, C
Meanwhile, it was recognized that for writing larger programs, the use of
procedures could not be avoided. The first language that can really be called
procedural is Algol (a rather strange acronym of “Algorithmic Language”).
The language came into existence in 1960, and it had an official definition, which
was very beneficial for the portability of programs among computers. A special
notation was used for describing the “grammar” of the language (BNF). This
notation is still in used, and has survived Algol itself.
In the euphoria on technology of the 1960s, in 1968 a new version of Algol was
designed: Algol68. A large committee tried an incorporated various new ideas in
the language. There were so many new ideas, that it became terribly hard to write
compilers for Algol68. There have been only a few, and Algol68 shared the fate of
the dinosaurs: it has gone extinct because of its sheer complexity.
Language designers learned from the experience: one should not strive for a
language with many features, but rather for a simple and compact design. The first
simple, yet procedural, language was designed by one person in 1971: Pascal (not
an acronym, but named in honor of the philosopher Blaise Pascal). Designer
Niklaus Wirth designed the language for teaching programming at the Zürich
Polytechnic. Soon, the language was used for real applications (of course, because
people tend to be conservative about the language they learned first).
However, for large projects Pascal was too limited. A large project was the
development of the Unix operating system in the late 1970s at Bell Labs. It was an
innovation anyhow to write an operating system using a procedural language (until
then, this was done using Assembler languages). For the purpose, a new language
was designed: C (said to be the successor of earlier prototypes A and B). Unix’
philosophy was that users could write their own extensions (e.g., editors). For
these extensions, people tended to use C as well. This made C the most important
imperative language of the 1980s, even for other operating systems than Unix.
4
Object-oriented languages: Simula, Smalltalk, C++, Java
In 1975, a researcher called Ole-Johan Dahl (Bergen, Norway) was interested in
programs doing simulations (of queues in post offices, traffic circulation, etc.). In
those days, it was not uncommon to design your own programming languages, and
thus Simula was born as an extension of Algol60. One of the extensions was the
existence of objects as a language feature. It was useful, because it could be used
to model a person in the post office, or a car in a traffic jam. It made Simula the
world’s first object oriented language.
Simula had a marginal (yet persistent) life. However, the idea of objects as a
language feature was picked up by researchers of Xerox at Palo Alto, who (prior
to Apple and Microsoft) experimented with windowing systems and a mouse.
Their language (called “Smalltalk”) used objects to model windows, buttons,
scrollbars and similar identifiable objects.
However, Smalltalk carried things to extreme: literally everything was modeled as
an object, even numbers. This was not accepted by the masses. Yet it was evident
that objects were a useful language feature. A C-like language with objects was
deemed to come into existence. Soon, the language C++ was designed (the double
plus sign means “successor” in C, so every C programmer understood that C++
was meant to be the successor of C). The first version of C++ is from 1978; the
official standard was published in 1981.
The language was very useful for writing window-based programs, which at the
time became fashionable. But the success of C++ is also due to the fact that it was
a true successor of C: (almost) all C programs are also acceptable as C++ program.
This was important, because people tend to be conservative about the language
they learned first.
Although C++ was standardized, the method libraries needed to write windowbased programs were not. Programming a window on an Apple, Windows, or
Unix machine was quite different. Consequently, programs could not be ported to
other machines. Initially, this was not really a problem. Things changed, however,
when in the mid 1990s, Internet became increasingly prominent: it was a pity that
programs published on the internet could only be used by that part of the audience
possessing the same operating system.
A new programming language was due to arrive, this time one designed with
portability among operating systems in mind. The language should resemble C++,
because people tend to be conservative about the language they learn first.
However, this would be a good occasion to drop some features which C++
inherited form C.
The Java language fills the niche (no acronym, no philosopher, but named after the
favorite coffee shop of the designers. For this language to have success in a world
of Internet users spoilt with free software, it should be useable for free. Which
company would be willing to invest in products to be distributed freely? Hardware
manufacturer Sun showed the benevolence, of course not without a hidden agenda:
an operating system independent language could help penetrating the market
dominated by rival Microsoft.
It is interesting to read the “small print” of the Java license: everything that is
usually prohibited with software is allowed: use, copy, distributed – all is free.
Only one thing is strictly prohibited: adding new features to the language
specifically targeted at one operating system. Of course, that is the rule Microsoft
tries to circumvent (e.g., by calling their compiler “J” instead of “Java”).
Microsoft’s answer to Java was to introduce a language of its own, called C#. It is
hard to predict what will be the outcome of this turmoil in programming language
land. Will Java be the standard language of the next decade? Will C++ become
obsolete, or is there still a need for it? Will Java rival the execution speed of C++?
Will C# become as popular as Java is? Will Java remain standardized, or will
dialects emerge?
Anyhow, Java is easier to learn than C++ (which, because of compatibility to C is
rather complex); so using Java, you can soon write interesting programs. Object
orientation is a prominent feature of Java, which is certainly important to learn.
Viewed as an imperative and procedural language, Java is certainly not worse than
Pascal. Having a Java background, you can easily learn other object-oriented
languages (such as C++ and C#, but also languages that do not exist as of now).
That might prove useful, because there is no sensible reason to be conservative
about the language you learn first…
1.5
assembler
assembler
Figuur 1.2: Translation by an assembler
Compiler
The advantage of all languages other than Assembler is that, at least in theory, the
can be written machine independently. Thus, only one program is needed, that can
be translated to machine code. The translator program is called a compiler. The
compiler itself is machine specific: it should know about the machine code to
produce. However, the program written by the programmer (the source code, or
source for short) is machine independent.
Translation by a compiler is the usual approach for procedural languages, like
Pascal, C and C++.
compiler
Program translation
Assembler
A computer program needs to bee translated for use on a specific computer. The
program that does the translation is called an assembler, compiler or interpreter,
depending on the specific situation.
An assembler is used to translate Assembler programs to machine code. Because
an Assembler program is specific to a certain processor, you need different
program for each target processor, which is assembled by an assembler for that
specific processor.
compiler
Figuur 1.3: Translation by a compiler
Interpreter
A more direct way to translate is by means of an interpreter. An interpreter is a
program which reads the source code and directly executes the statements, without
first translating them to machine code. The interpreter is machine specific, but the
source code is machine independent.
5
The word “interpreter” could be taken literally, if you consider the analogous
situation for human languages: an interpreter translates sentences immediately
when spoken, as opposed to a translator who processes a text as a whole.
The advantage of an interpreter over a compiler is that no separate compilation
phase is necessary. The disadvantage, however, is that translation is slower, and
that possible errors in the program are not caught in an early stage by the compiler.
Translation by an interpreter is common for relatively simple languages like Basic,
but also for HTML and the language JavaScript that is embedded therein. (Note:
do not confuse JavaScript with Java; these are different languages!).
interpreter
interpreter
Figuur 1.4: Translation by an interpreter
Compiler+interpreter
For Java a hybrid approach is taken. Java programs are meant to be communicated
via the Internet. Distribution of compiled machine code would not be adequate, as
machine code is machine specific: you would have to distribute separate versions
for every machine conceivable. Distribution of source code, however, might not be
acceptable: the source code would be readable for everyone, which is an invitation
to infringe on the copyright. A common situation is that users are allowed to use
the program, but not to read or modify the source code. Machine code is a
safeguard for that.
This is why Java takes a hybrid approach. There is a compiler, which translates the
source code. However, the target language is not machine code, but a machine
independent intermediate language called byte code. The byte code can be
distributed via the Internet. Subsequently, it can be executed on the user’s machine
by means of a byte code interpreter.
Byte code is simple enough for making simple interpreters. Also, interpreters can
be easily embedded in Internet browsers. Most of the translation job is done by the
6
compiler, so interpretation of byte code can be done relatively fast. Execution of
“real” machine code will however always be faster.
interpreter
compiler
interpreter
Figuur 1.5: Translation by a compiler and an
interpreter via an intermediate byte code
1.6
Programming
In the small: Edit-Compile-Run
The source code of a program being text, implementation usually begins by typing
in the source code using a text editor. Once completed, a compiler processes the
source code. If nothing goes wrong, the compiler produces byte code, which can
subsequently be interpreted.
Normally, things do go wrong. The source code should be legal Java code; you
can’t expect the compiler to translate nonsense to sensible byte code. This is why
the compiler checks whether the source code conforms to standards: if not, it
produces an error message, and doesn’t emit byte code.
In general, you will try hard to compile real Java source code, but it is only human
to make typing mistakes, or to sin against program syntax rules. Be prepared to
revise the program a couple of times using the editor.
Sooner or later, the compiler does not complain any more, and emit byte code.
Then the next stage begins: running (or executing) the program. Some (many?)
times you’ll notice that the program does not do what you had in mind. Of course
you tried hard to correctly phrase your intentions, but to err is only human.
The remedy is to return to the editor, and modify the program. Then you should
compile the program again (hoping that you didn’t introduce new typing mistakes)
and run again. Only to see that the program behaves differently this time, but still
not as you had in mind. Back to the editor…
In the large: Model-Specify-Implement
When programming projects are more ambitious, it is not a good idea to just sit at
the computer and start typing source code. Prior to implementing (the actual
writing and testing of the program as described above) are two more phases.
First, you will have to state your problem in terms of a program that processes
input from a user and shows results. This phase, modeling of the problem, might
be the most difficult one.
Once it is clear which tasks should be performed by the computer, the next step is
to list the classes that are necessary, and the methods contained by them. In this
phase you plan what methods to write, but not how this is done. Bear in mind that
you do not specify the impossible, because they will have to be implemented
sooner or later…
When the specification of the program is complete, the implementation phase
starts. The edit-compile-run cycle described above will most probably be traversed
repeatedly.
After implementation, the program can be transferred to the customer (which
might be you). In many cases the customer will reply that the program is nice, but
the problem that should have been solved was slightly different. Then you can
start all over again, revising the model, revising the specification, and making a
new implementation, and then…
7
2. Java
2.1
Program environment
Java-applets
One of Java’s raisons d’être is distributing programs via the Internet. This is done
most directly by executing programs from the Internet browser. Part of the
browser’s window is allocated to the program and can be used by the program for
communicating with the user. Java programs that behave like this are known as an
applet (for “small application”).
In HTML, the markup language for web pages, it is possible to indicate that an
applet should be included in a web page. Analogous to including an image using
the <IMG>-tag, you can include an applet by means of an <APPLET>-tag. The byte
code itself doesn’t take part of the HTML-file, but is located in a separate file, in
the same fashion that an image is located in a separate gif- or jpeg-file.
Java applications
Java being a complete, general purpose programming language, it is possible to
create stand-alone programs, which can be run without an Internet browser. As
opposed to an applet, a stand-alone program is called an application.
The source code for an application differs slightly from that of an applet. E.g., an
application must create it’s own window, where an applet can use the browser’s
window. An application can, if needed create more than one window, which is not
possible in an applet. Furthermore, an application can use local files, which is not
allowed in applets for security reasons. But it is possible for applets (as well as for
applications) to read files form the Internet.
For the larger part of a program, however, it is not relevant whether the program is
to be used as an application or as an applet. An applet can be easily modified to an
application (by adding statements that create a window, in which the applet output
is shown). The other way around might be more involved, as the application may
not conform to the restrictions that apply for applets.
JavaScript is not Java
Confusingly, there is one more language that is intended to use in an Internet
based environment. We are referring to JavaScript, which has, although the name
suggests otherwise, not much in common with Java.
8
Apart from the name, Java and JavaScript have in common that they are both
imperative, machine independent languages, that can be used with an Internet
browser in a secure way, such that the user need not worry that his local files will
be corrupted.
There are, however, quite a few differences:
 Java is object oriented, JavaScript is “only” procedural.
 Java is compiled (to byte code, which is subsequently interpreted); JavaScript
is interpreted directly.
 Java byte code is located in a separate file; JavaScript source code can be
embedded in the HTML-file.
 Java-applets are restricted to the part of the window that is allocated to them;
JavaScript programs can interfere with the rest of the browser (change
background color, surf to a different location, etc.)
 Java programs can use an extensive library of classes and methods; JavaScript
programs can only use a limited number of built in methods.
In short, Java is used mainly by programmers, and JavaScript is used mainly by
web designers.
In this course we will only use Java, because that language will provide more
long-term insight in object oriented programming languages. Thus, you can easily
learn other languages in the future; after all, there is no need to be conservative
about the language that you learn first. (Occasionally, we might envy JavaScript
programmers a bit, because of the cute graphical effects that can be easily
programmed with JavaScript).
2.2
Program structure
Program: enumeration of classes
Because Java is an imperative language, a program consists of statements
(instructions) that need to be executed at run time. Because Java is also
procedural, the statements are grouped in methods. And because Java is object
oriented as well, the methods are grouped in classes in turn. Thus, a program
consists of an enumeration of all classes needed (each containing some methods
(each containing some statements)).
In listing 2.1 one of the shortest Java programs possible is given. It is an applet
that writes Hello! to a window. There is only one statement, which nevertheless
need to be embedded in a method, which is the sole inhabitant of a class.
Each class bears a name, invented by the programmer. The example class is
named Hello.
import java.awt.Graphics;
import java.applet.Applet;
public class Hello extends Applet
{
public void paint(Graphics g)
{
g.drawString("Hallo!", 30, 20);
}
}
Listing 2.1: Hello.java
Class: enumeration of methods
A class mainly consists of an enumeration of member methods. In the example
program, there is only one method. Just as in the case of the class, the name of the
method is determined by the programmer. In the example, the method is named
paint.
Method: enumeration of statements
In methods, the statements proper are contained. In the example program there is
only one statement, viz. a statement to display a certain text at a specific location
of the screen.
We will now study the example program more closely.
2.3
Class definition
Class header and body
Each class definition consists of a header (the first line) and a body. The header of
the Hello class in the example program is
public class Hello extends Applet
The body which follows is enclosed between braces: { and } . This way, it is
clear which methods belong to this class. Usually, the braces are aligned
vertically, and placed on a separate line. All text in between is indented. Using
these layout conventions, the end of the class can easily be found.
public: may be used by the environment
The header of a class mentions the word class, to indicate that we’re dealing
with a class definition. Adjacent to the word class, the name the programmer
chose is written, in this case Hello.
Preceding the word class, the word public can be written. This indicates that
the class may be used by the outside world. The example program being an applet,
the class need indeed be public, because the class is used by the browser.
Instead of public, the word private might have been used. A private class is only
for internal use by other classes of the program. In the example program this
would not be a good idea (there are not even other classes!).
Leaving out the word public or private altogether makes a class private
automatically.
extends: extension of previous work
Following the name of the class, the word extends may be written, followed by
the name of another, already existing class. That way, we can indicate that a class
is not built from scratch, but that it is an extension of another class. Because the
example program will be an applet, we have our class extend the existing class
Applet. Thus, we need only describe in which way our program differs from an
“empty” applet.
2.4
Method definition
Method header and body
A class body consists of methods belonging to it. In the example program there is
only one: a method named paint.
Analogous to a class, a method consists of a header and a body. This time, of
course, the word class is omitted form the header. The header of the example
method is:
public void paint(Graphics g)
The method body must be enclosed in braces. That way, it is shown which
statements are parts of the method. In the example program this happens to be just
one statement.
For clarity we align the braces vertically, and indent the body that is enclosed by
them.
9
public: may be used by the environment
As was the case with a class header, a method header begins with an indication of
the protection: the word private or public. The example method is used by
the browser, and must therefore be public.
void: has effects, but no calculation result
The second word of the method header is the method’s type. Some methods may
calculate a result value; the type indicates what kind of value that will be. But
some methods are just there to execute statements because of their effect. The
example method is one of them. In these cases, the word void is used as a type.
Literally, this means “empty”, which is an adequate description of the non-existing
result value of the method.
2.5
Statements
Method call
In Java, there are a dozen of different statement forms. We’ll begin with one of the
most important: the method call.
When the processor executes a method call, it will start executing the statements
that are in the body of the method mentioned. Only after that has been completed,
the processor continues with the statement following the method call.
Interestingly, the statements of the method called may be method calls themselves.
Compare this to delegation of work to others: when a method is too lazy to carry
out some work, another method is called to do the job.
In the example program, the sole statement in the body of the paint method is a
method call:
g.drawString("Hello!", 30, 20);
Method name
The third word in the method header is the method’s name. In principle, the
programmer may determine the name. However, when an applet is started by the
browser, it will begin executing the statements in a method called paint. If we
want our method indeed being started by the browser, we’d better call it paint.
Method parameters
Next to the name of the method, an enumeration of so-called parameters follows.
They are enclosed in parentheses: plain, round parentheses, not braces. The
programmer may determine the number of parameters: zero, one, two or more. But
even if there are zero parameters, the parentheses are there, enclosing nothing.
In the case of the paint method, there is no choice, because the browser (who calls
the method) expects it to have exactly one parameter.
The parameters indicate the type of variables that are available for used in the
method. In the case of paint, there is no choice: the single parameter needs
necessarily be a Graphics-object. As a programmer, we may however freely
choose a name for the parameter. In the example, the name g was chosen.
The purpose of parameters will soon become clear. But first, we’ll investigate the
method body.
10
We’ll analyze this statement in detail now.
Object treated
Each method that is called treats a particular object. In a method call, that object is
mentioned first – after all, the paradigm is object oriented!
In the example the object g, which we got as a parameter, will be the object
treated by the method that is called.
Method name
Next to the object that will be treated, a dot is written, followed by the method that
needs to be called. In the example, we want our object g to draw something, which
is why we call the method drawString.
Method parameters
With the call of drawString we need to specify some details: which text to
draw, and where this is supposed to happen. The text under consideration is
"Hello!", the position 30 pixels (image dots) form the left-hand side edge, and
20 pixels from the top edge of the window.
Parameters must be enclosed in parentheses. Finally, a semicolon completes the
method call.
The text is written between quotation marks, to indicate that this text is to be taken
literally. Without quotation marks, the compiler would comply that there is no text
named Hello, and that a spurious exclamation mark is no legal Java code.
Between quotation marks however, everything is acceptable. Quotation marks
mark the boundaries of the text; all symbols in between of them are taken literally.
2.6
Methods and parameters
Parameters in a method definitions
Parameters are the way methods communicate: in a method header you can
specify that a method expects parameters when it is called; in a method call you
need to indicate what value the parameter has (which should be of the type that is
expected by the method).
The header of the paint method was:
public void paint(Graphics g)
Here, we specify that anyone who wants to call this method, needs to provide an
object of type Graphics. The browser, when he calls paint, indeed does so.
Parameters in a method call
In a method call, values for the parameters specified by the method should be
mentioned. In the method header of drawString it is specified that this methods
expects three parameters: a text and two numbers. When calling drawString,
we therefore need to provide a text value and two number values.
Both in the method header and in a method call, the parameters are enclosed in
parentheses. But the thing that is enclosed in them, differs: in a method header, a
type and a programmer determined name is given, in a method call only a value
for the parameter is given.
Objects of type Graphics
What, now, is a Graphics object, that is received as parameter by the paint
method?
Best way to think of a Graphics object is a “drawing apparatus”. It is an object
that, upon request, can draw texts (and other things) for us, namely by calling the
drawString method, mentioning the object before the dot.
Magically, the browser is in possession of such a drawing apparatus, and is
benevolent enough to pass it as a parameter when calling the paint method. In the
method header of paint we accept the parameter, labeling it with the name g. In
the method body we can use the object g thus acquired, using it as a the object that
is treated with the drawString method.
2.7
Names
Rules for naming
Many things in Java are indicated by their name: classes, methods, object types,
parameters. Sometimes the name is chosen by the programmer, sometimes it is the
name of an already existing class or method. Anyway, the name should conform to
the following rules:
 the name consists of one or more letters, digits, and/or underscore signs and
dollar signs;
 the first symbol is a letter;
 some fifty words are taboo, because they have a special meaning in Java
(examples are public, class, extends, and void).
Capitals and lower case letters are considered to be different; de method in the
example program needs to be named paint, not Paint or PAINT. These rules
are obligatory; when you violate them, the compiler complains.
Conventions for naming
Furthermore, there are some conventions for naming that most programmers
conform to. These rules are not strict in the sense that the compiler enforces them,
however it shows good taste to conform to them: when all members of a team do
so, programs will have a uniform “look”. The conventions are:
 names of classes start with a capital (for example our own class Hello, and
the existing class Applet), as do object type names (e.g., Graphics);
 names of methods start with a lower case letter (e.g., paint and
drawString) as do parameter names (such as g);
 when a name consists of multiple words, the second and later words begin
with a capital (as in drawString);
 funny acronyms should be avoided—rather use a multi word name (thus,
don’t use ann but aNiceName).
2.8
Library classes
Importing classes
In the example program, two classes are used form a library of Java standard
classes:
 Applet, because our class Hello is an extension of it
 Graphics, because it is the object type of the parameter of paint
11
To be able to use these classes, they have to be “imported” in the program. This is
done by a special import directive at the start of the program:
import java.awt.Graphics;
import java.applet.Applet;
As opposed to the method call further down the program, these are not statements:
the processor need not execute them at run time. Rather, they are directives for the
compiler that the classes mentioned will be used in the program. That is the reason
we call them “directives” rather than “statements”.
Package: group of classes
The classes in the Java libraries are organized in so-called packages. (Computer
scientist sort of like hierarchic orderings). In import directives, the name of the
package needs to be mentioned.
Class Applet is in package java.applet (in which besides Applet, some
more classes having to do with applets reside). Class Graphics is in package
java.awt. In these packages, all classes belonging to the abstract window
toolkit are located. The toolkit is called abstract because the classes are not
designed with a particular operating system in mind. Therefor you can use them
for making cross platform programs.
2.9
Programming environments
Java applets on a web page
Java applets are part of a web page. To test an applet, you’ll need to prepare an
HTML-file pointing to the applet. In listing 2.2 is an example HTML-file, which
wraps the Hello applet. This is done with an <APPLET>-tag, where the name of
the byte code file, the width end the height are specified. A corresponding closing
tag </APPLET> is also needed. Text appearing between opening and closing tag
is shown when the browser is incapable of running applets.
<HTML>
Here is a <B>simple</B> applet: <BR>
<APPLET code = Hello.class
width = 100
height= 50>
</APPLET>
</HTML>
Listing 2.2: Hello.html
12
Source code, byte code and HTML code
The name of the file that holds the source code needs to have the same name as the
class described therein, completed with a .java extension. The program named
Hello thus is stored in file Hello.java. Not all compilers enforce this rule, but
some do, and it is a useful convention anyhow.
import java.awt.Graphics;
import java.applet.Applet;
public class Hello extends Applet
{
public void paint (Graphics g)
{
g.drawString(“Hello!”, 20, 20);
}
}
Hello.java
compiler
Hello.class
<HTML>
Here is a <B>simple</B>
applet: <BR>
<APPLET code = Hello.class
width = 100
height= 50 >
</APPLET >
</HTML>
Hello.html
Figure 2.1: source code, byte code and HTML code
When compiling the source code, the compiler produces a file with .class
extension, viz. Hello.class. This is quite confusing, as the class is described in a
java-file, and the class-file holds byte code…
The byte code file is not readable using an editor. It need not be, because it is
intended to be used by the interpreter that is built in in the web browser. (You
might find it interesting to inspect a class-file using a hexadecimal editor: you’ll
recognize some method names, but not the statements you wrote).
The class-file and html-file should be placed on a web server. The java-file need
not be located on the server; it can be kept secret if desired. When someone visits
the web page, the applet is started and its output will be visible to the user
(because the browser calls the paint method). The result is depicted in figure 2.1.
Java2 Software Development Kit (SDK)
Sun Computer Inc. provides a bundle of software, known as the Java2 Software
Development Kit, containing (amongst others) the following programs:
 javac, a compiler translating Java source code to byte code
 java, an interpreter for running stand alone Java applications
 appletviewer, an interpreter for applets, with which you can test applets even
without a browser.
Formerly it was known as the ‘Java Development Kit’ or JDK, which went
through versions 1.0 and 1.1. With the advent of version 1.2, it was renamed SDK,
and for marketing reasons the product was named ‘Java2’. After that, the product
evolved into version 1.3, of which the full name would be ‘Java2 SDK, version
1.3, Standard Edition’. This year, a betatest version 1.4 became available.
Edit-compile-run using SDK only
There is no editor in the SDK. Instead, you can edit the source code and HTML
code using your favorite editor. A simple editor like notepad or pfe will do.
The compiler can be run from a DOS box, issuing the command
javac Hello.java
Error messages, if any, also appear in the DOS box. The compiler mentions the
line number of the error; you can search for this line in the editor, and correct the
mistake.
When the compiler detects no errors, it will generate a .class-file. You can then
run your applet by entering the command
appletviewer Hello.html
where Hello.html is the HTML-file containing the <APPLET>-tag referring to the
file Hello.class.
When the program is an application rather than an applet, you can run it with
java Startclass
Here Startclass is the name of the class (not the name of the file!) containing
the method that builds the main window. For the moment, however, we will not
use this, because all programs in the next few chapters will be applets.
developing environment (IDE), which combines compiler, interpreter and editor in
one program. An IDE provides facilities for:
 clicking error messages, upon which the cursor is automatically located at the
line containing the error;
 recognizing certain Java keywords and constructs, showing them in a
distinctive color;
 automatical completion of closing braces when you type an opening brace;
 browsing through methods and classes
 compile and run programs with a single keypress
 reading online help
Various IDEs for Java are commercially available: Webgain Visual Cafe, Inprise
JBuilder, Microsoft J++, and IBM Visual Age, Oracle Jdeveloper, Metroworks
CodeWarrior, and Tek-tools Kawa, to name a few.
Most IDEs do not have a built-in compiler, but behind the scenes use the compiler
that comes with SDK. The IDE is a mere “shell” around SDK. This has the
advantage that you can still use the IDE when newer versions of SDK will be
available.
In this course, we will use a freeware IDE called Jcreator from Xinox software,
which is quite as powerful as the commercial products, and moreover is, well,
free.
Developing programs using JCreator
Compiling and running a program using an IDE might look complicated from this
description, but is actually a lot easier to use than a separate editor, compiler and
appletviewer. We will go through 10 steps. Some of these steps might be
unneccessary in some circumstances, some of them might need te be repeated.
Step 1: start the IDE by clicking the icon on the desktop, or be selecting
Start>Programs>Jcreator>Jcreator. The JCreator main window will appear. In
this window, a few empty panes are visible at the left, and the usual wealth of
menu options and buttons are available near the top of the window.
Integrated developing environments
Although the SDK is in principle all you need to develop Java programs, the ease
of use is rather limited. More services are provided by a so-called integrated
13
Step 2: Because we work in a networked environment, the first thin we have to do
is to instruct JCreator that it should store files in your personal H disk, not on the
C disk of the computer that you happen to work at.
To do so, choose Configure>Options. There are many items that you can specify
options for – you might want to go through them some day to adapt JCreator to
your personal taste. But for now, choose Directories, and next to ‘Default Project
Directory’ type a path on the H disk. You might want to create a new directory, as
you will create a lot of files in the near future, which will clutter up your
documents directory. You can leave the other two directories (‘Syntax’ and
‘Project Templates’) as they are.
14
Step 3: Even a simple program needs more than one file. Files that belong
together (e.g., the java-file and the html-file) are bundled in a so-called project. So
the first thing to do when writing a new program is to create a new project. Choose
Project>New Project or File>New>Projects. You can choose from three types
of projects. For now, choose ‘Empty Project’, and type of a filename for the
project, e.g. Hello. In the pane near the left of the window, you see that yo have
a ‘workspace’ now, containing a single project named ‘Hello’.
Step 4: Now is the time to create the java-file for the program. From the menu,
choose File>New>Files, select the ‘Java file’ icon, and type a filename. You can
use Hello here again, as JCreator will automatically add the .java extension. It
won’t harm to type the extension yourself, though.
Step 5: The next step is typing the program. In the window that appeared when
you created the file in step 4, you can type in the Java program from listing 2.1.
When you’re done, choose File>Save to save your work to disk. As always, it is a
good idea to frequently save your work, as you might loose unsaved work when
the computer crashes. (see top figure in the next column)
Step 6: The same procedure is used to create the HTML-file. Again choose
File>New>Files, this time click the ‘HTML file’ icon. Again, you can name it
Hello, as the extension is automatically added. Type the HTML file from listing
2.2 and save your work.
15
Step 7: Before whe can test our program, it needs to be compiled. This is done by
choosing Build>Compile Project.
You can get rid of the appletviewer window by clicking the X in the top right
corner. The DOS box will also disappear.
It is quite probable that the program contains errors. You might have introduced a
typo, like the misspelled word ‘Grahpics’ (which should have been ‘Graphics’) in
the example above. In the example, that’s why the compiler complains that it
‘cannot resolve the symbol’. Other common sources of errors are confusing lower
case characters and capitals: in Java (unlike HTML), there is a difference between
‘paint’ and ‘Paint’.
When you double click on the error message, the cursor will jump to the line
containing the error. Especially in long programs, this is quite convenient. Next,
you can correct the error, and compile again choosing Build>Compile Project.
This should be repeated until there are no more errors, and the the Build window
just mentions ‘Process completed’.
Step 8: Once the program is successfully compiled, you can run the program to
see its output. For this, select Build>Execute Project. A black DOS box appears,
which you can ignore, but also an Appletviewer window appears, which shows the
output of the applet. Finally we have our Hello message on the screen…
16
Step 9: Alternatively, you could run the applet by loading the HTML-file to the
web browser. Locate the HTML file using Windows Explorer and double click it.
The output will be visible in an Internet Explorer window.
Notice that, this time, you will see all of the HTML file, including the text ‘this is
a simple applet’. The applet per se appears in a separate (grey) rectangle. This is in
contrast to the appletviewer approach shown in step 8, which only shows the
output of the applet (and the text ‘Applet started’).
Well, there are easier ways to show ‘Hello’ in an Internet Explorer window (just
type it in the HTML window). But remember that this is just a silly example to
show you all steps of compiling and running a program – we’ll meet more
involved programs in the next chapters.
Interactive documentation
You might wonder what classes are avaliable in the standard packages, and what
methods reside in these classes. In this course, we’ll encounter some of them.
They are summarized in appendix C. But there are many more, and mentioning all
details of them is far beyond the scope of these course notes. You will need some
of the unmentioned methods, though. For this purpose, there is online
documentation available. The easiest way to access it is to highlight a class name
(for example ‘Graphics’) in the source text, and then choosing Help>JDK Help.
(Or alternatively, right click the word and select Show JDK Help form the context
menu, or alternatively, press Ctrl-F1.)
You will be presented a reference manual for the class you selected. Some parts of
it might be incomprehensible by now, but if you browse through it, you will
encounter useful information – for example, an index of all methods in the class.
Using Wizards
All applets have the same structure as the simple Hello program shown in this
chapter. Each applet should have an accompagnying HTML-file, where its size is
determined. In steps 3 through 6 we created the project, the Java file and the
HTML file by hand. In practice, it is easier to let a wizard assist you in going
through these steps. When you choose File>New Project, you can select the
‘Basic Applet’ icon. You’ll obtain a ready-to-run applet quite similar to our Hello
example, which is a good starting point for making modifications to.
17
3. Calculated drawings
3.1
Graphics
Graphic output
A program just writing “Hello!” to the screen is not that interesting (this could
have been done even without Java, by putting the text “Hello!” directly in the
HTML-file…)
Fortunately, Graphics objects recognize more methods than just drawString. By
calling various methods in the body of paint, an applet can construct complicated
drawings. For example, the program in listing 3.1 draws a painting in the style of
Mondriaan’s “composition with red and blue”. Figure 3.1 shows the running
applet.
Methods in class Graphics
Objects of type Graphics, as provided as parameter of paint, can be used with the
following methods:
 drawString ( t, x, y )
draw text t at position (x,y )
 drawLine (x1, y1, x2, y2 ) draw a line from position (x1,y1 ) to (x2,y2 )
 drawRect (x, y, w, h )
draw a rectangle having width w and height h
 drawOval (x, y, w, h )
draw an oval in the described rectangle
 fillRect (x, y, w, h)
as drawRect, but filled in
 setColor (c )
use color c in subsequent calls of draw…
All sizes and positions are measured in pixels, counted from the top left corner.
Thus, x-coordinates range from left to right, and y-coordinates from top to bottom
(as opposed to graphs in mathematics).
In listing 3.1 we use method fillRect to color a number of rectangles. For
colored rectangles we first call setColor.
Classes describe object capabilities
You can call all methods from class Graphics, provided that you have an object
of type Graphics. In the body of paint this is no problem, as a Graphicsobject is given as a parameter, which may be used in the body.
This illustrates the role of class definitions. It is not just an enumeration of
methods: the methods can be used to perform some operation upon the objects
18
having the class as type. In as sense a class describes the capabilities of an object:
a Graphics-object “is able to” draw texts, lines, rectangles and ovals.
Objects have memory of their own. This becomes clear from studying setColor:
after having called it, the object “remembers” the color to be used in subsequent
method calls. This is consistent with the definition we gave of objects in section
1.2: an object is a group of variables. Meanwhile, we’ve seen that a class (section
1.2: named group of methods) describes the capabilities of an object.
The “behavior” an object exhibits is even more interesting than an enumeration of
component variables. You can see this from the way we’ve been using the
Graphics-object: we don’t even know of which variables the object is
composed, but we are able to use the object once we know what methods to call.
Usage of library classes is ruled by the motto: “benefit without wondering”.
The Color class
The method setColor in class Graphics needs some more explanation. When
calling the method, we need to supply a color as a parameter. In Java, a color is an
object in itself, which poses the question: where can we get color objects?
There is a library class Color, in which some methods are available that can
manipulate Color objects. But we cannot do so as long as we don’t have a Color
object yet…
But there is more to use in classes than just methods. In some classes, ready-to-use
objects are available. Indeed, in the class Color there are some Color objects there
to be used. You can retrieve these constants by mentioning the name of the class
and the name of the constant, separated by a dot. For example:
Color.blue
Note that this time in front of the dot is not the name of an object (as in method
calls), but the name of a class. The Color object thus retrieved can be used as a
parameter when calling setColor:
g.setColor( Color.blue );
Here, g is the Graphics object that in subsequent method calls must draw in blue.
In the Color class the following constants are available:
black darkGray
red
green
blue
gray
white lightGray cyan magenta yellow orange pink
“Cyan” is the opposite of red: the blueish/green color of cyanide salts. “Magenta”
is the opposite of green: a kind of bright pink.
When you want to use the Color class, you need to import it at the start of the
program. Just as Graphics, the Color class is in package java.awt, so the import
directive is:
import java.awt.Color;
3.2
Variables
Storage in memory
In the example program, three black vertical bars are drawn. This could have been
done using the following statements:
g.fillRect(10, 0, 10, 100);
g.fillRect(50, 0, 10, 100);
g.fillRect(90, 0, 10, 100);
The first two parameters denote the position of the bars: 10, 50 and 90 pixels from
the left edge, 0 pixels from the top edge. The third and fourth parameters denote
the width (10) and height (100) of the bars.
After some experimenting, it might become clear that a width of 12 pixels rather
than 10 is esthetically more pleasing. A problem is, that we cannot change every
“10” in “12” using the search-and-replace function of the editor, because this
would also change the x-coordinate of the first bar, and moreover would change
the height of the third bar from 100 to 120. (If you think that an easy way out
would be to change the figures manually, you are right, but think of an experiment
on a more complicated picture, say the Victory Boogie-Woogie).
A solution is the use of variables. In lieu of the two constants 10 and 100, we use
two variables, say bar en height:
g.fillRect(10, 0, bar, height);
g.fillRect(50, 0, bar, height);
g.fillRect(90, 0, bar, height);
We will make sure that these variables have value 10 and 100, respectively, in
such a way that they can be easily changed when needed.
Assignment statement
In Java, variables can be changed using an assignment statement. This is done as
follows:
bar = 10;
height = 100;
Thus, an assignment statement consists of:
 the name of the variable to change;
 the symbol = , to bepronounced “becomes”;
 the new value of the variable;
 a semicolon.
If the variable has received a value before (say, with another assignment
statement) the old value is lost. And contrariwise: the new value is preserved until
the next assignment statement to the same variable. That explains why the symbol
= should be pronounced as “becomes” rather than “is”: the value of the bar
variable is not (yet) 10 (necessarily), but it becomes so by execution of the
assignment statement.
We’ve seen two statement forms by now: the method call from section 2.5, and the
assignment statement.
Variable declaration
You may not use variables at will in a program. The variables that are used must
have been announced. This is done by a so-called declaration, or in other words:
the variables need to be declared. A declaration looks like this:
int bar, height;
A declaration consists of:
 the type of the variables;
 a name or names of the variable(s), separated by commas;
 a semicolon.
A declaration is not a statement: there is nothing to do at run time. A declaration is
rather a directive for the compiler that certain variables will be used in the
program, and are of certain type.
Location of declarations
Declarations are written in the body of the method where they are needed, that is
after the opening brace. In fact, they may appear anywhere in the method body, in
between of the statements. In practice, they are listed at the beginning of the
method body, in the same fashion as a recipe starts with listing the ingredients.
After the declarations, assignment statements follow that assign values to the
variables. After that, the variables may be used:
public void paint(Graphics g)
{
int bar, height;
19
bar = 10;
height = 100;
g.fillRect(10, 0, bar, height);
g.fillRect(50, 0, bar, height);
g.fillRect(90, 0, bar, height);
}
Variable declarations resemble to parameter declarations in the method header. In
fact, those are declarations as well. But there are some differences:
 variables are declared in the method body, parameters are declared in
parentheses in the method header;
 variables receive a value by means of an assignment statement, parameters
automatically receive a value at the time a method is called;
 in a variable declaration more than one variable can be declared, writing the
type only once; in a parameter declaration the type need be repeated for every
parameter (even if it’s the same)
 variable declarations end with a semicolon, parameter declarations don’t.
The type int
By means of a declaration (both of variables in the body, and of parameters in the
header of a method), a name is connected to a type. In many instances, this is an
object type: the parameter of paint, that we’ve been naming g throughout, is a
Graphics object.
The variables bar en height in the variable declaration have type int. This
type is not an object type, and thus bar en height are not objects. Instead, they
are numbers, which are primitive values in Java. These values are built in in Java,
without having a class that lists their properties.
Primitive values, being not objects, cannot be treated by methods. They can,
however, be used as parameters to methods, as is the case in the call of
fillRect. The corresponding parameter must have been declared, in the
definition of the method, as an int.
Primitive values are not objects, and thus primitive types are not classes. That is
why int, in contrast to object types, is not written with a capital. The type int is
built in in the language, and therefore needs not be imported.
The word int is not even a name, in contrast to class names indicating object
types. The word int, and the other primitive types, are “keywords” of the
languages, just as “public” and “extends” are.
Variables (and parameters) of type int are numbers. Their value must be integral,
there can not be digits “following the decimal point”. The value can be positive or
20
negative. The largest value possible is 2147483647, the smallest is –2147483648;
the range is thus roughly plus or minus two billion.
There are only a few primitive types. Others that we will meet later are double
(numbers that can have a decimal point), char (characters) and boolean (truthvalues). All other types are object types; their properties are described in a class.
Advantages of declarations
There are various advantages of declarations:
 because of declarations, the compiler knows the intended type of each
variable; using that information it can check whether method calls make sense
(calls of fillRect only make sense when they are treating Graphicsobjects, not when other object types or int values are written before the dot);
 in method calls, the compiler can check whether parameters are of the right
type; if you would accidentally swap the text and position parameters of
drawString, the compiler would notice the error;
 when you mistype the name of a variable (for example height instead of
height), the compiler will not accept this.
3.3
Calculations
Expressions having an int value
At various places in a program, an int value is required, for example:
 as a parameter of a method call taking int-parameters
 as right hand side in an assignment statement
In these locations, you can write a constant number, like 37, or the name of an int
variable, like height. But it is also possible to write a formula involving addition
or multiplication, for example height+5. When the statement in which the
formula appears is executed, the value is calculated (using the current values of the
variables). The outcome is used in the statement.
A formula is usually called an expression in Java and other languages.
Use of variables and expressions
In the example program in listing 3.1, variables and expressions come in handy.
To make the program easily adaptable, variables are not only used for the height
and width of the drawing and the width of the black bars, but also for the positions
of the bars. The x-coordinate of the three vertical bars is stored in variables x1, x2
and x3, whereas the y-coordinate of the two horizontal bars is stored in variables
y1 en y2 (note that digits may be part of variable names, provided that it begins
with a letter). Using assignment statements all variables are assigned a value:
width = 200;
x1 = 10;
x2 = 50;
x3 = 90;
etcetera. When drawing bars, no constants are used any more (except for the value
0): all values are stored in variables:
g.fillRect(x1, 0, bar, height);
g.fillRect(0, y1, width, bar);
Using expressions we can denote the positions of the colored fields in the drawing.
The blue field to the left is located directly below the first bar. The y-coordinate of
this filed is thus one bar-width bigger than the y-coordinate of the first bar:
g.setColor(Color.blue);
g.fillRect(0, y1+bar, …, …);
Because the blue field is adjacent to the left edge, its width is equal to the xcoordinate of the first vertical bar. Even its height can be calculated using a
formula: it is the difference of the y-coordinates of the two horizontal bars, minus
own bar width. The blue filed can thus be drawn using:
g.fillRect(0, y1+bar, x1, y2-(y1+bar) );
The red field at the top can be described in a similar way.
Operators
In int expressions you can use the following arithmetic operators:
 + addition
 - subtraction
 * multiplication
 / division
 % remainder after division
For multiplication, an asterisk is used, because the usual mathematical symbols (
of  ) are not on the keyboard. Leaving the multiplication operator out altogether,
as is sometimes done in mathematics, is not allowed, as this would be confusing in
the presence of multi-letter variable names.
When using the division operator / the result is rounded, because the result of an
operator on two int values is again an int value in Java. Round-off is done by
leaving out figures after the decimal point; positive values are therefore always
rounded “down” (and negative values always “up”). For example: the value of the
expression 14/3 is 4.
The unusual operator % calculates the remainder after division. The result of 14%3
for example is 2, and the result of 456%10 is 6. De result will always be a number
between 0 and the right hand side operand. The result is 0 if the division is exactly
possible.
Operator precedence
When more than one operator appears in an expression, the usual operator
precedence holds: “multiplication precedes addition”. Thus, the result of 1+2*3 is
7, not 9. Addition and subtraction have equal precedence, and multiplication and
the two forms of division as well.
When operators of equal precedence are used in one expression, it is evaluated left
to right. Thus, the result of 10-5-2 is 3, not 7.
If you want to digress from these precedence rules, you can use parentheses in an
expression, as in (1+2)*3 or 3+(6-5). In practice, expressions involving only
constants are rare, because you could just as well have written the result (9 or 4)
yourself.
A superfluous pair of parentheses is allowed: 1+(2*3), and the compiler not
even objects to exaggeration, as long as the parentheses are balanced:
((1)+(((2)*3))). Of course, expressions like this are harder to read for the
human reader.
3.4
Program layout
Comments
For human readers of a program (a co-programmer, or you yourself a couple of
months later, when you’ve forgotten about the details) it is very useful if the
program is explained with comments. Comments are ignored by the compiler, but
make the program easier to understand.
In Java, there are two ways to write comments:
 put text between the combination of symbols /* and the subsequent */
(possibly a few lines further down)
 put text between the combination of symbols // and the end of the line
21
import java.awt.Graphics;
import java.awt.Color;
import java.applet.Applet;
/* This applet draws a Mondrian-like
"composition with red and blue”
*/
public class Mondri extends Applet
{
public void paint(Graphics g)
{
int width, height, bar, x1, x2, x3, y1, y2;
// positions of the bars
width = 200; x1 = 10; x2 = 50; x3 = 90;
height = 100; y1 = 40; y2 = 70;
bar
= 10;
// background
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
// black bars
g.setColor(Color.black);
g.fillRect(x1, 0, bar, height);
g.fillRect(x2, 0, bar, height);
g.fillRect(x3, 0, bar, height);
g.fillRect(0, y1, width, bar);
g.fillRect(0, y2, width, bar);
// colored fields
g.setColor(Color.blue);
g.fillRect(0, y1+bar, x1, y2-(y1+bar) );
g.setColor(Color.red);
g.fillRect(x3+bar, 0, width-(x3+bar), y1);
}
}
Things that are useful to comment upon are: groups of statements belonging
together, methods as a whole and the intention of the parameters, and even classes
as a whole.
It is not really helpful to rephrase the Java statement in English; you may assume
that the reader understands Java. In the example program, the following comment
is used:
// positions of the bars
x1 = 10; x2 = 50;
rather than
// make variable x1 equal to 10, and x2 to 50
x1 = 10; x2 = 50;
During the test phase of the program, comment symbols may be used to disable
statements temporarily. Remember to remove statements that are “commented
out” from the final program.
Distribution over lines
There are no general rules for the distribution of Java source code over the lines of
a file. The compiler enforces no strict rules. It is customary, though, to write each
statement on a separate line. But when it improves readability, the programmer
may decide to write more than one statement on one line (in the example program
this is done with some relatively short assignment statements). For very long
statements, on the other hand, it is a good idea to use multiple lines.
Readability is improved furthermore by leaving a line blank once in a while, for
example between methods, en between groups of statements (and their
accompagning comments) that belong together.
White space
Also, for the placement of spaces there are no strict rules. The only place where
they are strictly needed is between adjacent words: public static void
may not be written as publicstaticvoid. In reverse, you may not add extra
spaces in the midst of a word, for it would split the word in two.
Text in quotes is always taken literally, including spaces. There is a difference
between
g.drawString("hello", 10, 10 );
g.drawString("hello", 10, 10 );
and
Listing 3.1: Mondri.java
22
g.drawString("h e l l o ", 10, 10 );
Apart from these situations, extra spaces are allowed everywhere.
Most programmers put extra spaces
 following each comma and semicolon (but not preceding it)
 left and right of the = sign in assignment statements
 at the start of lines, indenting bodies of classes and methods (normally, 4
positions) relative to the braces that delimit the class or method.
Figure 3.1: The Mondri program running
23
4. New methods
4.1
Method definition
Order out of chaos
Drawing a square and two slanted lines on top of it makes a simple house. The
example applet in this chapter draws three houses, as shown in figure 4.1. These
three houses could have been drawn using the paint method below:
public void paint(Graphics g)
{
// small leftmost house
g.drawRect(20,60,40,40);
g.drawLine(20,60,40,40);
g.drawLine(40,40,60,60);
// small house in the middle
g.drawRect(70,60,40,40);
g.drawLine(70,60,90,40);
g.drawLine(90,40,110,60);
// large rightmost house
g.drawRect(120,40,60,60);
g.drawLine(120,40,150,10);
g.drawLine(150,10,180,40);
}
Despite the comments number numbness strikes us. For example, what numbers
should be changes when on second thoughts the leftmost, rather than the rightmost
house should have been the large one? To accommodate this change, you’d need
to rethink all statements, and if you are not careful while doing so, there is a fair
chance that one of the roofs ends up in the air. Besides, this program only draws
three houses; extending the program to draw ten houses is downright boring.
We are going to create some order out of this chaos, using methods.
New methods
Methods are intended to group statements that belong together, and treat them as a
whole. When the group of statements need to be executed, you can do so by
calling the method.
24
Figure 4.1: applet Houses running
In the example, clearly the three statements that draw each house belong together
(the call to drawRect and the two calls to drawLine). These three statements
therefore are a candidate to group in a method: in the paint method, the will only
be three calls to this newly defined method left. The setup is as follows:
public class Houses extends Applet
{
private void drawHouse(…)
{
….drawRect(…);
….drawLine(…);
….drawLine(…);
}
public void paint(Graphics g)
{
….drawHouse(…);
….drawHouse(…);
….drawHouse(…);
}
}
Two methods are defined: next to the obligatory paint, there is another method that
draws only one house, which is why it is called drawHouse. The name may be
chosen at will, and it is a good habit to choose the name descriptively.
Whenever the browser needs to draw the applet, it calls paint. It is irrelevant
whether the method is or isn’t the first method in the class: whatever is in the
class, it is the method called paint which is called first. Only when the paint
method does a call to the drawHouse method, the statements in the body of
drawHouse are executed. After that, paint continues with the next statement,
which happens to be another call to drawHouse – hence a second house is drawn.
The third call in paint draws a house as well, and only after that program execution
is continued on the location from which paint was called.
Methods involve an object
The program skeleton is complete by now, but there are some details to be filled in
(indicated in the skeleton by ellipses). First, we consider the question: what is
written in front of the dot in the calls to drawRect, in the body of drawHouse?
Each method that is called involves a particular object (the paradigm is object
oriented, after all); it is the object mentioned before the dot. For example, the
drawRect method involves a Graphics-object.
Up till now, we’ve been using the Graphics-object that was available as a
parameter in the paint method (and that we’ve been calling g). That parameter,
however, is not available in the body of the drawHouse method.
Method parameters
We need to make sure that in the body of the drawHouse method, a Graphicsobject is available as well. We can do so by providing drawHouse with a
Graphics-object parameter. In the body, that object can be used as the object
involved when calling drawRect and drawLine:
private void drawHouse(Graphics gr, …)
{
gr.drawRect(…);
gr.drawLine(…);
gr.drawLine(…);
}
For a change, we called the parameter gr instead of g. After all, as a programmer
you are free to choose the names of the parameters. Of course, when you use the
parameter in the method body, you have to use the same name, so in the calls to
drawLine we use the Graphics-object gr.
The name of the parameter type can not be chosen at will: the object type
Graphics is an existing library class, which may not be called PencilSet or
whatever.
Now that we have specified that drawHouse takes a Graphics object as its first
parameter, we need to make sure that when calling drawHouse, indeed a Graphics
object is provided. Luckily, the call to drawHouse is done in the paint method,
which has a Graphics-object available: the object that the browser passes as a
parameter to paint. The calls to drawHouse look as follows:
public void paint(Graphics g)
{
….drawHouse(g, …);
….drawHouse(g, …);
….drawHouse(g, …);
}
Method drawHouse is only called by paint, not by the browser (that is, not
directly). Therefore, drawHouse can be declared to be a private method: it is for
“internal” use only.
Note that there is only one Graphics-object, that is called differently by the various
methods: in paint, the object is called g, whereas in drawHouse it is called gr.
Probably the browser called the object, before it passed it as a parameter to paint,
by yet another name. Or maybe not… It doesn’t really matter: methods may
choose themselves what the name of their parameters is, and callers of the method
need not know these names. Method callers need only to make sure that the
parameters they provide are of the right type.
The this object
The next detail to be filled in is the object in front of the dot in the calls to
drawHouse. Which object is involved at this call? Which object is involved, for
that matter, in executing the paint method itself?
It is certainly not a Graphics-object. Graphics-objects, after all, only know draw…
and fill… methods, not a paint method, let alone a drawHouse method.
The object involved with method calls is of the object type that appears in the
header of the class in which the method is defined. For example, method drawRect
involves a Graphics object, because drawRect is defined in class Graphics.
Now, as paint and drawHouse are defined in class Houses, they consequently
involve a “Houses-object”. Such an object is created by the browser, after which
the browser calls the paint method, involving that object. In the body of paint, we
need to use the very same object to be involved with the call to drawHouse. But
how do we address “the” object involved? That object is not a parameter, so we
didn’t have the opportunity to give it a name in the method header.
The solution is, that in Java the object involved with a method can be referred to
using the word this. This can be written at each occasion where “the object
involved” is needed. It comes in useful in the body of paint, because drawHouse
involves the same method that is involved with paint:
25
public void paint(Graphics g)
{
this.drawHouse(g, …);
this.drawHouse(g, …);
this.drawHouse(g, …);
}
The word this is exclusively reserved for the purpose in Java. You may not use
it as a name of a variable or things alike (as was neither the case with other
reserved words, such as class, extends, void, public, private and
int).
In each method, this refers to an object. Its object type is the class mentioned in
the header of the class in which the method is defined.
4.2
In search for parameters
Parameters make methods more flexible
The boring details –making sure that all methods can access the necessary
Graphics- and Houses-objects– are filled in now, and the fun part starts: the hunt
for the remaining parameters.
Up till now, we assumed that the house-drawing statements (drawRect and two
times drawLine) were the same in all three houses, and could therefore be
executed with three calls to drawHouse. But the house-drawing statements are not
exactly the same: for each house, the values passed as a parameter to drawRect
and drawLine are different.
Let’s have a look at the calls to drawRect in the initial (chaotic) version of the
program:
g.drawRect( 20, 60, 40, 40);
g.drawRect( 70, 60, 40, 40);
g.drawRect(120, 40, 60, 60);
The first two numbers are the coordinates of the rectangle’s top left corner, the
other two numbers are the width and height of the rectangle, respectively. Because
we’re drawing squares, width and height are equal: 40 for the small houses, 60 for
the big one.
So the width (also acting as height) is not the same in the three instances.
However, if the desired width were available as a parameter, we could specify the
desired width in each call.
The same holds for the coordinates: they being different for each call, we let the
caller of drawHouse specify them, as well. For the caller, it is probably more
convenient to specify the lower left corner rather than the upper left corner: the
26
coordinates of the upper corners are different for houses of different size, whereas
the y-coordinate for houses in a row are the same regardless of house size. This
can be settled for: we arrange that the y-coordinate specified is the position of the
base line, and the y-coordinate of the top left corner can be calculated with an
expression:
private void drawHouse(Graphics gr, int x, int y, int w)
{
gr.drawRect(x, y-w, w, w);
gr.drawLine(…);
gr.drawLine(…);
}
public void paint(Graphics g)
{
this.drawHouse(g, 20, 100, 40);
this.drawHouse(g, 70, 100, 40);
this.drawHouse(g, 120, 100, 60);
}
The parameters for the two calls of drawLine (the coordinates of starting and
ending points of the two lines forming the roof) are different for each of the three
houses. However, it is not necessary to provide additional parameters for them, as
the coordinates can be calculated form the position and size of the square, which
are already available as parameter.
The coordinates of the roof top point are needed twice: as ending point of the first
line, and as starting point of the second line. To avoid doing the calculation twice,
we use variables to store these coordinates temporarily. These variables are only
needed in method drawHouse, and therefore declared locally:
private void
drawHouse(Graphics gr, int x, int y, int w)
{
int topx, topy;
topx = x + w/2;
topy = y - 3*w / 2;
gr.drawRect(x, y-w, w, w);
gr.drawLine(x, y-w, topx, topy);
gr.drawLine(topx, topy, x+w, y-w);
}
Flexibility carried to extremes
Now that we’ve decided to specify the lower left corner of the house (rather than
the upper left corner of the wall), the y-coordinate turns out to be equal in all three
calls to drawHouse, namely 100. In hindsight, the parameter turns out to be
superfluous, as we could have written 100 in the body of drawHouse instead of y.
However, it is no problem to have “too many” parameters: who knows, in the
future we might wish to draw houses at another base line than 100, in which case
the method would be prepared for the situation.
The question is how flexible a method needs to be made by adding parameters.
The method drawHouse as developed can only draw houses with a square facade.
It is feasible to pass width and height of the facade as separate parameters, because
we might want to draw non-square houses in the future, and we’d be prepared for
the situation. And maybe the roof height should be specifiable as well, in order to
draw houses with flat or steep roofs. And a color-object could also be passed as
parameter, in order to be able to draw colored houses. Or make that two colors:
one for the facade, and one for the roof…
The price of all the extra parameters is that they have to be specified at each call.
When the caller has no intention to use the degrees of freedom possible, the extra
parameters are an unnecessary burden.
Balance should be found between the expenses of extra parameters (both for the
method writer and for the method caller), and the probability that the extra
flexibility is needed in the future.
Flexibility in the large
The same dilemma occurs with programs as a whole. Users like flexible software,
which can be configured to their needs. But when they need to enter long lists of
options before they can use the program, they tend to be annoyed. Also,
unnecessary options make the program complex and (therefore) expensive.
It is easy to judge in hindsight, but could programmers have foreseen that in the
future there would be a need for a 4-digit year rather than a 2-digit one? (Yes).
Should we, in our present software, be prepared for a future decision to introduce a
13th month, each month having 28 days? (Well, no). Should the user of financial
software be able to enter the current VAT rate? Or should the user, when the rate
changes, be forced to buy a new version of the program? Should the software be
prepared for a “medium” VAT rate, next to the current “low” and “high” rates?
And that the currency unit might change? Or the currency unit symbol?
In programs where time is involved, should the user be able to enter the day on
which daylight saving time ends? Or should the rule for it (last Sunday of October)
be built in in the program? And what if the rule changes (which happened a few
years ago)? Or should the user be able to specify the DST-end date rule himself? If
so, could/should he first choose the language in which to spell “October”?
4.3
Methods having a result
Function calculation
Using parameters, a method caller can specify values (int values as well as
objects) to a method, to be used in the method’s body. However, this is one-way
communication: the method can not “talk back” to the caller.
Sometimes, this is needed nevertheless. Compare mathematics, where functions
are calculated. You can “call” a method, such as square, by providing it with a
parameter: square(5). The function calculates the result, which is 25 in this case.
The answer is available to the function’s caller.
In Java methods can, as can functions in mathematics, calculate a value to be used
by the method’s caller. Just as in mathematics, functions can have multiple
parameters, but only one result value. A result value may be a primitive value such
as an int, but a result value may also be an object value.
A method’s result type
Analogous to parameters, method result values have a type. The result type might
be int, if the method returns an integer number, but also e.g. the object type Color,
if the method returns a Color object.
The method’s result type needs to be specified in the method header, immediately
in front of its name. For example, the header of a method square could look like
this:
private int square(int x)
If the method does not have a result, the word void serves as result type.
The return statement
In the body of a method having a result, somehow the result should be described.
Java has a special statement form for the purpose: the return-statement. The
body of the square method has a single return statement as its body:
private int square(int x)
{
return x*x;
}
The return statement consists of the word return (which is reserved for this
purpose), followed by an expression. As are assignment statements, a return
statement is terminated with a semicolon.
27
When a return statement is executed, the expression is evaluated, using the current
values of variables and parameters. That value is returned as a result to the caller
of the method.
Preceding the return statement, other statements might appear, doing some
preparations. For example, the following method calculates (x+1)3 given a
parameter x:
private int successorsThirdPower(int x)
{
int s;
s = x+1;
return s*s*s;
}
In theory, a return statement could appear in the midst of a method body; also, two
return statements might appear in one method:
private int strange(int x)
{
return x*x;
return x*x*x;
}
The method is called “strange”, for what is it that this method returns: the square
of the parameter, or its third power? At the first return statement the square is
calculated and given back to the caller, and the method is terminated at the same
time. The strange method never lives long enough to calculate any third power.
Although it is allowed in theory to write return statements at other than the last
line of a method, in practice this is never sensible: statements following the first
return statement can never be executed. The compiler will warn you that the
method contains “unreachable code”.
The word “return” can be understood in two ways:
 “give back”: the value of the expression in the return statement is given back
to the caller of the method;
 “go back”: after executing the return statement the processor goes back to the
caller, regardless any possible statements following the return statement.
Method calls
Calls of methods with a result value differ form calls of methods whose result type
is void. This is because the caller must accept the value that is returned,
somehow.
Calling a void method takes the form of a statement in itself, e.g.:
g.drawString("hello", 10, 10);
28
Calling a non-void method, however, takes the form of an expression. The
expression does not stand alone, but can be used in a statement, for example the
right hand side of an assignment statement:
k = this.square(5);
But a call of the square method can also occur on other places where an int-value
is needed, for example as a parameter of another method:
g.drawString("hi", this.square(3), this.square(4));
You can use the result value of a method as part of a bigger expression. Finally,
the big expression will be needed in a statement (be it an assignment statement, or
call of a void method):
p = this.square(4) + this.square(this.square(3));
// This applet draws three houses of various size
public class Houses extends Applet
{
// draw a house with lower left corner (x,y)
private void drawHouse(Graphics g,
int x, int y, int w)
{
int topx, topy;
topx = x + w/2;
topy = y - 3*w / 2;
g.drawRect(x, y-w, w, w);
g.drawLine(x, y-w, topx, topy);
g.drawLine(topx, topy, x+w, y-w);
}
public void paint(Graphics g)
{
int x, y;
x = 20; y = 100;
this.drawHouse(g, x, y, 40); x = x+50;
this.drawHouse(g, x, y, 40); x = x+50;
this.drawHouse(g, x, y, 60); x = x+70;
}
}
Listing 4.1: Houses.java
5. External input
5.1
Parameterizing applets
Method paint has a single parameter
Up till now, each applet had the same output every time it is run. That way, an
applet have no advantages for an HTML-page over an image, included with an
<IMG>-tag. It would be an enhancement, if you could provide an applet with
parameters: you could start the applet twice, with different parameters in each
instance.
It is not possible to add extra parameters to the paint method. The browser
assumes that paint has exactly one parameter, being of type Graphics. When the
header of the paint method is not exactly as expected by the browser (public, result
type void, one Graphics object as parameter), it is not recognized, and nothing will
happen when you run the program.
It is possible, though, to provide an applet with parameters at the call from the
HTML-file. We will make an applet again that puts “Hello!” on the screen; this
time the message is personalized for a specific person, for example “Hello,
Jeroen!”. The name to be used is specified in the HTML-file, and as such this
program is an example of parameterizing an applet.
Class extensions inherit methods
To understand how this is done, we need to investigate the meaning of extends
in the class header. A class header like
class Houses extends Applet
indicates that a number of methods follow, that involve Houses-objects. The
phrase extends Applet means that Houses-objects in addition know all
methods defined in class Applet. Using extends in the class header, you can
extend existing classes: each Houses-object is an Applet-object as well: quite a
special Applet-object in fact, that knows about some more methods.
methods is needed for passing information from the HTML-file to the applet: the
getParameter method.
Multiple parameters can be passed to an applet. By calling getParameter more
than once, you can get one at a time. The getParameter method takes as its
(method-)parameter the name of the (program-)parameter that you want to get. As
its method result it returns the value of the (program-)parameter requested. Both
the name and the value of the program-parameter are texts.
Texts play such an important role in Java programs, that there is a library class in
which some methods dealing with texts are located. The class is called String; a
String-object thus represents a text.
Both parameter and result of getParameter are of type String. The String return as
a result, can be temporarily stored in a variable, declared to have String type:
String person;
person = this.getParameter("firstname");
Now we have to make sure that the HTML-file indeed supplies a program
parameter with that name. The HTML-tag <PARAM> serves the purpose, to be
placed in between of the <APPLET>-tag and the </APPLET>-tag, as in:
<APPLET code=Greeting.class width=200 heigth=50>
<PARAM name=firstname value=Jeroen>
</APPLET>
The name of the program parameter (in this example: firstname), must be
represented in the Java program as a string, and therefore appears in quotes:
"firstname". The value which appears in the HTML-file following value=
(in the example: Jeroen) is available to the Java program as the result value of
getParameter.
The situation is rather complicated, because two kinds of parameters are taking
part of the scene: method-parameters and program-parameters. Especially, note
that the name of a program-parameter (in the example: firstname) is not a
Java-variable or –parameter, and thus needs not be declared in the program. The
name of a program-parameter is treated as a text in the Java program, hence the
quote marks in "firstname" in the Java program.
Methods in class Applet
It is worthwhile to learn about Applet’s methods: they can be used from each
method of extension classes of Applet, using the object this. One of Applet’s
29
5.2
Class String
Declarations of object references
Using declarations, you can create variables, to which you can subsequently assign
values using assignment statements. The value can be a constant, but also the
result of a method call. Some variables are of primitive type, such as int:
int x, y;
x = 37;
x = this.square(5);
But some variables have an object type, like String:
String s, t;
s = "hello";
t = this.getParameter("firstname");
In the case of object variables, the variable in fact does not contain the object
directly, but rather a reference to the object. In the assignment to variable t in the
fragment above, not a copy is made of "Jeroen" (or whatever String is returned
by getParameter), but a new reference is created to an already existing Stringobject.
Assignments to variables having an object type always take the same (short) time,
whether the object be large are small. Variables of object type always consume the
same amount of memory (4 bytes). The same holds for parameters of object type:
not the objects themselves are passed as parameters, but references to them are.
String expressions
For primitive values of type int, various expression forms exist: constants,
variables, operator expressions (see section 3.3), and calls of methods having an
int result (see section 4.3).
Values of object type String can be denoted in different ways as well:
 constant texts in quotes, like "hello"
 variables declared as a String
 call of methods with String result
 use of operator + between two Strings
The latter possibility is interesting: you can “add” two String objects, the result of
the addition being a String object, consisting of the two texts joined together.
Those two strings can themselves be constants, variables, results of method calls,
or even of addition of two more strings. “Addition” may not be an apt word for
this operation; “joining” is a better description.
30
All four expression forms occur in the final listing for the personal greeting, as
appears in listing 5.1.
5.3
Utility classes
Calculations involving rectangles
As a more elaborate example of program parameters, we introduce another applet.
The program is called Rectang, and calculates some properties of a rectangle
(perimeter, area and diagonal length). The width and height of the rectangle are
specified as program parameters to the applet. Furthermore, the program is an
example of the use of a few important library classes.
Listing 5.2 shows the complete program, and figure 5.2 shows the running applet.
Class Integer
Strings and int values are of different type. There is an essential difference
between the number 37 (an int value) and the text "37" (a String value, which
happens to contain digits only). The difference becomes clear when you try to add
them: 37+1 is 38, whereas "37"+"1" is "371".
In the example program width and height of the rectangle are provided as program
parameters, which are String objects. Before we can use the values in calculations
(area, for example, is width times height), we’ll have to convert the String objects
to int values.
Luckily, there is a library method that does the conversion. The method is named
parseInt, and resides in class Integer.
Class Integer is in package java.util, but you need not import this class, as
all classes in package java.util are imported automatically.
Class Math
For more serious mathematical operations, a class Math exists, loaded with
methods calculating all kinds of mathematical functions. Among others, the
following methods can be found in class Math:
 abs
absolute value
 sqrt
square root
 sin
sine of an angle (in radians)
 exp
e raised to the power of…
 pow
base raised to the power (base and exponent given as parameter)
 log
logarithm
Type double
Next to type int, type double exists. This is a primitive type as well: no
methods are applicable to double values. In a variable of type double you can
store a number, which may have digits following the decimal point.
Mathematical operators +, -, * en / can be used on double values as well as on int
values. Only operator % can be used solely on int values.
All methods from class Math mentioned in the previous paragraph have
parameters of type double, and return a double result. Where a double value is
needed, however, you may provide an int value. The value is converted
automatically. The other way around is not possible, for you cannot convert a
double to an int without loosing information (the digits following the decimal
point).
When using arithmetical operators, the result is a double value when at least one
of the operands is. The result is only an int value if both operands are.
Method parseInt from class Integer is static as well. It can be called as in:
Static methods
With all these library methods, you might ask what is the object that is involved.
Consider for instance the square-root calculating method sqrt: it takes a double
as parameter, returns a double result, but no further objects are involved. So what
object should we write in front of the dot, in a call to sqrt?
Writing this is no solution. When we want to calculate a square root from within
paint, the word this is a denotation for the object that is involved with paint,
that is an (extension of an) Applet-object, which is not a Math-object. Then, what
is a Math-object supposed to be?
The solution is that no Math-object whatsoever is needed. The methods in class
Math are so-called static methods. Static methods, as opposed to normal methods,
do not treat an involved object; the methods receive all necessary information via
their parameters.
Related differences are:
 in the method header, the word static appears in front of the result type;
 with method calls, you need not write an object before the dot; instead, you
write the name of the class;
 in the body of the method you may not use the word this: after all, there is
no object involved.
A call to method sqrt could look as:
"Dimension " + length
String lengthAsText;
int
lengthAsNumber;
lengthAsText
= this.getParameter("length");
lengthAsNumber = Integer.parseInt(lengthAsText);
Calculations with rectangles
The rectangle program is straightforward now. First, the program parameters
length and width are retrieved by calls to getParameter. Because they return String
values, the results need to be converted to numbers by calls to parseInt. The
numbers are used for the calculations. The sqrt method is used to calculate the
diagonal, according to Pythagoras’ theorem.
Finally, the results are drawn on the screen using drawString. The strings to be
shown are built using the + operator, in its “joining” sense. Even when one of the
operands of + is a number (int or double), strings are joined, as in the expression
In situations like this, the number is automatically converted to string first.
double diagonal;
diagonal = Math.sqrt(2);
31
import java.awt.Graphics;
import java.applet.Applet;
public class Greeting extends Applet
{
public void paint(Graphics g)
{
String person, greeting;
person
= this.getParameter("firstname");
greeting = "Hello, " + person + "!";
g.drawString(greeting, 50, 20);
import java.awt.Graphics;
import java.applet.Applet;
public class Rectang extends Applet
{
public void paint(Graphics g)
{
String lengthText, widthText;
int length, width, perim, area;
double diag;
lengthText = this.getParameter("length");
widthText = this.getParameter("width");
}
}
length
width
perim = 2*(length+width);
area = length*width;
diag = Math.sqrt(length*length+width*width);
Listing 5.1: Greeting.java
<HTML>
Here is an applet, that calculates some properties
of rectangles: <BR>
<APPLETcode=Rectang.class width=200 height=120>
<PARAM name=length value=12>
<PARAM name=width value=8>
</APPLET>
<HR>
Here is the applet again, this time for
another rectangle: <BR>
<APPLET code=Rectang.class width=200 height=120>
<PARAM name=length value=7>
<PARAM name=width value=3>
</APPLET>
</HTML>
Listing 5.2: Rectang.html
32
= Integer.parseInt(lengthText);
= Integer.parseInt(widthText);
g.drawString("RECTANGLE",
g.drawString("Dimensions "
+" times "
g.drawString("Perimeter is "
g.drawString("Area is "
g.drawString("Diagonal is "
}
}
Listing 5.3: Rectang.java
50, 20);
+
+
+
+
+
length
width,
perim,
area,
diag,
50, 40);
50, 60);
50, 80);
50,100);
6. User interaction
6.1
Interaction via objects
A color mixer
In the previous chapter the program was parameterized: by specifying values in
the HTML-file, the behavior of the program could be influenced. Once started, the
execution of the program was fully determined, and the user could do nothing but
watch. In most programs, however, the user is enabled to actively influence the
program execution. For this purpose, interaction components are available on the
screen, such as buttons, sliders, editable texts, menus, etc.
In this chapter we’ll study a program where the user can determine the color of
plane using three sliders; thus the program is a color mixer. Furthermore, there is a
button labeled “black”, which when pressed resets all sliders.
The program is quite short, but many programming principles are discussed. The
techniques used in this program are needed in every program interacting with a
user.
All interaction components (the three sliders and the button) are modeled in the
program as separate objects. In the Java library there are classes for all standard
interaction components, so we’ll certainly need to know about these classes.
Four ways to acquire an object
Here is a summary of ways to get an object. Up till now, we’ve seen three of them:
 the object is given as a parameter to a method (e.g., the Graphics parameter of
paint);
 the object is returned as the result value of a method (e.g., the method
getParameter, which returns a String object);
 the object is returned as the result value of an operator (e.g., the operator +
which, given two strings, returns a string).
There is, however, a fourth way to get access to an object:
 the object is created from scratch.
6.2
Creating new objects
Constructor methods and new
Java has a dedicated mechanism for creating brand new objects, without using
other, already existing objects in the creation process. In most classes a so-called
constructor method is available for the purpose, which can be used to create new
objects of the class.
When calling a constructor method, the following happens:
 somewhere in memory, space is reserved for storing the new object;
 the new object is treated by executing the statements of the constructor
method, in order to put the object in some sensible state;
 the new object (or rather, a reference to it) is returned as the result of the
constructor method.
The constructor method always has the same name as the class (which begins, as
an exception to the general rule for method names, with a capital). For example:
the constructor method to create new Color objects is named Color, and the
constructor method to create new Button objects is named Button.
Calling a constructor method is done in a special way. The usual form of method
call (object-dot-method name) is not possible, because there is not (yet) an object
available to write before the dot: it is the object we are about to create!
To call a constructor method, you write the word new, followed by the name of
the constructor method, followed by possible parameters. Note that there is no dot
between the word new and the method name. The word new is yet another
reserved word, only to be used in this specific situation. Here are two examples of
calls to constructor methods:
new Color(0,0,0)
new Button("press here")
The new construction is an expression
Calling a constructor method using new is a form of expression. The two examples
above consequently are not statements (which you can also tell from the fact that
they were not terminated by semicolons). It is an expression, because a constructor
method always has a result value: the newly created object (or more precisely: a
reference to it). The result value can be stored in a variable using an assignment
statement. The variable needs to be declared first.
Some examples are:
33
Color c;
Button b;
c = new Color(0,0,0);
b = new Button("press here");
But you can also use the newly created object in different ways, for example as a
parameter of a method expecting an object of that type:
g.setColor( new Color(0,0,0) );
New color objects
As can be seen from the examples above, the constructor method of Color takes
three int values as parameter. The values must be between 0 and 255. They
represent the amount of red, green and blue light in the new color. Imagine the
color to be mixed from three colored spotlights (which works the other way
around as you would expect from mixing paint). Examples of mixed colors are:
 new Color( 0, 0, 0)
no light, i.e. black
 new Color(255, 0, 0)
intense red
 new Color( 0,255, 0)
intense green
 new Color( 0, 0,255)
intense blue
 new Color(128, 0, 0)
between black and red, i.e. dark red
 new Color(255,255, 0)
red light plus green light gives yellow
 new Color(255,128, 0)
between red and yellow, i.e. orange
 new Color(255,255,255)
all spotlights on makes white
 new Color(128,128,128)
between black and white is gray
 new Color(255,128,128)
between red and white is pale red
 new Color(123, 37, 95)
try and see…
If you are not satisfied with the thirteen standard colors discussed in section 3.1
(Color.blue etc.), you can mix every shade you like calling the constructor
method Color. In total, 256*256*256=approx. 16 million colors are possible,
which is known as “true color” in hardware jargon.
6.3
The class Applet
Redefining method paint
In class Applet, there are a number of methods that are important for interacting
with the user.
34
To start with, there is method paint, having a Graphics parameter. The method is
defined in Applet, but has an empty body. Consequently, when the method is
called, nothing happens.
When you want to make an applet that does paint something, you need to make an
extension class of Applet, in which you define the method again. This is what we
did in all earlier examples. Remember that in an extension class, you can add new
methods (like method drawHouse in class Houses), but also inherit all existing
methods (see section 5.1). But you can also define a method again, which was
already inherited. When the method is called, the statements in the body of this
redefinition are executed.
Redefinition of method paint in extension classes of Applet is a clever trick. The
browser “naively” calls in method paint; by having redefined it, we’ve
successfully trapped it, and now we are in control of the program…
Calling paint indirectly via repaint
Method paint (the redefinition, or if it was not redefined, the empty default
definition existing in Applet) is called automatically by the browser each time the
screen needs to be drawn. This is the case at the beginning of program execution,
but also in situations where the window has been obscured by another window and
is re-exposed.
Sometimes, we would like to call paint from within the program. For example,
when the user has used an interaction component, and in reaction to that the screen
image needs to be modified. Unfortunately, you cannot call paint directly: it needs
a Graphics object as a parameter, which is not easy to get.
But the situation was anticipated. It is possible to call method repaint, available
in Applet. This method magically obtains a Graphics object, clears the screen, and
subsequently calls paint. If paint was redefined, it calls the redefined version,
which is the desired effect.
Redefining method init
Apart from paint there is another Applet method called by the browser, namely
the parameterless method init. Like paint, it has an empty body. It is meant to
be redefined in extension classes of Applet. That way, we can set another trap for
the browser.
Method init is called only once by the browser when the applet is first created,
even before paint is called first. This makes init the ideal place for statements
that need not be executed each time the window is drawn, but only once. Creation
of interaction components (calling new Button) is typically done in init.
Calling method add
In programs where a button is needed, method init can be redefined as follows:
public void init( )
{
Button b;
b = new Button("press here");
However, this is not the full story. The button is present in memory after execution
of this statement (reachable via object reference b), but this does not imply that
the button is visible. In order to do that, it is necessary to call method add. That
method is, like init, member of class Applet, and hence can be called involving the
object this. As a parameter, add takes the interaction component that must be
visualized:
this.add( b );
}
Interaction components thus added to the applet are automatically drawn, so you
need not care about them in paint.
6.4
Interaction components
Class Button
In package java.awt (“abstract window toolkit”) there are a number of classes
modeling interaction components.
Class Button models “push buttons” shown on the screen. The program can be
set up to execute designated statements when the user “presses” (that is: clicks
with the mouse) the button. This way, the program can react on user actions.
As described in the previous section, by calling the constructor method (also
named Button), you can create new objects for every push button needed in the
program. Two methods form class Button are of particular interest:
 Button: the constructor method
 setLabel: to modify the text appearing on the button
Both methods take a string parameter, which is shown on the button as soon as it
is added to the applet calling method add.
Class Scrollbar
Another interaction component we’ll use in the example program is Scrollbar.
Scrollbars are often used at the edge of windows, to scroll the contents of the
window. But it is also possible to use stand-alone scrollbars. Then, it acts like a
kind of slider, using which the user can determine a value.
Three methods of Scrollbar are of particular interest:
 Scrollbar: the constructor method, having no less than five parameters:
 Orientation of the scrollbar: horizontal or vertical. You can specify the
desired orientation by using one of two constants available for this
purpose in class Scrollbar: Scrollbar.HORIZONTAL or
Scrollbar.VERTICAL.
 The initial value
 The amount of change when the user clicks next to the slider
 De minimum value (slider to the left)
 De maximum value (slider to the right)
 setValue: a method to change the value of the scrollbar, and hence the
position of the slider. There is one int parameter, indicating the desired value.
The value should be bounded by the minimum and maximum value as
indicated when calling the constructor method.
 getValue: a method to retrieve the current value of the slider. The method
takes no parameters, but does have a return value.
Importing everything
Programs often use many classes from the awt library. In principle, they should all
be imported:
import java.awt.Button;
import java.awt.Scrollbar;
etcetera.
In practice, the list of imports tends to become long. Therefore, it is allowed to
import all classes from a library in one go:
import java.awt.*;
You’ll also import the classes you don’t need, but normally the will do no harm
(unless you’ve used one of the imported class names for other purposes).
Constructing and using Scollbar objects
In the example program, we’ll create three scrollbar objects, for letting the user
control the amounts of red, green and blue light. Therefore, we declare three
variables:
Scrollbar red, green, blue;
35
In method init these variables are made to refer to newly created objects:
red = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 255);
gren = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 255);
blue = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 255);
By three calls to add they are made visible:
this.add(red);
this.add(green);
this.add(blue);
declared here are permanently part of the object; in fact, they are the object. That
is why they are called object variables.
The program skeleton is thus as follows:
Class Mixer extends Applet
{
Scrollbar red, green, blue;
public void init()
{
red = new ScrollBar(…,…,…,…,…);
this.add(red);
…
}
In method paint we will draw a colored rectangle with color as specified by the
sliders. To know te position of the slides, we can call getValue:
int rv, bv, gv;
rv = red .getValue();
gv = green.getValue();
bv = blue .getValue();
Using the three values obtained we create a new Color object, to determine the
color of the rectangle:
Color c;
c = new Color(rv, gv, bv);
gr.setColor(c);
gr.drawRect(0,0,100,100);
Here, gr is the Graphics object available in paint.
Object variables
A problem arises with this approach: where to put the declarations of the three
Scrollbar objects red, green en blue?
These variables are needed in init (in the assignment statements, and as
parameter of add). But they are also needed in paint (to request the current value
of the sliders). If we would declare the variables in one of the two methods, the
compiler will complain that they are not declared in the other method. But
declaring them in both methods is not a way out: declarations are only valid
locally, so variables declared in different methods are not related, even if they
happen to have the same name.
The solution is to declare the variables in neither of the two methods. Variables
can also be declared outside the methods, that is directly in the class. Variables
36
// object variables
public void paint(Graphics gr)
{
int rv;
rv = red.getValue();
…
}
}
Object variables can be inspected and modified in all methods. This is what we’ve
been describing rather vaguely by saying that an object is “involved” with each
method, or that a method “treats” an object. The only exception are static methods:
they do not involve an object, or more precisely: the may not use object variables.
Each object has its own object variables. These come into existence when the
object is created, and remain available as long as the object is reachable via
reference variables.
It is a good habit to try and minimize the number of object variables: declare
variables locally whenever possible. That way, you will be sure that methods don’t
interfere with each other in an unwanted way.
6.5
User interaction
Event: action by the user
With the statements in init and paint as described, the program is ready to use, but
is still doesn’t react on user actions, like pressing the button or sliding the sliders.
An action of the user is known as an event. We’ll have to set up the program in
such a way that it does event handling.
Event listener: object which is informed
The user generates events by manipulating interaction components. To react on
that, an event listener needs to be associated to the interaction component. An
event listener is an object that is notified when the event occurs.
Associating an event listener to an interaction component is done by calling a
method of that component. The name varies by component type:
 class Button has a method addActionListener
 class ScrollBar has a method addAdjustmentListener
As a parameter, these methods get the event listener to be notified in the case of
user events. Methods init will be as follows (assuming that a Button black and a
Scrollbar red have been declared as object variables):
public void init()
{
black = new Button("revert to black");
red
= new Scrollbar(…,…,…,…,…);
this.add(black);
this.add(red);
black.addActionListener(…);
red .addAdjustmentListener(…);
}
The question remains what object will act as an event listener, and thus is passed
as a parameter in the latter two calls.
Event listeners are notified by a method call
Interaction components, like buttons and scrollbars, notify their associated event
listeners whenever the user triggers an event. The notification is done by calling a
special method of the event listener:
 A button calls method actionPerformed of its action listener
 A scrollbar calls method adjustmentValueChanged of its “adjustment
listener”.
They trust that the event listeners indeed have the methods as described. How can
we guarantee that?
Announcing methods using implements
Methods can be bundled in groups. This is no news; you know that such a group is
known as a class. News is that method headers can be grouped as well. A group of
method headers is known as an interface.
Interfaces are needed to describe what an action listener is. The following is part
of the Java library:
interface ActionListener
{
public void actionPerformed(ActionEvent e);
}
in other words: ActionListener needs to know a method actionPerformed with an ActionEvent parameter and void result.
In class headers you may promise that you will indeed define a method like that.
Including the text implements ActionListener in the class header makes the
promise.
In the example program we’ll make the promise in the single class that we have
(the header grows quite large, as it already contains the text extends Applet,
but that’s no problem; if necessary you can split the header in two lines):
public class Mixer extends Applet
implements ActionListener
{
With this header, we promise that class Mixer will contain all methods as listed in
interface ActionListener. In this case, there is only one such method, namely
actionPerformed.
Fulfilling the promise made by implements
Promises need to be fulfilled. That is why in de body of mixer, we indeed define
the method that was promised:
public void actionPerformed(ActionEvent e)
{
This method is called when the user presses the button. How do we want to react?
Right, by resetting the sliders to their initial position:
red .setValue(0);
green.setValue(0);
blue .setValue(0);
To update the screen according to the new situation, we force a call to paint by
calling repaint (see section 6.3). This completes handling the action event.
this.repaint();
}
37
Exploiting the promise made by implements
Now that we have fulfilled the promise that Mixer implements ActionListener, any
Mixer object may act like an action listener. The place where we needed an action
listener was in the init method, as a parameter to addActionListener:
public void init()
{
…
black.addActionListener(…);
}
Method init is itself in class Mixer, which means that a Mixer object is involved.
That object can be referred to by the word this. Therefore, this is acceptable
as an action listener. Now the initialization of the button is complete: creation of
the button, adding it to the applet, and associating an action listener with it:
public void init()
{
…
black = new Button("revert to black");
this.add(black);
black.addActionListener(this);
}
Reacting to Scrollbar events
Reacting to events the user triggers with one of the scrollbars is done in roughly
the same way as reacting on button presses:
 In method init, the Mixer object this is associated as event listener to the
scrollbars:
red .addAdjustmentListener(this);
green.addAdjustmentListener(this);
blue .addAdjustmentListener(this);

This is only allowed if Mixer objects indeed are able to behave as adjustment
listeners should, so that’s what we promise in the header of class Mixer:
public class Mixer extends Applet
implements ActionListener, AdjustmentListener

To fulfill the promise, we define the method adjustmentValueChanged
which is listed in interface AdjustmentListener:
public void adjustmentValueChanged
(AdjustmentEvent e)
38
{
}
this.repaint();
Handling scrollbar adjustments is done by simply calling repaint. In turn, that will
call paint, which determines current slider values using getValue. After scrollbar
adjustments, at least one of the three values will have been changed, which is
visualized by paint by drawing a rectangle of the color specified.
The notion interface
The notion interface is used in different contexts in computer science. On first
sight the following three meanings bear no relationship:
 In hardware jargon, the connections at the rear of a computer are called the
interface. A printer can be connected to the parallel interface, a mouse to the
serial interface. The interface is the “face” the computer shows to peripheral
components.
 In designers’ jargon, windows, buttons, dialogues, in short: interaction
components shown to the user are known as the graphical user interface
(GUI). The interface is the “face” the program shows to the user.
 In programmers’ jargon, the methods which can be called involving a
particular object form its interface, also known as API (application
programmer’s interface). The interface is the “face” a class shows to the
programmer using the class.
When reading close, in each of these three instances a “face” is shown by [the
computer / the program / the class] to the outside world. The use of the same term
is thus justified. Be aware, though, of the context of the term!
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
// ...continuation of class Mixer
public void paint(Graphics g)
{
int rv, gv, bv;
rv = red .getValue();
gv = green.getValue();
bv = blue .getValue();
g.drawString("R=" + rv + " G=" + gv + " B=" + bv, 20, 40);
g.setColor(new Color(rv, gv, bv));
g.fillRect(20, 60, 260, 220);
}
public class Mixer extends Applet
implements AdjustmentListener, ActionListener
{
private Scrollbar red, green, blue;
private Button black;
public void init()
{
red
= new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 255);
green = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 255);
blue = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 255);
black = new Button("Black");
this.add(red);
this.add(green);
this.add(blue);
this.add(black);
red .addAdjustmentListener(this);
green.addAdjustmentListener(this);
blue.addAdjustmentListener(this);
black.addActionListener(this);
}
// to be continued...
public void adjustmentValueChanged(AdjustmentEvent e)
{
this.repaint();
}
public void actionPerformed(ActionEvent e)
{
red .setValue(0);
green.setValue(0);
blue .setValue(0);
this.repaint();
}
}
Listing 6.1: Mixer.java (continued)
Listing 6.1: Mixer.java
39
7. Iteration
7.1
The while statement
Executing statements more than once
Now that we have event listeners we can let the program react upon user actions,
but after the associated method is completed, the program will be idle until the
next user event. To keep the program busy for a longer time, many statements
would be necessary, if there was not a statement that can execute a (or a few)
statements repeatedly. This statement form is known as the while statement.
An example of the use of a while statement is the following:
public static void paint(Graphics gr)
{
int x;
x = 1;
while (x<1000)
x = 2*x;
gr.drawString("final value: " + x, 10, 10);
}
In this method there is a declaration, an assignment statement, then a while
statement, and finally a call to the method drawString. The program fragment
while (x<1000)
x = 2*x;
counts as only one statement, consisting of a sort of a header: while (x<1000)
and a body: x=x*2; . The header consists of the word while followed by a
parenthesized condition. The body is a statement in its own right: here it happens
to be an assignment statement, but another possibility would have been a method
call.
When executing a while statement, the body is executed over and over again. This
continues as long as the condition in the header remains true. That’s why it is
called a “while” statement: the body is executed again and again while the
condition holds.
In the example, the variable x initially is assigned the value 1. That is certainly
smaller than 1000, so the body is executed. In the body, the value of x is doubled;
hence the value of x becomes 2. That value is still smaller than 1000, so the body
is executed again, making x equal to 4. Again, this is smaller than 1000, so x is
doubled resulting in 8, which is smaller than 1000, etcetera. The value of x will
40
become 16, 32, 64, 128, 256 and 512 in succession. The value 512 is still smaller
than 1000, hence the body will be executed again, making x equal to 1024. But
now, 1024 is not smaller than 1000, and so the iteration finally comes to an end.
It is only now that the next statement will be executed: the call to drawString. As a
result of that statement, the value of x after all the doubling (1024) will be
displayed on the screen.
Repeating more than one statement
The body of a while statement may consist of more than one statement. In that
case, the body is written in braces. For example, the following program fragment
determines how often you can double 1 until it is bigger than 1000:
int x, n;
x = 1; n = 0;
while (x<1000)
{
x = 2*x;
n = n+1;
}
gr.drawString(n + " times doubled", 10, 10);
Here, we use a variable n to count the number of iterations. Before the while
statement, the count is zero, and hence the value of n is initialized to zero. Each
time that x is doubled in the body of the while statement, we increment the value
of n, so that it keeps track of the number of doubling actions. Hence, when the
while statement is completed, the variable n holds the total count.
Note two tings in these program fragments:
 The variables which are used in the body, need to be initialized (receive an
initial value) before the repetition starts;
 The condition mentioned in the header had better to be dependent of a
variable that is changed in the body: otherwise, the iteration would either
immediately, or never be terminated.
Repetition using a counter
Variables counting the number of iterations are useful for controlling the
continuation of the repetition. For example, using a counter, you can execute a
statement exactly 10 times. The following code (part of the body of paint) will
draw 10 smileys on the screen:
int n;
n = 0;
while (n<10)
{
gr.drawString( ":-)", 0, 20*n );
n = n+1;
}
Apart from counting the iterations, the counter proves useful here to determine the
position of the n-th smiley: the y-coordinates 0, 20, 40, 60 etc. can be calculated
easily from n.
Accumulation of a result
Often, in a while statement some sort of result is accumulated. An example is the
following method, which calculates the factorial of a number, which is passed as a
parameter. (The factorial of a number is the products of all numbers between one
and that number, e.g. factorial 4 is 1*2*3*4=24.)
Apart from a counter, this method uses a variable result, in which the result is
accumulated:
private static int factorial(int x)
{
int n, result;
n=1; result=1;
while (n<=x)
{
result = result*n;
n = n+1;
}
return result;
}
7.2
Boolean values
Comparison operators
The condition in the header of a while statement is an expression, which when
evaluated yields a truth-value: “yes” or “no”. The repetition is continued while the
outcome of the evaluation is “yes”.
In conditions, you can use comparison operators. The following are available:
 < less than
 <= less than or equal to / at most
 > bigger than
 >= bigger than or equal to / at least
 == equal to
 != not equal to
These operators can be used on two numbers, ints as well as doubles. Left and
right of the operator appear constants, variables, or full expressions using addition
and multiplication etc.
Note that the test for equality is written using two equal signs: this is necessary,
because the single equal sign is already in use as the assignment operator. The
difference is essential:
x=5;
x==5
statement
expression
make x to be equal to 5 !
is x equal to 5 at the moment ?
Logic operators
A condition is what is called in mathematical logic a predicate. Operators used in
mathematical logic to combine predicates (“and”, “or” and “not”) can be used in
Java as well. The funny symbols used in mathematics are unfortunately not
present on the keyboard, so we’ll have to make do with more primitive
representations:
 && logical “and”
 || logical “or”
 ! logical “not”
The type boolean
Expressions in which comparison operators are used, or in which comparisons are
combined using logical operators, have a type of their own. The outcome of an
expression is, after all, a value: one of the two possible truth-values “yes” or “no”.
Logicians call these values “true” and “false”.
You can use logical expressions in other contexts than just conditions in a while
statement. A logical expression is nothing special really: it is just an expression
with a particular type. Therefore, you can do anything with a logical expression
that you can do with, say, an int-expression: store its value in a variable, or yield it
as a method result.
The type of logical values is known as a boolean. This is one of Java’s seven
primitive types, so it is not an object type. The type was named after the British
logician George Boole (see figure 7.1).
Here is an example of the declaration of a boolean variable, and a subsequent
assignment to it:
boolean test;
test = x>3 && y<5;
41
7.3
The for statement
Shorthand of incrementing counters
In bodies of while statements, especially when a counter is involved, frequently
assignment statements occur which increment the counter value. This can be done
using the statement:
n = n+1;
(As an aside: particularly in this situation, it would be unwise to pronounce
assignment as “is”, because the value of n is not equal to n+1, but rather becomes
equal to the (old) value of n+1.) Statements incrementing the value of a variable
occur so frequently, that there is a special shorthand notation:
n++;
Figuur 7.1: George Boole (1815-1864)
A more realistic example is a method having a boolean value as a result. For
example a method that answers the question whether a number is divisible by 7:
private static boolean isSevenFold(int x)
{
return x%7==0;
}
A number is divisible by 7 if the remainder after division by 7 is 0. De result of
that expression is therefore the result of the method. The method can be used to,
say, find the first 7-divisible number bigger than 1000:
n = 1000;
while ( ! isSevenFold(n) )
n = n+1;
This example illustrates that the condition of a while statement need not
necessarily be a comparison, provided that it has a boolean type. Conversely,
conditions are not the only place where comparisons are useful: the can be used in
other contexts where a boolean value is required.
An adequate pronunciation for ++ would be “is incremented”.
For increments with more than one there is another notation:
n += 2;
is shorthand for
n = n+2;
Counting automatically
Many while statements use a counting variable, and have the following structure:
int n;
n = initialValue;
while (n<finalValue)
{
do something useful, using the value of n
n++;
}
Such a “counting repetition” is rather common. Therefore, a special shorthand
notation is provided for it:
int n;
for (n=initialValue; n<finalValue; n++)
{ do something useful, using the value of n
}
The meaning of this so-called for statement is the same as that of the while
statement above. The advantage is that the three things controlling the counter
42
(initial value, final value and the incrementing) are grouped neatly together in the
header. This reduces the risk that you forget one of them.
In cases where the payload (“do something useful”) consists of only one statement
you may omit the braces, making the notation even more compact.
7.4
Special cases of iteration
Zero repetitions
It might be the case that the condition in the header is false right at the beginning.
This is the case in the following:
x=1; y=0;
while (x<y)
x++;
In this case the body of the while statement is not executed at all, not even once. In
the example, the value of x remains 1.
Infinitely many repetitions
A caveat when using while statements is that the might not end at all (the
execution, that is – the body is, of course, finite). A statement with this behavior is
easily written:
while (1==1)
x = x+1;
The value of x is incremented forever. De condition 1==1 will remain true
forever, and the statement is thus executed over and over again.
In this program this behavior was probably intended, but often a while statement
gets stuck because of a programming error:
x = 1;
count = 0;
while (count<10)
x = x*2;
count = count+1;
// erroneous!
It was intended that the value of x is doubled ten times. Unfortunately, the
programmer forgot the braces around the two statements that should form the
body. This interpretation is suggested by the lay out, but the compiler pays no
attention to lay out. Therefore, the only statement that is repeated is x=x*2; . As
this does not change the value of count, it will never reach a situation where the
condition is false. After finishing the while statement, the assignment count
=count+1; would be executed once, but that statement is never executed,
because the while statement takes infinite time.
Of course, the programmer’s intention was:
while (count<10)
{
x = x*2;
count = count+1;
}
// correctly.
It would be a waste to discard the computer that has gone into coma due to a
forgotten pair of braces. Fortunately, there is a way to force termination of
program execution, even when it is not yet completed. The way in which this is
done differs with operating system. When you test your program using
appletviewer you can just close the window. When using the Kawa development
environment, you can choose “Stop Run” form the “Project” menu. Program
execution is stopped immediately, and you can start looking for the error that
made the program run infinitely long.
As a rule of the thumb, when a program seems not to react, it is a good idea to
investigate each while statement more closely. An infamous error is forgetting t
increment the counting variable.
Iterated iteration
The body of a while statement or a for statement is a statement at its own. It can be
an assignment statement, or a method call, or a group of statements bundled
together using braces. But also, the body can be a while statement or for statement
itself. For example:
int x, y;
for (y=0; y<10; y++)
for (x=0; x<y; x++)
gr.drawString("+", 20*x, 20*y);
In this fragment, the variable y counts from 0 to 10. For each of these values, the
body is executed, which happens to be a for statement as well, controlled by
variable x. The upper bound of x is the current value of y. Therefor the “inner”
repetition will last longer as y increases. The statement that is executed again and
again, is the drawing of a plus-symbol at a position proportional to x and y. The
result is a triangle shaped tableau of plus-signs:
43
+
++
+++
++++
+++++
++++++
+++++++
++++++++
+++++++++
On the first row, there are no plus signs at all. The value of y is 0 at that moment,
and hence the valued of x is varied from 0 up to, but not including 0; i.e., not at all.
This zero-times-iteration nicely fits in the regular scheme.
7.5
Case study: interest calculation
Interest on interest
Many of the constructs discussed are used in the applet given in listing 7.1, which
is shown running in figure 7.1. The applet allows the user to enter an amount of
money and an interest rate, and will show how a capital () of debt () will build
up in the forthcoming 10 years.
Because of the “interest on interest” effect, there is not a fixed increment each
year. Instead, the capital/debt increases with an increasing amount. Increment of
the capital is modeled by the assignment statement:
capital *= (1 + 0.01*interest);
The operator *= used here means “is multiplied by”, just as += means “is
incremented by”. It is a shorthand notation for
capital = capital * (1 + 0.01*interest);
For example, when the interest rate is 5, the capital is multiplied by 1.05. In a for
statement this statement is executed eleven times, after each intermediate capital is
drawn on the screen.
Input via a TextField
The user may enter the initial amount and interest rate. This can be done using
interaction components of type TextField. Therefore, two TextField objects are
created in method init. Because these objects are needed in paint as well, they are
declared as object variables. Parameters of the constructor method are the text
shown in the textfield initially, and the width of the textfield.
As is the case for buttons, an action listener can be associated to a textfield. The
user generates events by hitting the Enter key when the cursor is in the textfield. In
44
method actionPerformed we specified (by calling repaint) that method paint will
be called as a consequence.
In that method, we retrieve the values which were entered by a call to getText ,
and after that convert the Strings obtained to numbers (the strings are not even
stored in variables first) using method parseInt. The calculation is done using the
values thus obtained.
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
public class Interest extends Applet implements ActionListener
{
TextField startText, rateTekst;
public void init()
{
startText = new TextField("100", 8);
rateText = new TextField("5",
4);
this.add(startText);
this.add(rateText);
startText.addActionListener(this);
rateText .addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
this.repaint();
}
public void paint(Graphics gr)
{
int start, rate, year;
double capital;
start = Integer.parseInt( startText.getText() );
rate = Integer.parseInt( renteText.getText() );
capital = start;
for (year=0; year<=10; year++)
{
gr.drawString( "After " + year +
" year: " + capital, 10, 50+15*year);
capital *= (1 + 0.01*rate);
}
}
}
Listing 7.1: Interest.java
45
8. Choice
8.1
The if statement
Conditionally executing statements
Statements are normally executed in sequential order. Using a while statement,
you can repeat statements when necessary, but after that the next statement in the
list is executed (provided that the while statement terminates). However,
sometimes it is necessary that not all statements are executed, but that some
statements are only executed in particular circumstances. The circumstances
ultimately depend on the input the user has given.
For example, suppose that a variable named temperature has a value, maybe
because the user entered it by means of a textfield. Using a special statement form
we now can let the program comment on the whether, but only if that is
applicable:
if (temperature<0)
gr.drawString("It’s freezing!", 10, 10);
The structure of this if-statement resembles that of a while statement: there is a
header with a condition, and a statement forming the body. The statement in the
body is only executed if the condition is true.
An alternative part following else
In some situations, it is desirable that another statement is executed in the case that
the condition is not true. For this, the if-statement can be augmented with an elsepart, as in:
if (temperature<0)
gr.drawString("It’s freezing!", 10, 10);
else gr.drawString("It’s thawing.", 10, 10);
Note that the whole of “if+condition+statement+else+statement” is considered as
one statement itself. The whole, with or without else-part, can thus appear for
example as the body of a for-statement, without need for braces:
for (n=1; n<20; n++)
if (n%3==0)
gr.drawString(n+" is divisible by 3",…,…);
46
else gr.drawString(n+" is not divisible by 3",…,…);
Conditionally executing groups of statements
If more than one statement needs to be executed conditionally, they can be
grouped by braces, just as in the case of a while-statement, like in:
if (temperature<0)
{
gr.drawString("It’s freezing,", 10, 10);
gr.drawString("I’m cold!",
10, 25);
}
The statement following else can be a compound statement in the same fashion.
Many alternatives
When there are many value categories, a sequence of if-statements can find out
which of the categories applies. The second test is placed following the else
belonging to the first test, to have it executed only in the case the first category
does not apply. Following the second test’s else-part may follow a third test, etc.
The example below determines the railway fare to be paid by an individual having
a given age. The result is placed in a textfield. which we assume to be available in
the object variable tf.
if (age<4)
tf.setText("Free");
else if (age<12)
tf.setText("Junior");
else if (age<65)
tf.setText("Regular");
else tf.setText("Senior");
Each else (except for the last one) is followed by another if-statement. For infants,
the text “Free” is showed, and the rest is skipped (because it follows “else”). For
senior citizens, on the other hand, all tests are evaluated (less than 4? less than 12?
less than 65?) before we can decide for “Senior”.
Using indentation with tabs or spaces, it is shown in the program which else
belongs to which if. For long sequences of tests, the screen might not be wide
enough to accommodate for all those tabulations. As an exception to our habit of
indenting sub-statements, we will use a different layout for sequences of ifstatements:
if (age<4)
tf.setText("Free");
else if (age<12)
tf.setText("Junior");
else if (age<65)
tf.setText("Regular");
else tf.setText("Senior");
After all, this layout is aesthetically pleasing as well, the alternatives being clearly
discernable.
Stop when found
An if statement can appear in the body of a method. You could use it to
conditionally execute a return-statement (by which a method makes its result
available to the caller). Here is the railway fare example again, this time in the
form of a method:
private static String tariff(int age)
{
if (age<4)
return "Free";
if (age<12)
return "Junior";
if (age<65)
return "Regular";
return "Senior";
}
8.2
Applications
Determining which button is pressed
In listing 8.1 and figure 8.1 (code and snapshot) a program is shown which draws
a green circle to the screen. There are two buttons, labeled “shrink” and “grow”.
Pressing these buttons, the user can shrink and grow the circle, provided that it
would not become invisible or unreasonably large.
Program structure is as usual for interactive programs: method init creates the
interaction components, there is an action listener that forces a call to paint, and
there is a method paint that draws the picture.
Variables referring to the two button objects are declared as object variables,
because they need be accessed in both init and in actionPerformed.
Furthermore, an int variable radius is declared as an object variable.
The radius is needed in all three methods:
 in init it is initialized, i.e. receives an initial value
 in paint it is used to determine the size of the circle to be drawn
 in actionPerformed it is incremented or decremented, depending on the
button that was pressed.
Because the return-statement immediately returns to the caller of the method, it is
not necessary to write the second test in the else-part of the first. In cases that the
first test is true, the second test will not be evaluated, because the method has
already returned.
In section 4.3 we remarked that it is senseless to have more than one returnstatement in a method body, because the code following the return-statement
would be unreachable. In this case, however, multiple return-statements are
sensible, because the first return-statement is not always executed, so the
statements following it might be reachable in some circumstances.
47
For the decision whether to increment or to decrement the radius, an if-statement
can be used. To know which button was pressed, we can inquire the parameter of
actionPerformed. It is an object of type ActionEvent, which may be
asked all kinds of details about the event the user caused. Most important detail is
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
public class Circle extends Applet implements ActionListener
{
Button shrink, grow;
int radius;
public void init()
{
shrink = new Button("Shrink");
grow
= new Button("Grow");
this.add(shrink);
this.add(grow);
shrink.addActionListener(this);
grow .addActionListener(this);
radius = 100;
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==shrink && radius>10)
radius -= 10;
if (e.getSource()==grow && radius<150)
radius += 10;
this.repaint();
}
public void paint(Graphics gr)
{
gr.setColor(Color.green);
gr.fillOval(150-radius, 150-radius, 2*radius, 2*radius);
}
}
Listing 8.1: Circle.java
the identity of the interaction component the user touched. It can be retrieved by
calling ActionEvent’s method getSource.
By writing two if-statements, we test whether the “source” of the event is the
“grow” or the “shrink” button. Part of the condition (using the “and” operator) is a
check that the radius would not become too big or small, respectively.
48
Note that the == operator not only numbers, but also objects can be tested for
equality. The operator != can be used on objects in the same way, to test whether
two objects are not equal. However, it is not possible to use the ordering operators,
like < and >= on objects.
Password checking
In listing 8.2 is the code that draws a nice picture, but only if the user has typed a
password in a textfield.
As object variables, we have a variable referring to the textfield, and two more
variables: a string holding the secret key, and a boolean value open, indicating
whether the “lock” has already been opened. In method init, the key string is
assigned a value (which, being secret, we will not disclose here ), and variable
open is assigned value false, because initially the lock is closed.
Method actionPerformed is called when the user presses Enter in the textfield,
after entering a password. In actionPerformed, we check whether the password
entered is correct. If so, we assign true to variable open, to indicate that the
lock is now open.
In method paint, which is called indirectly via repaint, we inspect the value of
open. Only if it is true, the drawing is made. As open is a boolean variable, it
can appear as a condition directly: the condition, after all, needs to be a boolean
expression: when its value is true, the first statement is executed, when it is false,
the statement following else is executed.
Note the special way the password entered is compared to the key. We retrieve the
password form the textfield with password.getText(), and the key is
available in variable key. The two strings are not compared, however, with
if ( password.getText() == key )
// wrong!
but with
if (password.getText() .equals(key) )
// right.
Should we’ve done the comparison using ==, we would have tested whether the
two string expressions refer to the same object (i.e., to the same memory location).
Here, that would always be false: key refers to a constant string, whereas the
result of getText is a newly created string, which certainly resides in another
memory location.
Instead, we do the test using method equals from class String. This method
compares the contents of two strings, character by character. The method has
access to one string (because it is a method of class String); the second string is
passed as a parameter. The result is a boolean value.
In the code, the method calls are cleverly combined. We could have done the
retrieval of the text, the comparison, and the check in the if-statement as
successive steps:
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
String entered;
boolean ok;
entered = password.getText();
ok
= entered.equals(key);
if (ok)
public class Secret extends Applet implements ActionListener
{
TextField password;
boolean open;
String key;
// this is…
// more complicated…
// than necessary!
public void init()
{
password = new TextField(20);
this.add(password);
password.addActionListener(this);
password.setEchoChar('*');
key = "secret";
open = false;
}
All these extra variables make the code long and tedious. Instead, we can treat the
string that is the result of getText directly by method equals. The boolean
value which is the result of that, can be used as the condition of the if-statement
if (password.getText().equals(key) )
// concise.
As a finishing touch we make the textfield into a real password field. By a call to
setEchoChar it is arranged that while typing, the user sees only asterisks, as is
common for password fields. Once the key is correctly entered, we can remove the
textfield using method setVisible.
public void actionPerformed(ActionEvent e)
{
if ( password.getText().equals(key) )
{
open = true;
password.setVisible(false);
this.repaint();
}
else password.setText("");
}
Minimum/maximum thermometer
In listing 8.3 a program is given that acts like a maximum/minimum thermometer.
Using a scrollbar, the user can set a temperature. The maximum and minimum
values that have ever been reached are shown on the screen. Also, there is a
pushbutton labeled “Reset”. When it is pressed, maximum and minimum are reset
to the current temperature.
Central to this program is the if-statement in adjustmentValueChanged. Is
the current value bigger than the maximum-up-till-now? Then the variable which
holds the maximum needs to be adjusted!
Variables minimum and maximum are needed in all three methods, and hence are
declared as object variables. Also, the variable referring to the scrollbar is needed
more than once and thus declared as an object variable. The button reference
however, is only needed in method init, and hence can be declared locally.
public void paint(Graphics gr)
{
if (open)
{
gr.setColor(Color.green);
gr.fillOval(50,50,100,100);
gr.setColor(Color.blue);
gr.fillOval(81,85,8,8);
gr.fillOval(111,85,8,8);
gr.drawArc(75,75,50,50,225,90);
}
else gr.drawString("please enter password", 50, 50 );
}
}
Listing 8.2: Secret.java
49
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
public class Thermo extends Applet
implements ActionListener, AdjustmentListener
{
Scrollbar meter;
int maximum, minimum;
public void init()
{
Button reset;
reset = new Button("Reset");
meter = new Scrollbar(Scrollbar.HORIZONTAL,0,1,-50,50);
maximum = 0;
minimum = 0;
this.add(reset);
this.add(meter);
reset.addActionListener(this);
meter.addAdjustmentListener(this);
}
public void adjustmentValueChanged(AdjustmentEvent e)
{
int value;
value = meter.getValue();
if (value>maximum)
maximum = value;
if (value<minimum)
minimum = value;
this.repaint();
}
public void actionPerformed(ActionEvent e)
{
maximum = meter.getValue();
minimum = maximum;
this.repaint();
}
public void paint(Graphics gr)
{
gr.drawString("hoogste: " + maximum, 50,50);
gr.drawString("laagste: " + minimum, 50,70);
}
}
Listing 8.3: Thermo.java
50
8.3
Case study: Graph and zeroes of a parabola
Description of the case
In this section we’ll develop a more complicated program, in which both choice
and iteration play an important role. Furthermore, interaction components with
event-listeners are used, methods and parameter, local declarations and object
variables. Also, we’ll see some aspects of handling double values.
The program will draw a parabola, that is the graph of a mathematical function
described by y = a x2 + b x + c, where a, b and c are constants to be supplied. In
the applet the user can determine the constants by typing them in textfields, and
immediately see the resulting graph.
A classic subject of high school calculus is finding the zeroes of a parabola. These
are given by applying the so-called abc-formula (named after the constants a, b
and c which appear in it). The applet will use this formula to calculate the zeroes,
and show them to the user.
Conversion if double-values
In the program, the constants a, b and c are declared as double variables: they
are real numbers, possibly with digits following a decimal point. In the program
they are not constant at all: the user can change them! But their value remains
fixed during the drawing of one particular parabola.
When dealing with double values, we need two things that we haven’t used before:
conversion of strings to double-values, and conversion of double-values to intvalues.
For the conversion from strings to int-values, there was a method parseInt:
String s; int n;
n = Integer.parseInt(s);
Unfortunately, there is no analogous method parseDouble. There is, however, an
indirect way to do the conversion. First, we use the static method getValue
from class Double. The result is not a primitive double-value, but a Double-object
(note the capital D in the type!). From that double-object, we subsequently call
method doubleValue, by which we finally get the desired primitive double-value.
String s; Double dobj; double d;
dobj = Double.valueOf(s);
d
= dobj.doubleValue();
The extra variable dobj is not strictly necessary, because you can combine the
two calls: the Double-object returned by valueOf can immediately be used to
call the method doubleValue:
d = Double.valueOf(s).doubleValue();
As for the conversion back, from double-values to strings: actually we’ve seen this
before, because we’ve been using operator + for concatenating strings and doublevalues. By using a zero-character string as left operand of +, we can force
conversion of the other operand from double to string:
s = "" + d;
The trick also works for conversion form int-values to strings.
51
// Parabool.java (continued)
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
private void zeroes(Graphics gr)
{
double discriminant, denominator, root;
discriminant = b*b-4*a*c;
denominator = 2*a;
public class Parabola extends Applet
implements ActionListener
{
TextField abox, bbox, cbox;
double a, b, c;
if (denominator==0)
gr.drawString("straight line!", 50,50);
else if (discriminant<0)
gr.drawString("no zeroes", 50, 50);
else if (discriminant==0)
gr.drawString("one zero: "+ -b/denominator, 50, 50);
else
{
root = Math.sqrt(discriminant);
gr.drawString("two zeroes: " +
+ (-b-root)/denominator + " and "
+ (-b+root)/denominator , 50, 50);
}
public void init()
{
a = 0.5;
b = 2.0;
c = -4.0;
abox = new TextField(""+a, 8);
bbox = new TextField(""+b, 8);
cbox = new TextField(""+c, 8);
this.add(abox);
this.add(bbox);
this.add(cbox);
abox.addActionListener(this);
bbox.addActionListener(this);
cbox.addActionListener(this);
}
private void axes(Graphics gr)
{
gr.drawLine(0,250,500,250);
gr.drawLine(250,0,250,500);
}
}
public void actionPerformed(ActionEvent e)
{
a = Double.valueOf(abox.getText()).doubleValue();
b = Double.valueOf(bbox.getText()).doubleValue();
c = Double.valueOf(cbox.getText()).doubleValue();
this.repaint();
}
private void graph(Graphics gr)
{
int xpixel, ypixel, oldy;
double xvalue, yvalue, scale;
scale = 0.03;
oldy = 0;
for (xpixel=-1; xpixel<500; xpixel++)
{
xvalue = (xpixel-250)*scale;
yvalue = this.parabola(xvalue);
ypixel = (int) (250-(yvalue/scale));
public void paint(Graphics gr)
{
this.zeroes(gr);
gr.setColor(Color.red);
this.axes(gr);
gr.setColor(Color.blue);
this.graph(gr);
}
double parabola(double x)
{
return a*x*x + b*x + c;
}
// see continuation…
52
if (xpixel>=0)
gr.drawLine(xpixel-1, oldy, xpixel, ypixel);
oldy = ypixel;
}
}
}
Listing 8.4: Parabola.java
Structure of the program
Object variables are declared for three textfields, in which the user can enter
values for a, b and c. In method init, the textfield objects are created. Three more
variables are declared for the values a, b, and c themselves. In method init they are
assigned a default value; thus the user can view an initial parabola without having
to enter values first. We’ll make sure that the double-values of a, b, and c always
correspond to the values that are entered in the three textfields. For a start, when
creating the textfields, the initial text which is displayed in this textfield are the
string-conversions of the values of a, b, and c.
Whenever the users presses “Enter” in one of the textfields, method
actionPerformed is called (because actionPerformed is defined in class
Parabola, which is announced in the class header by implements
ActionListener, which makes that every Parabola-object behaves as an
action-listener; in particular the object this does so, it being a Parabola-object,
and can therefore be added as an action-listener to the three textfields).
As a reaction, we modify the values of a, b, and c to make them correspond to the
possibly changed contents of the textfields. Now that the values of a, b, and c are
up-to-date again, actionPerformed calls method repaint, thus forcing a
call to paint.
Heart of the program is method paint: finding the zeroes, and drawing the graph.
Because these are separate tasks, we define two separate methods for doing the
job. A third method is defined for drawing the axes. This way, the method paint is
relatively simple: what remains are only choosing the colors, and calling the three
auxiliary methods. The auxiliary methods receive the Graphics-object, which paint
has available, as a parameter, in order to be able to write things to the screen.
Finding the zeroes
In method zeroes we can concentrate entirely on finding the zeroes, without the
fuss involved with handling textfields. We just assume that variables a, b, and c
contain appropriate values.
We can calculate the zeroes by applying the abc-formula, provided that they exist.
In the formula, the square root is taken from b 2-4ac, so if that value happens to be
negative, there are no (real) solutions. Furthermore, a division occurs by 2a, so if
that value is 0 special actions have to be taken. Using if-statements, all these cases
are distinguished, and an appropriate message is written to the screen in each case.
Drawing the graph
For drawing the graph, the idea is that for each possible x-value we calculate the
corresponding y-value. At that location, we could place a small dot:
for (xpixel=0; xpixel<500; xpixel++)
{
ypixel = this.parabola(xpixel);
gr.fillRect(xpixel, ypixel, 1, 1);
}
However, in places where the graph is rather steep, and y-coordinates of adjacent
x-coordinates differ more than the dot thickness, the dots will not be connected.
Therefore, instead of drawing a dot we’d better draw a line from the preceding
point. For that purpose, the y-coordinate of the previous point is kept in variable
oldy. An if-statement makes sure that for the first point no line is drawn, because
at that moment, there is not yet a “previous” point. We need not to keep the old x
value, because the x-coordinate of the previous point is of course x-1.
for (xpixel=-1; xpixel<500; xpixel++)
{
ypixel = this.parabola(xpixel);
if (xpixel>=0)
gr.drawLine(xpixel-1, oldy, xpixel, ypixel);
oldy = ypixel;
}
The compiler is not yet satisfied with this program, and insists in correcting the
error that “variable oldy may not have a value when used”. This is because the
compiler is aware of the fact that in the body of the while-statement, the variable
oldy seems to be used before it is assigned a value to. The compiler is not smart
enough to see that the if-statement is there to prevent this situation. To satisfy the
compiler, we write an extra assignment to oldy at the beginning of the whilestatement.
Scaling
The interval [0,500] is not the most interesting range to study parabolas for the
more common values of a, b, and c. More interesting would be the interval [-7,7].
That is why, in the program, calculation is not done with the value of xpixel, but
rather with a translated and scaled version of it. The resulting y-value is scaled
back, translated back, and corrected for the upside-down Java coordinate system.
The details of this process are easier to describe using formulas than words, which
is exactly what is done in the program. So check out listing 8.4 for the details…
53
9. Objects and classes
9.1
Class: description of an object
Object: named group of variables
An object is a group of variables belonging together. You may not be consciously
aware of the fact, but each time you create a new object using the new keyword,
you create a group of variables. For example, when you create a new button with
the expression new Button("press here"); a group of variables comes
into existence that does the necessary bookkeeping for managing a button:
recording its size, position on the screen, color, status (pressed or not), the identity
of the corresponding action-listener, the caption, etc.
Mostly, you are not dealing with these variables directly: to be able to use a button
object in your program, you don’t even need to know of which variables a button
object is composed, and what their names are. It is however important to know
which methods are available that can manipulate the object. For a button, available
methods are amongst others: setLabel (to modify the caption) and
addActionListener. Via these methods you can indirectly modify the
member variables of the object, without explicitly assigning values to them.
Class: declaration of variables plus method definitions
A class definition is a description of the objects of that class. Therefore, a class
definition consists of two parts:
 a declaration of the member variables of the object
 a definition of the methods by which the object can be manipulated.
This holds for the classes in the standard libraries, but also for classes that you
define yourself. For example, when the definition of your class Thermo begins as
follows:
class Thermo extends Applet
{
private Scrollbar meter;
private int min, max;
then every Thermo object that comes into existence will be composed of three
variables: a reference to a scrollbar object, and two integer numbers. Moreover, as
it is an extension of Applet, each Thermo object contains all variables that were
54
declared in Applet. Such a Thermo object is created by the browser, whenever it
encounters a web page containing (the byte code) of this class as code.
When writing the code of the program, you might have the illusion that of each of
the variables declared in the class, only one is present. Indeed, that is the case
within one object, but it may occur that the browser creates two instances of the
same class. For example, this will happen when in the HTML file, there are two
<APPLET> tags with the same code. We have seen an example of that in section
5.3, where in one HTML-file two instances of Rectang-applets were created. Each
of these applets has its own group of variables.
Objects and object references
To get some idea of what happens in memory when objects are created, we’ll
investigate in detail what happens when the program Thermo (the
minimum/maximum thermometer from section 8.2, listing 8.3) is run.
When processing the <APPLET> tag the browser creates a Thermo object. The
browser possesses a reference, which will point to the new object. The Thermo
object consists of the variables that were declared in the class: two integer
numbers named min and max, and a reference to a scrollbar object, named
meter. But as Thermo is an extension class of Applet, the Thermo object also
consists of the variables that were declared in the Applet class.
Next, the browser calls method init. In that method, a local variable is declared: a
reference to a Button-object, named reset. Local variables are in memory as
well, but not as part of an object. Hence, you can visualize the situation in memory
which is occurs at this point as:
reset
browser’s
current
applet
this
Thermo
inherited
declared
meter
by us
min
max
Method init has access to an object via the pseudo-variable this. The
expression this can be thought of as a kind of variable that is automatically
present in each method, the difference with a normal variable is that assignment to
it is neither needed nor possible. In the scheme above, it is not shown of which
variables are inherited from Applet; you need not know this for library classes.
Note that the local variable reset, and the variable meter that is part of the
Thermo object, are references to objects, which at the moment do not yet refer to
any object. This will happen only when the assignment statements in the body of
init are executed:
reset
meter
max =
min =
= new Button("Reset");
= new Scrollbar(Scrollbar.HORIZONTAL,0,1,-50,50);
0;
0;
After that, the situation is as follows:
Button
The next two statements in method init are calls to method add, using the two
newly created objects as a parameter:
this.add(reset);
this.add(meter);
Method add is defined in class Applet. Although the pointer this refers to a
Thermo object, but part of that object (the part that was inherited) is a fully
equipped Applet object. It is that (part of the) object that is treated by add.
Method add is part of the standard library, so we cannot know what variables are
modified by add, as we don’t know what variables are part of the Applet object.
So in order to visualize what is going on, we’ll have to do a bit of guessing. The
idea is that an Applet object will keep a copy of the object references that were
passed as a parameter to add, to have them available for later use. The situation
will be roughly as follows: (In reality, the row of variables almost certainly is not
named added. However, we neither can, nor need, nor should want to know what
the real name is).
Button
reset
browser’s
current
applet
reset
this
Thermo
Scrollbar
browser’s
current
applet
this
Thermo
Scrollbar
added
meter
min
0
max
meter
0
min
The four variables to which an assignment has been done, now have a value. In the
case of min and max, this is an int-value, in the case of reset and meter, it is a
reference to a newly created object. The new objects contain variables, which are
declared in the library classes Button and Scrollbar respectively. In the scheme,
the details of that are not shown.
In a method, you may use both local variables (in this case: the variable reset) and
object variables of the object that is reachable via this (here: meter, min and
max). In a situation where the name of a local variable happens to coincide with
the name of an object variable, the local variable has precedence.
0
max
0
In the final two statements in the body of init, event listeners are added to the
button and scrollbar objects:
reset.addActionListener(this);
meter.addAdjustmentListener(this);
This time, not the this object, but two other objects are treated. Again, we can
only guess what will happen exactly. However, it is reasonable to assume that in
both cases, a copy of the parameter is stored for later use. If at a later moment the
55
button is pressed, the button “knows” which object is its action-listener, that is: of
which object the method actionPerformed should be called in response.
As these were the last statements of method init, now the local variables are not
present any more: the local variable reset, and also the pseudo-variable this
are disposed of. The situation that is created after the call to init is completed is
as follows:
Button
browser’s
current
applet
actListener
Thermo
Scrollbar
added
adjListener
0
value
meter
min
0
max
0
Note that the local variables are disposed of, but not the objects to which they
referred. These objects are still reachable indirectly, via the copies of the
references to them, that were created by the calls to method add.
Programs with multiple classes
Up till now, we’ve been writing programs consisting of just one class. This class
was an extension of Applet in all examples, and was written with the intention that
the browser would create (at least) one object of that class.
More objects were used in the example programs, but their type was a library class
in all cases (Button, Scrollbar, Graphics, String etc.).
In the next application this will change. Apart from the, by now well known,
extension class of Applet, we’ll define some more classes. In the program, we’ll
use objects having these classes as their type. This way, we can use “home brew”
objects of our own design in the program.
56
9.2
Application: moving particles
Description of the case
The program that we’ll develop is a simulation of moving particles in a confined
space. You may think of molecules in a bottle, or of balls on a (frictionless)
billiard table, or of rats in a cage. For ease of drawing, we will display the particles
as small colored circles, and the space as a large rectangle.
In the running program, three spaces will be visible, each having different
dimensions. In each space, three particles are present, having different colors. The
particles can move: they’ll do one “step” whenever the user presses a button
labeled “Step”. Moreover, there is a button “Start”. When it is pressed, the
particles will start moving continuously, which is perceived by the user as an
animation. The caption of the button is changed to “Stop”; by pressing the button
again, the user can pause the animation. Figure 9.1 shows a snapshot of the
running program.
Class Space
In the simulation’s window (see figure 9.1) five things are visible: three spaces
containing particles, and two buttons. It would be sensible to create the five things
in the same fashion: by creating new objects, which are subsequently added to the
display.
For the buttons, this is no problem, but of course, there is no library class Space.
We can however define the class ourselves. We need not do that from rock
bottom: instead, we can extend an existing class named Canvas.
A Canvas is an interaction object, just as Button and Scrollbar are. As such, it can
be added to an Applet using add. A Canvas object is like an artist’s canvas: you
can make a drawing on it. A Canvas object has a size and a background color of its
own, so we do not need to worry about that. In class Space, which is an extension
of Canvas, we need only to declare extra variables needed for the colored
particles, and methods that let them move.
Class Particle
Each moving particle in this program has a set of properties: a color, a position in
a space, and a direction of movement. For each of these properties, we can declare
a variable: the color is a reference to a Color object, the position consists of two
int values x and y, and the direction of movement can be described by the
distances dx and dy to travel at each step.
Each particle has its own color, position and direction. That’s why we define a
class Particle, in which these variables are declared. Having done that, in the
main program we can create a Particle object for each particle, in which the
variables are bundled.
Class Particle is not an extension of any existing class. It is defined entirely by
ourselves. Each Particle object consists solely of the variables that we declare in
the class; no variables are inherited.
Design of the classes
The program will consist of three classes: the usual extension of Applet that we’ll
name Simulation this time, and the auxiliary classes Space and Particle. First,
we’ll investigate the variables that are needed; the methods are dealt with later.
class Simulation extends Applet
{
Button step, auto;
Space s1, s2, s3;
// methods still to be written
}
class Space extends Canvas
{
Particle p1, p2, p3;
// methods still to be written
}
class Particle
{
Color color;
int x, y, dx, dy;
// methods still to be written
}
We now need to create objects having these classes as their type, thus creating a
network of references. The desired situation can be depicted as follows:
Simulation
Button
browser’s
current
applet
stap
auto
r2
r1
Space
d1
Button
r3
Space
d2
d3
d1
Space
d2
d3
d1
d2
d3
x
x
x
x
x
x
x
x
x
y
y
y
y
y
y
y
y
y
dx
dx
dx
dx
dx
dx
dx
dx
dx
dy
dy
dy
dy
dy
dy
dy
dy
dy
color
color
color
color
color
color
color
color
color
Particle
Particle
Particle
Particle
Particle
Particle
Particle
Particle
Particle
The browser creates a Simulation-object. It consists partly of variables, which are
inherited from Applet, and partly of the variables that are declared in class
Simulation: step, auto, r1, r2 and r3. It’s the job of method init to let these
variables refer to newly created objects. As usual, this is done by means of
assignment statements:
step
auto
r1 =
r2 =
r3 =
= new Button("Step");
= new Button("Start");
new Space(…);
new Space(…);
new Space(…);
As a consequence, the variables step and auto will refer to newly created
Space-objects. These Space-objects partly consist of Canvas variables, and partly
of the three variables that were declared in class Space: d1, d2 and d3. However,
these variables do not yet refer to objects.
57
The constructor method of Space
When a new-expression is evaluated, two things happen:
 memory is allocated for the new objects
 the constructor method, as defined in the class, is called.
All statements appearing in the constructor method are thus automatically
executed when a new object is created. Therefore, the constructor method is the
natural place to initialize object variables and do other prepatory work.
There are two differences between a constructor method and other methods in a
class:
 the name is the same as the name of the class, and thus begins with a capital
letter
 a constructor method does not have a result type, not even void. This is
because a constructor method can only be called by way of the special newexpression, and therefore has always the newly created object as a result.
In our class Space we’ll write a constructor method, in which a newly created
Space object is initialized.
First task of the constructor method is to set the size of the Space. This is done by
way of a call to setSize, which was inherited from Canvas (not that Space is an
extension of Canvas!). When calling setSize, the width and height are specified.
Because the three Space objects need to have different dimensions, we’ll pass the
dimensions as a parameter to the constructor method of Space. When creating a
Space object (in Simulation’s init method), the dimension can be chosen by
passing the corresponding values.
So, this is the beginning of the constructor method of class Space (note that there
is not a result type between public and the method name):
public Space(int width, int height)
{
this.setSize(width, height);
Next thing to do is to set the background color. This can also be done via a method
that was inherited form Canvas: setBackground. Because the color of all three
canvases is the same, we need not pass it as a parameter to the constructor method.
We can just call:
this.setBackground(Color.lightGray);
Now it’s time to initialize the object variables: de references to Particle objects d1,
d2 and d3. The objects they’ll refer to are newly created by:
58
d1 = new Particle(…);
d2 = new Particle(…);
d3 = new Particle(…);
So, the three Particle objects are created immediately during initialization of each
Space object. Class Particle has a constructor method of its own. We therefor shift
our attention to the methods of class Particle.
De methods of class Particle
Class Particle doesn’t extend anything. A Particle objects just consists of the
variables declared in the class: x, y, dx, dy and color. The question is what kind of
things we’d like to do with such a Particle object, in other words: which methods
are needed? Some things which are necessary are:
 a constructor method for initializing the object variables
 a method setPos, which sets the position variables x and y of the particle
 a method setDir, which sets the direction of movement dx and dy
 a method doStep, which changes the position of the particle, thus letting it
move in the direction indicated by dx and dy
 a method draw, which draws the particle on a Graphics-object, which is
supplied as a parameter.
Simplest method is setPos. It takes two parameters, specifying the desired
location; in the method body the corresponding object variables are changed:
public void setPos(int x0, int y0)
{
x = x0;
y = y0;
}
Analogously, method setDir sets the direction variables dx and dy.
Method draw takes a Graphics object, so that it is able to draw things. Before
drawing the circle, we set the color that is stored in the Particle object:
public void draw(Graphics gr)
{
gr.setColor(color);
gr.fillOval(x-3, y-3, 7, 7);
}
Here, we trust that variable color holds a color value. The place to initialize that
variable is the constructor method by giving the constructor method a Color
parameter, each particle can have its own color.
Method doStep is the most interesting one. By calling it the Particle will be able to
move. Because both the current position and the direction of movement are stored
in the Particle object, it doesn’t need any parameters. Movement is done by
incrementing the position variables x and y with the corresponding values dx and
dy:
public void doStep()
{
x += dx;
y += dy;
Now it may be the case (when dx or dy is negative) that the coordinate become
negative. In that case, the particle needs to bounce off the wall. The coordinate
will become positive again, but also, the direction of movement is inverted. For
example, when bouncing to the left wall, the direction of movement changes from
leftbound to rightbound.
Bouncing to the left and upper walls is handled with the following code:
if (x<0)
{
x = -x;
dx = -dx;
}
if (y<0)
{
y = -y;
dy = -dy;
}
Bouncing to the right and bottom walls is more difficult. For testing whether the x
coordinate grows too big, we need to know the size of the space in which the
particle moves. However, this cannot be determined form the object variables (x,
y, dx, dy and color) alone!
There are two solutions to this problem. Either we can pass the necessary
information as a parameter to doStep, or we do so once in the constructor method,
and store that information in additional object variables. In the program, we take
the latter approach.
We pass a reference to the Space-object to which the Particle belongs as a
parameter of the constructor method. Then, we’re able to call a method, which
Space inherited form Canvas:
public Particle(Space r, Color k)
{
color = k;
maxx = r.getSize().width;
maxy = r.getSize().height;
}
We’ve introduced an object variable maxx, which comes in useful for testing
wheter the right wall was been hit in doStep:
if (x>=maxx) …
It is left as an exercise to the reader to see what assignment is needed to handle the
bouncing (the solution is in listing 9.3).
Methods of class Simulation
Class Simulation is only used for the creation of a single object, but nevertheless is
important. The object models the complete applet, and thus is similarly to other
programs that we’ve seen: there is a method init for doing the initializations, and
an event-listener to handle user actions. A method paint is not necessary, as
nothing is drawn on the background of the applet. The two buttons and the three
canvas objects draw themselves and their contents.
Part of method init has already been discussed: creation of the five objects to
which the object variables should refer:
public void init()
{
step = new Button("Step");
auto = new Button("Start");
r1 = new Space(100,196);
r2 = new Space(196,150);
r3 = new Space(60,75);
When creating the Space objects, we pass the necessary width and height, as
required by the constructor method of Space that we defined. As usual, next step is
to add to the applet’s user interface:
this.add(step);
this.add(auto);
this.add(r1);
this.add(r2);
this.add(r3);
The applet as a whole will act as an action listener for both buttons:
step.addActionListener(this);
auto.addActionListener(this);
}
59
The object this may only act as an action listener if we promise that ability in the
class header (using implements ActionListener), and fulfill the promise:
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==step)
this.doStep();
else …
}
For clarity, we’ve put the proper handling of pressing the Step-button in a separate
method. Th name of that method is doStep (not to be confused with the method in
class Particle bearing the same name!). In Simulation’s doStep method, we could
call the Particle’s doStep methods. However, we’re not going to do that for each of
the nine particles. Instead’, we’ll delegate that work to the three Space objects, by
calling a method which is (again!) named doStep. Let’s not forget that we need to
write it later…
private void doStep()
{
r1.doStep();
r2.doStep();
r3.doStep();
The method is defined to be private, as it is only called by one of its fellow
methods, and not directly from some other class.
After the three Space objects have moved their respective particles, the new
situation needs to be made visible. Therefore we call method repaint, which the
Space objects have inherited form Canvas:
r1.repaint();
r2.repaint();
r3.repaint();
}
Methods of class Space
What remains to be done is the writing of the methods in class Space. We already
wrote part of the constructor method:
public Space(int width, int height)
{
this.setSize(width, height);
this.setBackground(Color.lightGray);
Also, the three Particle objects are created. By now, we know what parameters are
needed for Particle’s constructor method: a Space-object and a Color-object. For
60
the Space object only this is a sensible choice. For the Color parameter we
choose some nice colors:
d1 = new Particle(this, Color.red);
d2 = new Particle(this, Color.green);
d3 = new Particle(this, Color.blue);
Now the particles do have a color and know the size of their bounding spaces, but
they also need to have a position and a direction. We call the methods responsible
for that, immediately after the particles are created:
d1.setPos(30,40);
d2.setPos(100,80);
d3.setPos(200,60);
d1.setDir(10,10);
d2.setDir(5,-10);
d3.setDir(8,2);
}
Still on our wish list is to include a method doStep in Space: after all, we call it
from method doStep in Space. It is quite simple: we just call the doStep method of
the three particles.
public void doStep()
{
d1.doStep();
d2.doStep();
d3.doStep();
}
Final method which needs to be written in class Space is paint. This is a
redefinition of the default method (which does nothing) in Canvas. As we’re used
to in Applet, paint is automatically called when the canvas needs to be drawn.
Also, calls can be forced by calling repaint, which we did in Simulation’s method
doStep.
Drawing the canvas is actually quite simple: we just call the method draw that is
present in Particle, to draw all three particles:
public void paint(Graphics gr)
{
d1.draw(gr);
d2.draw(gr);
d3.draw(gr);
}
Now the program is almost complete. What remains is handling the “auto” button,
which deserves a chapter of its own.
9.3
Animation
Automatic movement
Continuously pressing the Step button, the user can keep the particles moving. It
would however be easier if this could be automated, so that the user can sit back
and relax while seeing the particles moving. In other words: we want the program
to behave as an animated movie.
Making animations is quite easy in Java (as opposed to other languages like Basic,
Pascal, C and C++). Actually, we need only a few extra lines in the program. But
be careful not to loose thread, because the mechanism is subtle!
Class Thread
At the core of the animation mechanism is a class named Thread in package
java.util. When you want to do animation, you’ll need an object of that class:
a Thread-object. When constructing a Thread, you need to pass an object as a
parameter: this is a common choice. Thus, we proceed as follows:
Thread animation;
animation = new Thread(this);
After the object is created, you can start the animation by calling method start :
animation.start();
The Thread-object will react with calling method run from the object that was
passed as a parameter during creation of the thread. How can it be so sure that a
method run indeed exists for that object? That’s simple: the compiler will check
that the object is of a class that implements Runnable. So, we’ll promise that in the
header, and fulfill the promise by indeed defining a method run.
Now why do we take all this trouble? Why not just call that run method directly:
this.run();
We could have done so, but there is an important difference between the direct and
the indirect way of calling run: the Thread object calls run, but does not wait until
it’s finished. So method start puts run to work, but immediately returns afterwards.
So from that moment on, two things happen simultaneously: method run is
executed, but also the statement following the call to start is executed.
We’ll exploit this fact, by keeping method run busy for a long time:
public void run()
{
while (1==1)
this.doStep();
}
Instead of the always true expression 1==1 we could even have used the boolean
constant true). This way, doing the steps is done automatically.
Method sleep
But wait a second, now the animation runs so quickly that you can hardly see it.
We’d better pause for a short time after doing a step. This can be done by calling
the static method sleep from class Thread. As a parameter, we pass the number
of milliseconds the pause should last. So, our new version of run is:
public void run()
{
while (true)
{
this.doStep();
Thread.sleep(50);
}
}
The 50 millisecond pause makes sure that a step is performed 20 times per second,
resulting in a smooth animation.
Calling sleep should be done in a try-catch statement
The compiler will object to a call to method sleep as described above: “exception
must be caught”. It happens to be the case that in exceptional cases the pause can
be interrupted before the full time has elapsed. In this program that will not
happen, because we don’t use the possibility. Nevertheless, the compiler insists
that we be prepared for the situation.
Handling exceptional cases (exceptions) is done in a so-called try/catch statement.
This is explained in detail in a later chapter. For now, suffice it to say that the call
to sleep should be done from the body of a try-statement, with a corresponding
catch-part having an empty body. You can use the following code:
try
{
Thread.sleep(50);
}
catch (Exception e)
61
{
}
As opposed to the bodies of while- and if-statements, here the braces around the
body of try are obligatory, even if there is only one statement.
Controlling the animation
The Thread-mechanism is initiated when the user presses the button labeled
“Start”:
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==auto)
{
animation = new Thread(this);
animation.start();
To enable the user to stop the animation at a later stage, we change the caption of
the button when the animation is started:
auto.setLabel("Stop");
When the button is pressed again, it should of course be handled differently. So we
need to revise the body of actionPerformed. We’ll use a boolean variable moving,
and make sure it has value true while the animation is running. It is declared in the
class, and initialized to false in method init.
Now handling the button is done as follows:
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==auto)
{
if (moving)
{
// stop the animation
moving = false;
auto.setLabel("Start");
}
else
{
// start the animation
moving = true;
animation = new Thread(this);
animation.start();
auto.setLabel("Stop");
}
}
else …
}
62
Merely setting a variable to false will not stop the animation. But we can change
the method run for doing so. Instead of running eternally, we can check the value
of our boolean variable carefully each time a step is done:
public void run()
{
while (moving)
{
this.doStep();
try {Thread.sleep(50);} catch (Exception e){}
}
}
Normally, the condition of a while-statement will not change if no assignments to
it are done in the body of the while-statement. However, here we are in a situation
where to processes run in parallel, influencing each other: while the animation is
running, the user can press a button, which will set the value of moving to false.
The value null
Using an assignment statement you can let object variables refer to actual objects.
In some circumstances, you might want to undo the reference, that is let the object
variable refer to no object at all. For this purpose, there is a special constant: null.
This is a neutral value for object references; it is the value all object variables have
before an assignment to them is made.
The nice thing is that you can test whether or not a variable has value null. Using
that, we can revise our program so that a boolean variable moving is not necessary.
Instead, we’ll use the variable animation that we need anyway. It is the reference
to the Thread-object. We’ll make it equal to numm whenever the user presses the
Stop button. To know whether the animation is still running, we can test the value
of variable animation for non-null-ness.
So here is the final version of the button handling method:
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==auto)
{
if (animation!=null)
{
animation = null;
auto.setLabel("Start");
}
else
{
animation = new Thread(this);
animation.start();
auto.setLabel("Stop");
}
}
else this.doStep();
}
See listing 9.1 for the revised version of run, which checks continuously wheter
animation is non-null.
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
// continuation of Simulation.java
public void actionPerformed(ActionEvent e)
{
if (e.getSource()==step)
{
this.doStep();
}
else if (e.getSource()==auto)
{
if (animation==null)
{
animation = new Thread(this);
animation.start();
auto.setLabel("Stop");
}
else
{
animation = null;
auto.setLabel("Start");
}
}
}
public class Simulation extends Applet
implements ActionListener, Runnable
{
Space r1, r2, r3;
Button step, auto;
Thread animation;
public void init()
{
r1 = new Space(100,196);
r2 = new Space(196,150);
r3 = new Space( 60, 75);
step = new Button("Step");
auto = new Button("Start");
animatie = null;
this.add(r1);
this.add(r2);
this.add(r3);
this.add(step);
this.add(auto);
stap.addActionListener(this);
auto.addActionListener(this);
public void run()
{
while (animatie!=null)
{
this.doStep();
try
{
Thread.sleep(50);
}
catch (Exception e)
{
}
}
}
private void doStep()
{
r1.doStep();
r2.doStep();
r3.doStep();
r1.repaint();
r2.repaint();
r3.repaint();
}
}
}
// continued…
Listing 9.1: Simulation.java
63
import java.awt.*;
import java.awt.*;
class Particle
{
int x, y, dx, dy, maxx, maxy;
Color color;
class Space extends Canvas
{
Particle d1, d2, d3;
public Space(int b0, int h0)
{
this.setSize(b0, h0);
this.setBackground(Color.lightGray);
d1 = new Particle(this, Color.red);
d2 = new Particle(this, Color.green);
d3 = new Particle(this, Color.blue);
public Particle(Space r, Color k)
{
color = k;
maxx = r.getSize().width;
maxy = r.getSize().height;
}
public void setPos(int x0, int y0)
{
x = x0 % maxx;
y = y0 % maxy;
}
d1.setPos(30,40);
d2.setPos(100,80);
d3.setPos(200,60);
d1.setDir(10,10);
d2.setDir(5,-10);
d3.setDir(8,2);
public void setDir(int dx0, int dy0)
{
dx = dx0;
dy = dy0;
}
}
public void doStep()
{
d1.doStep();
d2.doStep();
d3.doStep();
}
public void doStep()
{
x += dx;
y += dy;
if (x >= maxx)
{
x = 2*maxx-x;
}
else if (x<0)
{
x = -x;
}
if (y >= maxy)
{
y = 2*maxy-y;
}
else if (y<0)
{
y = -y;
}
dx = -dx;
}
dy = -dy;
Listing 9.3: Space.java
dy = -dy;
}
public void draw(Graphics gr)
{
gr.setColor(kleur);
gr.fillOval(x-4, y-4, 9, 9);
}
}
Listing 9.2: Particle.java
64
public void paint(Graphics gr)
{
d1.draw(gr);
d2.draw(gr);
d3.draw(gr);
}
dx = -dx;
10. Inheritance
10.1 Subclasses
Subclass: defining additional variables/methods
Using class libraries can save you quite a lot of work. Even the worse it is, if there
is a library class that does almost what you want, but not exactly so. Or you’ve
written a class like the one you need before, but you want to make a slight
enhancement. How to proceed?
A solution that was used before object oriented languages existed (that is, in
languages like Pascal and C) was to make a copy of the original program, and
modify the copy where needed. At least, that saved the author a lot of typing.
However this “cut and paste” strategy had a disadvantage: when the original
program was improved (e.g., bugs fixed, or efficiency improved) after the copying
had been done, the improvements had to be carried out separately in the copy. And
if the copy in turn was copied again, the improvements have also to be made in the
third generation copies.
In short, a version management problem exists: various versions are hard to
manage together. A small improvement in the original program (for example:
storing years using four digits instead of two) may thus grow into a multi-billion
Euro project.
So what is a better way to build upon past work? When you want to extend
existing classes, rather than to make a copy you should just state that you want to
write an extension. In Java, this is done by mentioning “extends” in the header of
the class, followed by the name of the class that you want to extend. We’ve seen
many examples of this:
class Hello
extends Applet
class Simulation extends Applet
class Space
extends Canvas
{…}
{…}
{…}
extends generates subclasses
The extended class is also known as a subclass of the original class. Conversely,
the original class is referred to as the superclass of the extension.
A class can have only one (direct) superclass, but it can have many subclasses. For
example, class Applet has both Hello and Simulation as its subclasses, but Hello
has only one superclass (namely Applet).
However, you can again extend the extended classes, thus creating a sub-subclass
of the original class. The sub-subclass has one direct superclass, but indirectly is a
subclass of its super-superclass. The whole can be thought of as a “genealogy” of
classes.
Objects of a subclass can also be regarded as objects of its superclass. For
example, a Space-object (as defined in chapter 9) is a valid Canvas-object as well.
Quite a special Canvas object indeed, namely one that shows colored particles! In
mathematical jargon: a Space-object is a special case of a Canvas-object.
Inheritance of methods and variables
Objects of a subclass may use the methods of its superclass, and of the superclass
thereof, etc. Those methods are said to be inherited from the superclass. The same
holds for the variables that were declared in the superclass: they are also present in
each object of the subclass.
This is why, you can call method add in subclasses of Applet, even if add is not
defined in the subclass. The method is known in Applet, and is inherited by all its
subclasses.
When you look for methods in the manual, you should realize that they may be
inherited from other classes, and thus do not appear in the class where you’d
expected it. For example, method add does not appear in the manual of class
Applet: it is defined in Applet’s super-superclass Container.
Inheritance can also be important in your own classes. Suppose that you’ve
defined a class Ball. A Ball object has a position and a diameter. In the class,
methods setPos, grow and draw are defined:
class Ball
{
int x, y, diam;
void setPos(int x0, int y0)
{
x = x0; y = y0;
}
void grow()
{
diam++;
}
void draw(Graphics gr)
{
gr.fillOval(x,y,diam,diam);
}
}
Later, you might want to extend the class in a class ColorBall, in which the class is
extended with a variable color and a method to set the color:
65
class ColorBall extends Ball
{
Color color;
void setcolor(Color c)
{
color = c;
}
Once you have an object of class ColorBall, you can call method setColor, but also
methods setPos and grow. After all, each ColorBall is a Ball as well, and for the
growing process it doesn’t matter whether or not the Ball possesses a color.
The converse is not possible: if you’ve just a Ball object, you cannot call setColor,
because a Ball has no color component (unless it happens to be a ColorBall, but
you cannot be sure of that).
Redefinition of methods
With the inheritance of method draw by class ColorBall a problem arises. A
ColorBall needs to be drawn in a different way than an ordinary Ball: for the
drawing, the color is important. For situations like this, it is allowed to define a
method again in a subclass, a so-called redefinition. So, in class ColorBall we can
redefine method draw:
void draw(Graphics gr)
{
gr.setColor(color);
gr.fillOval(x,y,diam,diam);
}
}
The not-yet-extended object super
It is a pity that, as soon as you decide to redefine a method, you need to rewrite the
entire body. For example, in the redefinition of draw, the call to fillOval had to be
copied form the original version. Now for one statement this is not that hard, but it
is a nuisance if the drawing would have been complicated (for example, when
drawing houses instead of balls). And what’s worse: a version management
problem is introduced.
What we’d like to do is to call the original method using
this.draw(gr);
However, that is not possible, because it would call the redefined method, which
calls the method again, and again, and again…
66
As a way out, Java provides a special constant named super. It is like the
constant this, but with a difference: super refers to the current object, as if it
has the superclass as its type. So the redefinition of draw can be done as follows:
void draw(Graphics gr)
{
gr.setColor(color);
super.draw(gr);
}
10.2 Class hierarchies
Extends: “is a”
Using subclasses we can try and categorize the world. If you read “extends” as “is
a”, you can feel whether your class hierarchy has the right design. Here is a
hierarchy of some means of transportation:
class Transport
class Vehicle
extends Transport
class Plane
extends Transport
class Boat
extends Transport
class MotorVehicle extends Vehicle
class Bicylce
extends Vehicle
class MotorBoat
extends Boat
class SailBoat
extends Boat
class SteamBoat
extends MotorBoat
class Car
extends MotorVehicle
class Van
extends Car
For each class in this hierarchy, you can define the relevant variables and/or
methods. For example, the variable numberOfWheels typically belongs in
Vehicle and not in Transport, as boats have no wheels. Variable altitude
belongs in Plane, and boolean variable hasBell in class Bicycle.
The hierarchy can be presented nicely in a chart:
In creating the hierarchy, you take all sorts of design decisions. It is a matter of
taste which is the “best”. In the example, we first subdivided the means of
Transport according to the medium in which they move: air, land or water. Only
then the subdivision according to motorization is made. We could have done it the
other way around.
For some classes the position n the hierarchy is not obvious: is a MotorCycle a
special kind of icycle (viz., a motorized one) or a special kind of MotorVehicle
(viz., one with only two wheels)?
However, there should be no doubt which is the superclass and which is the
subclass. A Van is a Car, but a Car is not (always) a Van. Hence, Van is a subclass
of Car. Similarly, a Bicycle is a Vehicle, but not every Vehicle is a Bicycle.
Object-variables: “has a”
Not every chart showing a hierarchic relationship is a class diagram! When
dealing with object there is another hierarchy involved: which objects are parts of
other objects. For example, in the Simulation program of chapter 9:
Chart Title
browser's current
Simulatie
stap
Button
auto
Button
r1
Space
d1
Particle
d2
Particle
r2
Space
d3
Particle
d1
Particle
d2
Particle
r3
Space
d3
Particle
d1
Particle
d2
Particle
d3
Particle
This diagram ought to be interpreted differently. Here, lines should be read form
top to bottom, and read as “has a”. The diagram shows the relationships between
objects that are created in a particular program, but it is not a class diagram. After
all, a Particle is not special kind of a Space (but it is a part of it).
The boxes in this diagram are not classes, but objects. That is why (objects having
the same) class can occur more than once in the diagram, which is another
difference with class diagrams, where that is not the case.
10.3 Class hierarchies in Java libraries
Interface components
All classes in Java packages are ordered in hierarchies, just as in the Transport
example. All interaction components of which a graphical user interface is built
are (directly or indirectly) a subclass of class Component.
Methods that are applicable to any component are defined in class Container.
Examples are setBackground (to change the background color) and getBounds (to
query the size of the component). Methods that are only applicable to components
Component
Button
Panel
Applet
Container
Canvas
Label
Window
Frame
TextComponent
TextArea
Scrollbar
TextField
Dialog
FileDialog
where the user can type text, like getText, are defined in class TextComponent.
Methods that address the subdivision of texts into lines are however placed in
TextArea, because they are not applicable to TextField objects.
Event-listeners
To react on user inputs, you can add event listeners to components. The type of
event listener may vary among components: a Button and a TextField may have an
ActionListener, but a Scrollbar has an AdjustmentListener.
There are differences between an ActionListener and an AdjustmentListener, but
they also have things in common. That’s why they are organized in a hierarchy.
Informally we have already done so, by referring to them as “event listeners”.
Indeed, that’s the name of the superclass:
EventListener
ActionListener
AdjustmentListener
ComponentListener
MouseListener
More precisely, an EventListener is not a class, but an interface: the methods are
not defined in it, but they are merely wish lists, to be implemented by other
classes. Nevertheless, they can be ordered in hierarchies.
(The boxes are marked with double-line borders to indicate the distinction).
67
Events
An eventlistener puts other objects to work by calling methods like
actionPerformed and adjustmentValueChanged. As a parameter, an
object is passed to these methods specifying some details about the event. The
type of that object varies, but always have something in common: they describe an
“event”. That’s why there is a hierarchy of event-describing objects types:
EventObject
AWTEvent
ActionEvent
AdjustmentEvent
ComponentEvent
InputEvent
KeyEvent
FocusEvent
MouseEvent
Object
Everything in one hierarchy
The higher up in the hierarchy, the more general is the description of a class. It is
hard to describe a class high in the hierarchy without being vague. Try and
describe what a Component is, without resorting to examples (“things like buttons
and scrollbars and the like”).
It is a nice pastime to look for similarities between seemingly unrelated classes.
What do String and Component have in common? And an Image and an
ActionEvent? Not that much, but in any case: all of these are descriptions of an
object. Reason enough to give them a superclass in common, which is simply
called Object.
Methods in class Object are of a very general nature. To mention two:
 clone: makes an exact copy of the object
 toString: converts the object to a readable String
Method toString is automatically called when you try to use operator + between a
String and an object. That’s why in many classes toString is redefined, in order
to easily show objects to the user.
68
String
Component
EventObject
Image
11. Strings and Arrays
b.addActionListener(this);
}
In the method called upon user actions, we grab the text form the TextArea, count
the number of symbols, and show the result on the TextField:
11.1 Strings and characters
Class TextArea
We’ve been using TextField objects for enabling the user to type in values.
However, in a TextField you can enter only one line. For multiple-line input, you
can use a TextArea object. You can use a TextArea both for input and for output.
The following methods are available in TextArea:
 TextArea(int r, int c): creates a TextArea having the indicted
number of rows and columns
 void setText(String s): make a string visible on the TextArea
 String getText(): get the text which was entered by the user as a string
 void append(String s): append a string to the text already present on
the TextArea
 void setEditable(boolean b): specify whether or not the user is
allowed to change the text.
As opposed to TextField, a TextArea object cannot have an ActionListener. For a
TextField, an action event occurs when the user hits the Enter key. For a
TextArea, the Enter key will proceed to the next line, but not generate an action
event. To let the user indicate that he completed the text, therefor often a Button is
used in conjunction to a TextArea.
Example: how many characters typed?
As an example, we show a program that enables the user to type in a text in a
TextArea. Whenever the user presses a button, the length of the text is shown in a
single-line TextField.
The class header of an Applet-extension should be familiar by now, so we’ll
proceed to the init method, where the interaction components are created:
public void init()
{
input = new TextArea(5, 40);
output = new TextField(40);
b = new Button("Tel");
this.add(input);
this.add(output);
this.add(b);
public void actionPerformed(ActionEvent e)
{
String s; int n;
s = input.getText();
n = s.length();
output.setText("you typed " + n + " symbols");
}
More interesting would be to not only show the number of characters, but also the
number of words. For that, we need not only inspect the string’s length, but also its
individual characters, in search of spaces. For that, we need some more string
methods.
Class String
In class String, amongst others, the following methods are available:
 int length(): determines a String’s length
 String substring(int x,int y): selects the part of a string
between two positions, and returns that part as a result
 String concat(String s): concatenates the string with another
string, and returns the joined string
 boolean equals(String s): compares a string to another on character
by character
 char charAt(int n): determines which symbol is at a particular
position
Calling substring, you can select part of a string, for example the first five letters:
head = s.substring(0,5);
output.setText(head + " is the head of the string");
Numbering of characters in a string is rather peculiar: the first character appears
on position 0, the second at position 1, etc. The parameters of substring are the
position of the first desired character, and the position of the first character that is
next to the end of the selection. So the call s.substring(0,5) returns the
characters at position 0, 1, 2, 3 and 4; in other words: the first five characters.
You can get the first character of a string by:
69
String initial;
initial = s.substring(0,1);
The result is a string of length 1.
However, there is another way to retrieve single characters form a string: calling
method charAt. The result of that is not a string object, but a primitive value of
type char. As a primitive value, it can be stored in a variable directly:
char first;
first = s.charAt(0);
An advantage of char over strings which happen to have length 1, is that you can
test characters for equality using operator ==, whereas for strings you need to call
method equals.
Primitive type char
Just like other primitive values, you can store char values in variables, pass them
as parameters to methods, yield them as result value of methods, make them part
of an object, etc.
There is a special notation to denote constant char values in a program: you just
type the desired symbol, enclosed in single quotes. Confusion with string
constants in not possible, as they are enclosed in double quotes, as in:
char asterisk;
String railroad;
asterisk = ’*’;
railroad = "####";
In single quotes, precisely one symbol must appear; in double quotes, you may
write many symbols, but also one or no symbol at all.
History of char
The number of different symbols representable in a char has increased in history
(and in different programming languages):
 In the 1970s one thought that 26=64 different symbols would be enough: 26
letters, 10 digits and 28 punctuation marks. Alas, there was no room for
differentiation between capitals and lower case.
 In the 1980s one used 27=128 different symbols: 26 capitals, 26 lower case,
10 digits, 33 punctuation marks and 33 special symbols (newline, tab, beep,
etc). It was known as ASCII: de American Standard Code for Information
70
Interchange. Useful for Americans, but not for Françaises, Deutsche
Mitbürger, and people form España and the Fær-Œr isles.
 In the 1990s a coding scheme with 28=256 symbols was introduced by ANSI
(American National Standards Institute), later adopted by ISO (International
Standards Organization). However, there was no representation for Greek and
Cyrillic letters, the Indian Devangari alphabet and Japanese Kanji-symbols.
 In the 2000s the symbols set was extended to 2 16=65536 different symbols,
which will do for a while. The coding scheme is known as Unicode. The first
256 symbols coincide with ISO-coding, which remains valid therefore.
In Java Unicode is used for characters. You cannot display all the new characters
on all hardware, but at least we are prepared for the future.
Quote symbols
When using strings and chars, be careful not to forget to write the quotes. When
you omit them, the text is not interpreted as literal text, but as Java code. And
there is a big difference between
 the literal string "hello" and the variable name hello
 the literal string "boolean" and the type name boolean
 the literal string "123" and the int value 123
 the literal char-value ’+’ and the addition operator +
 the literal char-value ’x’ and the variable name x
 the literal char-value ’7’ and the int value 7
Special char values
Special values are, being special, not representable in the standard way. For some
special symbols therefore a special notation is in used, involving a reversed
slanted line (backslash):
 ’\n’ for newline
 ’\t’ for tabulation
This introduces a new problem: how to denote a backslash that is really a
backslash? This is done by doubling the backslash: the first backslash means that
something special follows, the next thing is the special thing. This also solves the
problem of how to represent the quote symbols themselves:
 ’\\’ for the backslash
 ’\’’ for a single quote sign
 ’\"’ for a double quote sign
Although there are two glyphs between the quotes, they represent only one
symbol.
public void actionPerformed(ActionEvent e)
{
String s;
s = input.getText();
Doing arithmetic with char
Unicode-symbols are ordered: each symbol has an ordinal number. For example:
the ordinal number of ’A’ is 65, of ’a’ it is 97. Note that the ordinal number of
’0’ is not 0, but 48. Also the space is not numbered 0, but 32. The symbol having
code 0 is a special symbol having no visual representation.
You can determine the ordinal number of a char by assigning a char value to an
integer variable:
For the counting, we need to inspect each individual character of the string. We’ll
count the number of spaces and newlines; after all, that’s what separates words.
Therefore we declare two variables that will hold the respective counts, and one
variable by which we can indicate a position:
char c; int i;
c = ’*’;
i = c;
int spaces, lines, position;
Using a for-statement we can let variable position indicate all possible positions in
the string. Note that the count starts at 0, and continues up to (but not including)
the length of the string:
spaces = 0;
lines = 0;
for (position=0; position<s.length(); position++)
or directly:
i = ’*’;
This is always possible; after all, there are only 65536 different symbols, where an
int can hold values up to 2 billion.
For the conversion back form int to char, you need to guarantee that the value is in
range. This is done by writing the parenthesized word (char) before the value:
c = (char) i;
This way, you can do arithmetic with characters: the symbol following ’z’ is
(char)(’z’+1), and the capital version of c is the c-’A’+1-th letter of the
alphabet.
This “range guaranteeing”-notation is known as a cast. We’ve been using it for
converting double values to int values, agreeing that the value would be truncated
if non-integral:
double d; int i;
d = 3.14159;
i = (int) d;
Example: counting words
Now we can adapt the previous example program, to show not only the number of
characters typed, but also the number of words. To start with, we again grab the
text that was entered from the input TextArea:
In de body of the for-statement we get a character by calling charAt, and check
whether it is a space or a newline:
{
if (s.charAt(position)==’ ’ ) spaces++;
if (s.charAt(position)==’\n’) lines++;
}
Finally we can show the result to the user:
output.setText( spaces+lines + " words\n"
+ "on " + lines + " lines"
);
}
Note that we use the newline symbol "\n" to split the output on two lines.
11.2 Arrays
Array: many variables having the same type
In the next section we’ll write a program which not only counts frequencies of
spaces and newlines, but of every letter of the alphabet. Hence the output will be
something like “23 A’s, 7 B’s, 3 C’s, 8 D’s …”.
Instead of having two counters for holding the number of spaces and newlines, we
could declare 26 variables for holding the counts for each individual letter. The
declaration is rather large:
int as, bs, cs, ds, es, fs, gs, hs, is, js, ks, ls, …
71
and what’s worse: in the body of the for-statement we need 26 if-statements for
checking against all letters:
if
if
if
if
(s.charAt(position)==’a’
(s.charAt(position)==’b’
(s.charAt(position)==’c’
(s.charAt(position)==’d’
)
)
)
)
as++;
bs++;
cs++;
ds++; // etcetera…
Fortunately, there is an easier way to declare many variables. You can create a row
of numbered values, each addressable using its sequence number. Such a row is
known as an array.
Creation of arrays
An array has many characteristics of an object. First, you need to declare a
variable that will hold the reference to the array. For an array holding int-values,
the declaration looks like:
int [] table;
The square brackets indicate that we are not dealing with a single int-variable, but
rather with an array of values. The variable table is not the array itself: it is a
reference variable, which might refer to an array in the future.
table
To indeed let the variable refer to an array, we need an assignment statement. As
with object, we need a new-expression for creating the object. The notation differs
slightly form objects: after new, the type of the elements follows, and their number
in brackets:
table = new int[5];
The situation in memory is now as follows:
table
5
length
0
1
2
3
4
72
The array object created consists of an int-variable storing the length, and a
sequence of numbered variables of the desired type (which in this case happens to
be int as well). The numbering starts at 0, and that’s why the last number is one
less than the length.
Using array values
You can assign values to the component values of an array by mentioning the
reference variable, followed by the index number in square brackets:
table[2] = 37;
in the same way, you can use array elements in an expression:
x = table[2] + 5;
In short, array elements can be used as any variable.
The variable length, which is also an attribute of an array, can also be used in
expressions, for example
if (table.length < 10) …
You can, however, not change the length. Once created, the length of an array is
fixed.
The real power of arrays lies in the fact that the number indicating the desired
array element can be denoted by an expression. Take, for instance, the situation
where all array elements need to get the same value. You could do so with a long
series of assignment statements:
table[0] = 0;
table[1] = 0;
table[2] = 0;
table[3] = 0;
table[4] = 0;
but that’s rather tedious (especially for long arrays). Instead, we’d better exploit
the pattern in these statements: instead of the index (which is 0, 1, 2, 3 or 4) we
can write a variable. In a for-statement the variable traverses all values in the
range. The length of the array can be used as an upper bound for the count:
int number;
for (number=0; number<table.length; number++)
table[number] = 0;
Arrays as a parameter
You can pass arrays as a parameter to a method. It’s not really the array that is
passed but rather the reference to it. The array object itself is still in the same place
in memory where it was created.
It’s reasonable to expect that the method will be called with a reference to an
existing array (thus, doesn’t have null as its value), and furthermore that all
components are initialized. The situation might be as follows:
table
5
particles
length
12
0
95
1
11
2
length
23
3
3
15
4
Now we can write a method that takes such an array as a parameter, and for
example determines the smallest element in the array:
static int smallest(int [] table)
First guess is that the very first value of the array is the smallest. In the example,
that value is 12. That is not the smallest of all (because 11 is smaller), but we’ve
not yet inspected that value.
{
Arrays of objects
Elements of an array can be of any desired type. It could be a primitive type, like
int, double, boolean or char, but also an object-type. You can thus create arrays of
Strings, Buttons, TextFields, or of objects for which you defined the class
yourself, like Particle in chapter 9.
Here is an array of Particle objects, which could have been used instead of the
separate variables d1, d2 and d3 in chapter 9:
int result;
result = table[0];
Now, we use a for-statement to inspect all values. For each value we check
whether it is smaller than what we thought was the smallest up till now. If so, we
adapt the result value:
int number;
for (number=0; number<table.length; number++)
if (table[number] < result)
result = table[number];
After the for-statement is completed, we can safely return the result value, because
it has been checked against all values in the array.
0
1
2
x
y
dx
dy
color
x
y
dx
dy
color
x
y
dx
dy
color
Particle
Particle
Particle
The reference variable can be declared with:
Particle [] particles;
The array proper can be created with:
particles = new Particle[3];
But beware! We have created the array now, but not the individual particle
objects. This should be done in a for statement, creating each individual particle:
int number;
for (number=0; number<particles.length; number++)
particles[number] = new Particle();
return result;
}
73
Arrays versus strings
Arrays having characters as elements have much in common with string objects:
both in an array-of-char and in a String, characters can be stored. Yet there are
differences between an array-of-char and a String, the most prominent being:
 In an array, individual elements can be changed writing a[x]=…;
which is not possible in a String.
 With a String you can call various methods, like equals and substring.
Furthermore you can “add” Strings using the plus-operator. For arrays, neither
of these is possible.
But there are also similarities, although the notation might be different:
 Both from an array and from a String you can select the n-th element, using
the notation a[x] and s.charAt(x) respectively.
 Both from an array and from a String you can determine the length. For an
array this is done by inspecting the object variable length: a.length , for a
String it is done by calling a method: s.length() Note that for an array
no parentheses are needed, but for a String they are.
in counter number 26. Capitals and lower case letters are treated separately; other
symbols are just ignored.
for (n=0; n<s.length(); n++)
{
c = s.charAt(n);
if (c>=’A’ && c<=’Z’)
table[c-’A’]++;
else if (c>=’a’ && c<=’z’)
table[c-’a’]++;
}
After the entire string is checked, we can display the results. We’ll step through
the entire array, for each counter displaying an applicable text, by appending it to
the output TextArea:
output.setText("");
for (n=0; n<26; n++)
{
c = (char)(n+’A’);
output.append (c + ": " + table[n]
+ " times\n"
);
}
11.3 Example: Text analysis with letter frequencies
Counting of individual character frequencies
We can now adapt the running example, this time counting not only the
frequencies of spaces and newlines, but also the frequencies of each individual
character in a text. We’ll revise method actionPerformed once more:
public void actionPerformed(ActionEvent e)
{
String s; int n; char c;
s = input.getText();
For the 26 counters we create an array of integers. It must be declared, created,
and initialized to zero:
table = new int[26];
for (n=0; n<26; n++)
table[n] = 0;
Now we can inspect all characters of the string. For each symbol that we
encounter, we increment the corresponding counter in the array. The number of
the counter is determined by subtracting the Unicode-code of constant ‘A’ from
the symbol taken from the string. That way, the number of A’s is counted in
counter number 0, the number of B’s in counter number 1, and the number of Z’s
74
}
Separating contents from the user interface
Meanwhile, the method has grown rather complex. What is especially
complicated, is that various problems play a role: grabbing the text from the
TextArea, creation of the array, the actual checking, and the layout of the message
displayed.
It would increase readability if we could outsource some of these tasks to a
separate class. For example, we could define a class Checker, which could provide
a method check for checking all characters in a string. If we could also ask it to
return the final message as one string, the whole method actionPerformed would
consist of only four lines:
public void actionPerformed(ActionEvent e)
{
Checker c;
c = new Cheker();
c.turf( input.getText() );
output.setText( c.toString() );
}
Of course, such a Checker class does not exist. However, we can define one for
our purpose. Various tasks are put in separate methods:
 in the constructor method: creating and initializing the array
 in method check: the actual counting
 in method toString: layouting the result
We can write a fourth method, that handles the checking of a single character,
taking into account the capital/lower case distinction. In the check method, we can
call that method for all characters in the string.
In the main class, apart from the short version of actionPerformed, only the
creation of the user interface remains. Thus, all communication with the user is
done in one class, and all “contentual” matter is done in another class. Such a
separation of concerns is always a good idea.
In listing 11.1 and 11.2 the complete program is given.
75
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
class Checker
{
int counters[];
int total;
public class Text extends Applet
implements ActionListener
{
TextArea input, output;
Button b;
public Checker()
{
counters = new int[26];
}
public void init()
{
input = new TextArea( 5,30);
output = new TextArea(28,20);
b
= new Button("Count");
output.setEditable(false);
this.add(input);
this.add(b);
this.add(output);
b.addActionListener(this);
}
private void check(char c)
{
if (c>='A' && c<='Z')
{
counters[c-'A']++;
total++;
}
else if (c>='a' && c<='z')
{
counters[c-'a']++;
total++;
}
}
public void actionPerformed(ActionEvent e)
{
Checker c;
c = new Checker();
c.check( input.getText() );
output.setText( c.toString() );
}
public void check(String s)
{
for (int i=0; i<s.length(); i++)
check( s.charAt(i) );
}
}
Listing 11.1: Text.java
Listing 11.2: Checker.java
Figuur 11.1: snapshot of the Text program
76
public String toString()
{
String s = "";
for (int i=0; i<26; i++)
s += (char)(i+'A') + ": "
+counters[i]+ "times\n";
s += "total: " + total;
return s;
}
}
12. Designing the interface
12.1 Layout of the user interface
Layout managers
Interaction components that are added to the interface appear all next to each
other. When they don’t fit in the row, they are continued in a next row.
The spaces available for the applet may vary. When running an applet with
appletviewer, this can even be done while the program is running. When running
an applet with a browser, the dimensions are fixed, but can be changed in the
HTML file.
If the dimensions are changed, interaction components are reshuffled: there may
fit more components next to each other, or fewer. By cleverly choosing sizes, you
can force a cute layout (as was done in Simulation, where the three Space objects
just fit in the first row, so that the Button objects appear in the second row).
The positioning is done automatically, and is done by a so-called LayoutManager,
which is associated with the Applet. If you are not satisfied with the layout, you
can choose another layout manager. This is done by calling method setLayout
(which is available in Component and all its subclasses). As a parameter you pass
the desired manager, which is (of course!) an object itself. for example:
this.setLayout( new BorderLayout() );
Because you need to reference it only once, you need not to first store the layout
manager object in a variable, but you can immediately pass it to setLayout.
Available Layout managers
In the library, some four layout managers classes are available. All of them are
implementations of interface LayoutManager, which is what setLayout expects:
LayoutManager
BorderLayout
FlowLayout
GridLayout
The standard layout manager is FlowLayout. It positions the components next to
each other/below each other from left to right, from top to bottom.
Instead, you could choose for a GridLayout, to order components in a fixed grid.
As parameters to the constructor method of GridLayout you specify the number of
rows and columns, and the number of pixels between them:
this.setLayout( new GridLayout(2,3,5,5) );
The manager changes the shape of the individual components. Available space is
evenly distributed among components. If there is not enough space, you are out of
luck (see the button with caption “kortschildkever”).
A BorderLayout orders its components along the borders of the available space:
four at the various edges, and a fifth in the center. There cannot be more than five
components in this case. The position is mentioned as an additional parameter to
add: a string specifying a compass direction or “Center”:
this.setLayout( new BorderLayout() );
this.add( "North", new Button("koe") );
this.add( "West", new Button("varken") );
this.add( "Center",new Button("kortschildkever") );
this.add( "East", new Button("kip") );
this.add( "South", new Button("olifant") );
North and south edges get as much vertical space as necessary, but are stretched in
width. West and east get as much horizontal space as is needed, and are stretched
vertically. The remaining space is for the center.
A final possibility is having no layout manager at all. To get rid of the default
FlowLayout, you specify null as a layout manager. The price is that you’ll have to
77
position every component yourself by calling setBounds. You’ll have complete
freedom of layout, but nothing is rearranged when the size of the window changes!
Your init method will contain statements like
b =new Button("koe");
b.setBounds(10,10,70,20);
this.add(b);
b =new Button("varken");
b.setBounds(25,50,50,30);
this.add(b);
b =new Button("kortschildkever");
b.setBounds(40,30,100,15);
this.add(b);
12.2 Example: Calculator
Description of the case
We’ll create a simple 4-function calculator, which the user can control via buttons
on the screen:
The result will look like:
Class Panel
You can achieve more complex layouts by using Panel objects, which have a
layout manager of their own. A Panel is a component to which you can add subcomponents, which are arranged with a local layout. So the applet can have a
BorderLayout, with a Panel appearing in the center, which in turn has a
GridLayout.
You can even nest Panels within Panels, thus creating complicated “dashboards”
for controlling your program.
78
Division in classes
As in the previous chapter we’ll write two classes:
 a class Calc which creates the interface and handles the button presses
 a class Proc doing all arithmetic, but which does not deal with user
interaction.
The program appears in listing 12.1.
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
class Proc
{
long value, prev, screen;
char operator;
public class Calc extends Applet implements ActionListener
{
Label result;
Panel knoppen;
Proc proc;
Proc()
{
clear();
}
void clear()
{
value = 0;
prev = 0;
operator = '+';
screen = 0;
}
public void init()
{
Button knop;
String opschrift;
proc
= new Proc();
result = new Label( "0", Label.RIGHT );
knoppen = new Panel();
result.setFont( new Font("Arial", Font.BOLD, 20) );
void calc()
{
switch(operator)
{
case '+': prev
case '-': prev
case '*': prev
case '/': prev
}
screen = prev;
value = 0;
}
this.
setLayout( new BorderLayout() );
knoppen.setLayout( new GridLayout(4,4,6,6) );
for (int n=0; n<16; n++)
{
opschrift = "789/456*123+0C=-".substring(n,n+1);
knop
= new Button(opschrift);
knop.addActionListener(this);
knoppen.add( knop );
}
this.add( "North", result );
this.add( "Center", knoppen );
}
}
value;
value;
value;
value;
break;
break;
break;
break;
void digit(int n)
{
value = 10*value+n;
screen = value;
}
public void actionPerformed(ActionEvent e)
{
Button b; char c;
b = (Button) (e.getSource());
c = b.getLabel().charAt(0);
if
(c=='C')
proc.clear();
else if (c=='=')
proc.calc();
else if (c>='0'&&c<='9') proc.digit( c-'0' );
else
proc.operation(c);
result.setText( ""+proc.screen );
+=
-=
*=
/=
void operation(char c)
{
calc();
operator = c;
}
}
}
79
A. Reserved words
kind
statements
parts of
statements
primitive types
80
keyword
break
continue
do
for
if
return
switch
throw
try
while
case
catch
default
else
finally
boolean
byte
char
double
float
int
long
short
void
see section
12.2
kind
special values
7.3
8.1
4.3
12.2
program structure
9.3
7.1
12.2
9.3
12.2
8.1
modification of
classes and methods
7.2
11.1
8.3
3.2
historic remains
2.4
keyword
false
instanceof
new
null
super
this
true
class
extends
import
interface
package
throws
abstract
final
native
private
protected
public
static
synchronized
threadsave
transient
byvalue
const
goto
see section
7.2
6.2
9.3
10.1
4.1
7.2
2.3
2.3
2.8
6.5
4.2
2.4
5.3
B. Operators and syntax
prio
14
14
14
13
13
13
13
12
12
12
11
11
10
10
10
9
9
9
9
8
8
7
6
5
4
3
2
1
1
operator
()
[]
.
++
-!
*
/
%
+
<<
>>
>>>
<
>
<=
>=
==
!=
&
^
|
&&
||
? :
=
op=
position
post
post
in
pre/post
pre/post
pre
pre
in
in
in
in
in
in
in
in
in
in
in
in
in
in
in
in
in
in
in
mix
in
in
semantics
method call
array selection
component selection
increment
decrement
bitwise “not”
logical “not”
multiplication
division
Remainder after division
Addition, or: concatenating strings
Substraction
Shifting bits tot the left
Shifting bits tot the right
ditto, filling with zeroes
less than
bigger than
at most
at least
equal to
unequal to
bitwise “and”
bitwise “exclusive or”
bitwise “or”
logical “and”
logical “or”
if – then – else
assignment
calculate and assign
program
item
class
method
par-decl
declaration
statement
expression
item*
import expression ;
class
class name [extends name] { [declaration]* method* }
[modification]* name ( [par-decl [ , pardecl]*]) { statement* }
type name
type [[]]* name
type name [ , name]* ;
type [[]]* name [, [[]]* name ] ;
declaration
expression ;
if ( expression ) statement [ else statement ]
while ( expression ) statement
for ( [expression] ; [expression] ; [expression] ) statement
switch ( expression ) statement
try { statement* } [catch ( par-decl ) { [statement]* }]*
break ;
return [expression] ;
{ statement* }
Number
’ symbol ’
”[symbol]*”
variable
expression operator expression
expression postfix-operator
( expression )
expression . expression
expression [ expression ]
expression ( expression )
class . expression
( type ) expression
new expression
new type [ expression ]
Parts in […] may be omitted
Parts followed by * may be repeated
Parts in typewriter type must appear literally
81
class Thread
©
Thread
void
start
static void
sleep
interface Runnable
void
run
C. Summary Java-packages
12.1 package java.lang
class Object
String toString
class String
boolean equals
boolean equalsIgnoreCase
boolean compareTo
int
length
String substring
String substring
String concat
char
charAt
int
indexOf
String toUpperCase
int
hashCode
class Integer
static int
parseInt
class Double
static Double valueOf
double doubleValue
class System
static void
exit
static InputStream in;
static PrintStream out;
class Math
static double PI, E;
static int
abs
static double abs
static double sqrt, log, exp
static double sin, cos, tan
static double pow
static int
min, max
static double min, max
static double random
82
()
(String s)
(String s)
(String s)
()
(int from)
(int from, int to)
(String s)
(int pos)
(char c)
()
()
8.2
9.5
9.5
9.5
9.5
9.5
13.4
5.3
(String s)
()
8.3
8.3
(int n)
(double d)
(double d)
(double d)
(double base, double expo)
(int a, int b)
(double a, double b)
()
9.3
9.3
9.3
()
9.3
12.2 package java.util
(String s)
(int x)
(Runnable r)
()
(long milliseconds)
13.2
13.5
13.5
5.3
5.3
5.3
5.3
5.3
15.2
class StringTokenizer
©
StringTokenizer
(String tosplit, String separators)
String nextToken
()
boolean hasMoreTokens
()
class Vector
©
Vector
()
void
addElement
(Object x)
void
setElementAt
(Object x, int n)
Object elementAt
(int n)
int
size
()
boolean isEmpty
()
class Stack
©
Stack
()
void
push
(Object x)
Object pop
()
boolean empty
()
class Calendar
static Calendar getInstance
()
int
get
(int field)
int
set
(int field, int value)
static int
SECOND,MINUTE,HOUR,AM_PM,HOUR_OF_DAY; // fields
static int
DATE,MONTH,YEAR; // fields
static int
DAY_OF_WEEK,DAY_OF_MONTH,DAY_OF_YEAR; // fields
static int
WEEK_OF_MONTH,WEEK_OF_YEAR; // fields
static int
JANUARY,...,DECEMBER; // values field MONTH
static int
SUNDAY,...,SATURDAY; // values field DAY_OF_WEEK
void
setMinimalDaysInFirstWeek (int value)
void
setFirstDayOfWeek
(int value)
int
getMaximum
(int field)
int
getActualMaximum
(int field)
9.5
9.5
9.5
16.3
16.3
16.3
16.3
16.3
16.3
16.3
16.3
16.3
16.3
9.5
9.5
12.3 package java.awt
class Graphics
void
drawString
(String s, int x, int y)
2.5
void
drawLine
(int x1, int y1, int x2, int y2)
3.1
void
drawRect
(int x, iny y, int b, int h)
3.1
void
drawOval
(int x, int y, int b, int h)
3.1
void
drawImage
(Image im, int x, int y)
15.1
void
fillRect
(int x, int y, int b, int h)
3.1
void
fillOval
(int x, int y, int b, int h)
8.1
void
setColor
(Color c)
3.1
class Color
©
Color
(int r, int g, int b)
6.2
static Color white, gray, black, red, green, blue, yellow, magenta, cyan, orange, pink;
3.1
class Font
©
Font
(String name, int style, int size)
12.2
static int
BOLD, ITALIC, PLAIN; // styles
12.2
class Dimension
int
width, height;
9.2
class Toolkit
static Toolkit getDefaultToolkit
()
15.1
Image getImage
(String filename)
15.1
class Image
15.1
int
getWidth
(ImageObserver x) // e.g. null
15.1
int
getHeight
(ImageObserver x) // e.g. null
15.1
class BufferedImage extends Image
©
BufferedImage
(int b, int h, int type)
static int
TYPE_INT_RGB, TYPE_INT_ARGB, TYPE_BYTE_GRAY, ... ; // types
void
setRGB
(int x, int y, int rgb)
9.5
int
getRGB
(int x, int y)
9.5
Graphics getGraphics
()
9.5
class MediaTracker
©
MediaTracker
(Component parent)
15.1
void
addImage
(Image im, int id)
15.1
void
waitForID
(int id)
15.1
void
waitForAll
()
15.1
class PixelGrabber
©
PixelGrabber
(Image im, int x, int y, int b, int h,
int [] target, int offset, int scansize) 15.1
void
grabPixels
()
15.1
class AudioClip
void
play
void
loop
void
stop
class MenuBar
©
MenuBar
class Menu
©
Menu
void
add
void
addSeparator
class MenuItem
©
MenuItem
void
addActionListener
()
()
()
9.5
9.5
9.5
()
13.2
(String s)
(MenuItem m)
()
13.2
13.2
13.2
(String s)
(ActionListener a)
13.2
6.5
Layout managers
LayoutManager
BorderLayout
FlowLayout
GridLayout
interface LayoutManager
class BorderLayout implements LayoutManager
©
BorderLayout
()
static String NORTH,SOUTH,EAST,WEST,CENTER; // add-directions
class FlowLayout implements LayoutManager
©
FlowLayout
()
class GridLayout implements LayoutManager
©
GridLayout
(int rows, int cols, int dx, int dy)
12.1
12.1
12.1
83
Interaction-components
Component
Button
Panel
Applet
Container
Canvas
Window
Frame
Label
TextComponent
TextArea
Scrollbar
TextField
Dialog
FileDialog
class Component
void
addMouseListener
(MouseListener m)
void
addMouseMotionListener (MouseMotionListener m)
void
addKeyListener
(KeyListener k)
void
setVisible
(boolean b)
void
setSize
(int b, int h)
void
setBounds
(int x, int y, int b, int h)
void
setBackground
(Color c)
void
setFont
(Font f)
Dimension getSize
()
void
paint
(Graphics g)
void
update
(Graphics g)
void
repaint
()
class Container extends Component
void
add
(Component c)
void
add
(Component c, Object richting)
void
setLayout
(LayoutManager m)
class Panel extends Container
©
Panel
()
class Applet extends Panel
void
init
()
String getParameter
(String name)
Image getImage
(URL base, String name)
class Window extends Container
void
addWindowListener
(WindowListener w)
void
show
()
84
15.2
15.2
8.2
9.2
12.1
9.2
12.2
9.2
2.4
15.2
6.3
6.3
12.1
12.1
12.1
6.3
5.1
15.1
13.2
13.4
class Frame extends Window
void
setMenuBar
(MenuBar b)
void
setTitle
(String s)
class Dialog extends Window
class FileDialog extends Dialog
©
FileDialog
(Frame parent, String title, int typ)
String getFile
()
class Button extends Component
©
Button
(String s)
void
setLabel
(String s)
void
addActionListener
(ActionListener a)
class Canvas extends Component
©
Canvas
()
class Label extends Component
©
Label
(String s)
©
Label
(String s, int alignment)
static int
LEFT, CENTER, RIGHT; // alignments
void
setText
(String s)
class Scrollbar extends Component
©
Scrollbar
(int alignment, int value, int step,
int minimum, int maximum)
static int
HORIZONTAL, VERTICAL; // alignments
void
addAdjustmentListener (AdjustmentListener a)
void
setValue
(int x)
int
getValue
()
class TextComponent extends Component
String getText
()
void
setText
(String s)
void
setEditable
(boolean b)
class TextField extends TextComponent
©
TextField
(int cols)
©
TextField
(String s, int cols)
void
setEchoChar
(char c)
void
addActionListener
(ActionListener a)
class TextArea extends TextComponent
©
TextArea
(int rows, int cols)
void
append
(String s)
13.2
13.4
13.2
13.4
6.2
6.4
6.5
9.2
9.5
12.2
12.2
6.4
6.4
6.5
6.4
6.4
7.5
8.1
11.1
7.5
7.5
8.2
6.5
11.1
11.1
Event-objects
12.4 package java.awt.event
EventObject
Event-listeners
EventListener
ActionListener
AdjustmentListener
ComponentListener
AWTEvent
ActionEvent
MouseListener
AdjustmentEvent
ComponentEvent
InputEvent
interface EventListener
interface ActionListener extends EventListener
void
actionPerformed
(ActionEvent e)
interface AdjustmentListener extends EventListener
void
adjustmentValueChanged (AdjustmentEvent e)
interface WindowListener extends EventListener
void
windowClosing
(WindowEvent e)
void
windowOpened
(WindowEvent e)
void
windowClosed
(WindowEvent e)
void
windowActivated
(WindowEvent e)
void
windowDeactivated
(WindowEvent e)
void
windowIconified
(WindowEvent e)
void
windowDeiconified
(WindowEvent e)
interface MouseListener extends EventListener
void
mousePressed
(MouseEvent e)
void
mouseReleased
(MouseEvent e)
void
mouseClicked
(MouseEvent e)
void
mouseEntered
(MouseEvent e)
void
mouseExited
(MouseEvent e)
interface MouseMotionListener extends EventListener
void
mouseMoved
(MouseEvent e)
void
mouseDragged
(MouseEvent e)
interface KeyListener extends EventListener
void
keyPressed
(KeyEvent e)
void
keyReleased
(KeyEvent e)
void
keyTyped
(KeyEvent e)
KeyEvent
6.5
6.5
13.2
13.2
13.2
13.2
13.2
13.2
13.2
15.2
15.2
15.2
15.2
15.2
15.2
15.2
FocusEvent
MouseEvent
class EventObject
Object getSource
()
8.1
class AWTEvent extends EventObject
class ActionEvent extends AWTEvent
class AdjustmentEvent extends AWTEvent
int
getValue
()
int
getAdjustmentType
()
static int
UNIT_INCREMENT, BLOCK_INCREMENT, TRACK,...; // types
class ComponentEvent extends AWTEvent
class InputEvent extends ComponentEvent
boolean isAltDown
()
15.2
class KeyEvent extends InputEvent
char
getKeyChar
()
int
getKeyCode
()
static int
VK_LEFT,VK_RIGHT,VK_UP,VK_DOWN,VK_HOME,VK_END,
static int
VK_PAGE_UP,VK_PAGE_DOWN,VK_F1,...,VK_F24,...; // keycodes
class MouseEvent extends InputEvent
int
getX
()
15.2
int
getY
()
15.2
12.5 package java.net
class URL
©
URL
(String specification)
14.3
©
URL
(String prcol, String host, String file)14.3
URLConnection openConnection ()
14.3
class URLConnection
InputStream getInputStream
()
14.3
85
12.6 package java.io
Non-stream
class File
©
File
©
File
©
File
static String pathSeparator
static char
pathSeparatorChar
String getName
File
getParentFile
boolean exists
boolean isFile
boolean isDirectory
void
delete
long
length
File[ ] listFiles
File[ ] listRoots
class RandomAccessFile
©
RandomAccessFile
int
read
void
write
long
getFilePointer
void
seek
Byte streams
class InputStream
int
read
int
read
long
skip
void
close
class OutputStream
void
write
void
write
void
flush
void
close
86
(String pathname)
(String parent, String child)
(File parent, String child)
()
()
()
()
()
()
()
()
()
()
()
13.4
13.4
13.4
9.5
9.5
9.5
13.4
13.4
9.5
13.4
13.4
(File f, String mode)
(byte[ ] b)
(byte[ ] b)
()
(long pos)
()
(byte[ ] b)
(long number)
()
13.4
13.4
(int b)
(byte[ ] b)
()
()
13.4
13.4
class FileInputStream extends InputStream
©
FileInputStream
(String name)
©
FileInputStream
(File f)
class ByteArrayInputStream extends InputStream
©
ByteArrayInputStream (byte[ ] b)
class FilterInputStream extends InputStream
class BufferedInputStream extends FilterInputStream
©
BufferedInputStream (InputStream is)
class DataInputStream extends FilterInputStream
©
DataInputStream
(InputStream is)
int
readInt
()
double readDouble
()
// etcetera
class FileOutputStream extends OutputStream
©
FileOutputStream
(String name)
©
FileOutputStream
(File f)
class ByteArrayOutputStream extends OutputStream
©
ByteArrayOutputStream ()
byte[ ] toByteArray
()
class FilterOutputStream extends OutputStream
class BufferedOutputStream extends FilterOutputStream
©
BufferedOutputStream (OutputStream os)
class DataOutputStream extends FilterOutputStream
©
DataOutputStream
(OutputStream os)
void
writeInt
(int n)
void
writeDouble
(double d)
// etcetera
class PrintStream extends FilterOutputStream
// no constructor, use PrintWriter!
void
print
(Object o)
void
println
(Object o)
13.4
13.4
13.4
13.4
13.4
13.4
13.4
13.4
13.4
13.4
13.4
13.5
13.5
13.5
Character streams
class Reader
int
read
int
read
class Writer
void
write
void
write
void
write
void
close
()
(char[ ] c)
13.4
13.4
(int c)
(char[ ] c)
(String s)
()
13.4
class InputStreamReader extends Reader
©
InputStreamReader
(InputStream is)
©
InputStreamReader
(InputStream is, String encoding)
class FileReader extends InputStreamReader
©
FileReader
(String name)
©
FileReader
(File f)
class StringReader extends Reader
©
StringReader
(String s)
class BufferedReader extends Reader
©
BufferedReader
(Reader r)
String readLine
()
class LineNumberReader extends BufferedReader
©
LineNumberReader
(Reader r)
int
getLineNumber
()
class FilterReader extends Reader
class PushbackReader extends FilterReader
©
PushbackReader
(Reader r)
void
unread
(int c)
class OutputStreamWriter extends Writer
©
OutputStreamWriter
(OutputStream os)
class FileWriter extends OutputStreamWriter
©
FileWriter
(String name)
©
FileWriter
(File f)
class StringWriter extends Writer
©
StringWriter
()
String toString
()
class BufferedWriter extends Writer
©
BufferedWriter
(Writer w)
13.4
class FilterWriter extendsWriter
class PrintWriter extendsWriter
©
PrintWriter
©
PrintWriter
void
print
void
print
void
println
void
println
(Writer w)
(OutputStream os)
(Object o)
(allPrimTypes x)
(Object o)
(allPrimTypes x)
13.4
13.4
13.4
12.7 Application
13.4
one classof the program contains method:
static void
main
(String [ ] ps)
13.1
13.4
13.4
13.4
13.4
13.4
13.4
12.8 Primitive types
type
void
boolean
char
byte
short
int
long
contains
nothing
truth
unicodesymbol
integer number
integer number
integer number
integer number
default
false
(char)0
0
0
0
0
size
0 bits
1 bit
16 bits
8 bits
16 bits
32 bits
64 bits
float
double
floating point
floating point
0.0
0.0
32 bits
64 bits
range
false, true
(char)0 .. (char)65535
–128 .. 127
–32768 .. 32767
–2147483648 .. 2147483647
–9223372036854775808 ..
9223372036854775807
±1.4E–45 .. ±3.4028235E+38
±4.9E–324 ..
±1.7976931348623157E+308
13.4
13.4
13.4
87
Download