Java
Java
by
Willi-Hans Steeb
International School for Scientific Computing
email address of the author:
steebwilli@gmail.com
and
Yorick Hardy
International School for Scientific Computing
email address of the author:
yorickhardy@gmail.com
Web page:
http://issc.uj.ac.za
Contents
1 Introduction 1
1.1 Why Java ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Aim of Object-Oriented Programming . . . . . . . . . . . . . . . . . 2
1.2.1 Information Hiding . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.2 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.3 Polymorphism . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.4 Built-In Classes . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.5 Java Compared To C++ . . . . . . . . . . . . . . . . . . . . . 5
1.3 Identifiers and Keywords in Java . . . . . . . . . . . . . . . . . . . . 6
2 Java Basics 7
2.1 My First Java Program . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 My First Applet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.3 Basic Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.4 Arithmetic Operations . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.5 Unicode, ASCII Table, and Types Conversion . . . . . . . . . . . . . 18
2.6 Precedence Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.7 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.8 Control Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.8.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
2.8.2 The if Statement . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.8.3 The for Loop, while Loop, do-while Loop . . . . . . . . . . . . 31
2.8.4 The switch Statement . . . . . . . . . . . . . . . . . . . . . . 35
2.9 Logical AND, Logical OR and Logical NOT . . . . . . . . . . . . . . 38
2.10 Bitwise Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.11 Shift Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.12 Pass by Value, Pass by Reference . . . . . . . . . . . . . . . . . . . . 43
2.13 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
2.14 Jump Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
2.15 Reading from Keyboard . . . . . . . . . . . . . . . . . . . . . . . . . 54
2.16 Command Line Arguments . . . . . . . . . . . . . . . . . . . . . . . . 56
2.17 System Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
2.18 Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.19 Applets and HTML Parameters . . . . . . . . . . . . . . . . . . . . . 62
i
3 String Manipulations 64
3.1 String Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.2 StringTokenizer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
3.3 StringBuffer Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
9 Threads 228
9.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
9.2 Thread Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
9.3 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
9.4 Priorities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
9.5 Synchronization and Locks . . . . . . . . . . . . . . . . . . . . . . . . 240
9.6 Producer Consumer Problem . . . . . . . . . . . . . . . . . . . . . . . 245
9.7 Deadlock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
10 Animation 250
10.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
10.2 Image Class and Animation . . . . . . . . . . . . . . . . . . . . . . . 252
10.3 AudioClip Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
11 Networking 266
11.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
11.2 Addresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
11.3 Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
11.4 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
11.5 URL Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
11.6 Socket Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
11.7 Client-Server Application . . . . . . . . . . . . . . . . . . . . . . . . . 284
11.8 Remote Method Invocation . . . . . . . . . . . . . . . . . . . . . . . 292
11.9 SocketChannel and ServerSocketChannel . . . . . . . . . . . . . . . . 301
Bibliography 385
Index 385
iv
Preface
Besides C++ Java is now the most widely available and used object-oriented pro-
gramming language. It is a very useful language that is successfully utilized by
many programmers in many application areas. It is a reasonably carefully thought-
out language where the design is based partly on acknowledged principles and partly
on solid experience and feedback from actual use. Java is a powerful but lean object-
oriented programming language. It makes it possible to program for the Internet by
creating applets, i.e. programs that can be embedded in a web page. For example,
an applet can be an animation with sound, an interactive game, or a ticker tape
with constantly updated stock prices. However Java is more than a programming
language for writing applets. It also can be used for writing standalone applications.
It seems it is becoming the standard language for both general-purpose and Internet
programming. Java is close to C++. It has taken many features of C++, but unfor-
tunately discarded some of them, for example templates and multiple inheritence.
To this lean core it has added garbage collection (automatic memory management),
multithreading (the capacity for one program to do more than one task at the time),
and security capabilities. Java is a platform consisting of three components: (1) the
Java programming language, (2) the Java library of classes and interfaces (Java has
a huge number of built-in classes and interfaces), and (3) the Java Virtual Machine.
In chapter 2 we give the basic concepts in Java. The given programs are very helpful
for the beginners. They are also the building blocks for more complex applications.
The widely used String class and the classes StringTokenizer and StringBuffer
are introduced. Chapter 3 is devoted to classes and objects. Furthermore the
wrapper classes, the container class Vector, the class Math for doing mathematics
and the BigInteger and BigDecimal classes are introduced. The Object class is the
ancestor of all classes and discussed in detail in section 3.6. Finally the this object
is explained in detail. Chapter 4 deals with inheritance and abstract classes. The
graphical user interface (GUI) is discussed in chapter 5 and a number of examples
are provided. Chapter 6 introduces exception handling. File manipulations for
reading from file and writing to files are introduced in chapter 7. Java is able
to produce multi-threaded applications, which often form a part of applications
including animations. Threads are discussed in chapter 8 and application of threads
in animation are given in chapter 9. An introduction into networking together with
a number of programs is given in chapter 10. Chapters 11 and 12 deal with the
additions to Java for the version 1.2. Finally chapter 13 lists important Web sites
for Java, JavaScript and HTML.
The level of presentation is such that one can study the subject early on in ones
education in programming. There is a balance between practical programming and
the underlying language. The book is ideally suited for use in lectures on Java and
object-oriented programming. The beginner will also benefit from the book. The
reference list gives a collection of textbooks useful in the study of the computer
language Java. There are a number of good textbooks for Java available [1], [2].
For applications of Java in science we refer to W.-H. Steeb et al [6] and Steeb [5].
Comprehensive introductions into JavaScript are given by [3] and [4].
vi
Without doubt, this book can be extended. If you have comments or suggestions,
we would be pleased to have them. The email addresses of the author are:
whsteeb@uj.ac.za
steebwilli@gmail.com
http://issc.uj.ac.za
vii
Chapter 1
Introduction
All these points have contributed to Java being the fastest growing computer lan-
guage for nearly all computer and operating systems and for nearly all software
applications, ranging from scientific to administrative programs to real-time indus-
trial applications and computer games.
1
2 CHAPTER 1. INTRODUCTION
The class is the foundation of Java’s support for object-oriented programming, and
is at the core of many of its advanced features. The class provides the mechanism
by which objects are created. Thus a class defines a new data type, which can be
used to create objects. A class is created by using the keyword class.
2. Polymorphism
3. Inheritance
1.2.2 Inheritance
Often one object shares a number of characteristics with another, but has a few
additional attributes. For example, our firm might have a database for vehicles.
For each vehicle the registration number, model, year and maintenance history are
stored. Suppose the firm wants to expand this data base to include its trucks.
However, they want to store additional information for trucks, such as the the pay-
load and the number of axes (for toll-road purposes). Instead of rewriting all the
code for trucks, one can see a truck as a special case of a vehicle having all the
attributes of a vehicle plus a few additional attributes. By making truck a derived
class of vehicle, it inherits all the attributes of vehicle and the programmer has only
to add the code for the additional attributes. This not only reduces the amount of
coding to be done and maintained, but it also ensures a higher level of consistency.
Should the country decide to change its format for number plates, it has to be only
changed in the base class vehicle and the trucks automatically inherit the change.
In Java a superclass is the parent of a class. The keyword is super. It is the class
from which the current class inherits. In Java, a class can have only one superclass.
Thus Java is a single inheritance system, in which a class can only inhert from one
class. C++ is a multiple inheritance system in which a class can inherit from one
or more classes.
4 CHAPTER 1. INTRODUCTION
1.2.3 Polymorphism
Often one wants to perform an action such as editing on a number of different
objects (i.e. text files, pixel files, charts, etc.). Polymorphism allows one to specify
an abstract operation like editing, leaving the actual way in which this operation
is performed to a later stage. In the case where dynamic binding (linking during
run-time) is used the decision of which code to be used for the editing operation is
only made during run-time. This is especially useful in the case where the actual
type of object which is to be edited is only known at run-time.
Furthermore, if a new object type is to be supported (e.g. faxes) then the new
editing code (provided by the fax-software supplier) can be linked in at run-time.
Even when the original program is not recompiled, it can support future additions
to the system. Polymorphism is hence again a higher level of abstraction, allowing
the programmer to specify an abstract action to be performed on abstract objects.
Java allows defining abstract classes.
The String class does all the string manipulations such as length() to find the
length of a string and charAt(int) which finds the character at the given position.
The System class includes the method exit(). The Graphics class includes all
drawing methods, for example drawLine(int,int,int,int) which draws a line
between to points given by the arguments. The class Object is the mother of all
classes. The Vector is a container class. Mathematical operations are in the class
Math.
import java.applet.Applet;
is used.
1.2. AIM OF OBJECT-ORIENTED PROGRAMMING 5
no pointers,
no references,
no structs,
no unions,
no typedefs,
no #define,
no core dumps,
no sizeof operator.
The size of the basic data types in Java are fixed. C++ has signed and unsigned
data types for short, int and long. Java has no unsigned data basic data type.
All integer basic data types are signed. There are no standalone methods in Java.
Everything in Java must be in a class even the main method. In Java basic data
types can only be passed by value. Arrays are passed by reference. Operators such
as +, * cannot be overloaded in Java. Java does not allow function or class templates.
Java has a boolean data type called boolean. Only newer C++ compilers have a
boolean data type called bool. There is no multiple inheritance in Java. There is
no scope resolution operator :: in Java. Java uses the dot . (access operator) for
everything. There are no global functions or global data in Java. If we want the
equivalent of globals, we use static methods and static data within a class. Java
does not have the C++ concept of a destructor, a method that is automatically
called when an object is destroyed. The reason is that in Java the practice is simply
to forget about objects rather than to destroy them, allowing the garbage collector
to reclaim the memory as necessary. Java has both kinds of comments like C++
does.
6 CHAPTER 1. INTRODUCTION
x X _x x1 myClass
x! 1X true #x1
The identifier true is invalid because it is a reserved word. Since Java is case
sensitive we could use True as an identifier.
where
describe the basic (primitive) data types. The keyword class indicates an abstract
data type, for example
class Rational
Chapter 2
Java Basics
The file name is First.java. The extension of a Java program file is .java. To
compile the code from the command line we enter
javac First.java
First.class
java First
This command is also case-sensitive. Both javac and java are execute files in the
bin directory.
7
8 CHAPTER 2. JAVA BASICS
In a Java program the name of the file with extension java must be the same as the
name of the class which contains the main method. In the program given above the
file name is First.java and the class name which contains main is First. Java is
case sensitive. The keyword class is there because everything in a Java program
lives inside a class. Following the keyword class is the name of the class. The com-
piled byte code is then automatically called First.class (platform independent).
We have declared the class First public so that it is publicly accessible.
{ ... }
are used to delineate the parts (usually called blocks) in the program. A Pascal
programmmer can relate them to the begin/end pair.
Every Java program must have a main method within a class for our code to compile.
The method main is declared static. A static member method of a class can be
invoked independently of any class instance. Instances of classes are called objects.
A public class is defined within its own file and is visible everywhere. The main
method must also be declared public. The main method returns void which is
Java’s way for specifying nothing. The main method has as argument an array of
strings. Arrays are denoted in Java by a pair of square brackets []. The name of the
array of strings is args. This array will hold any command line parameters passed
to our application.
// ....
/* ... */
The System class contains several useful class fields and methods. The method
void println(String s)
is in class PrintStream and prints a string and terminates the line. The method
void print(String s)
// Welcome.java
import java.applet.Applet;
import java.awt.Graphics;
javac Welcome.java
Welcome.class
<HTML>
<COMMENT> file name: Welcome.html </COMMENT>
<APPLET CODE="Welcome.class" width=275 height=135>
</APPLET>
</HTML>
appletviewer Welcome.html
10 CHAPTER 2. JAVA BASICS
The command is provided with Java’s Developer’s Kit. This means appletviewer
is an execute-file in the directory jdk1.4\bin. The program displays the messages
Welcome to JAVA
Welcome to ISSC
on the screen at the coordinates 25 and 25 and 50 and 50, respectively. Coordinates
are measured from the upper-left corner of the applet in pixels. A pixel (picture
element) is the unit of display for the computer screen. Many computers have 640
pixels for the width of the screen and 480 pixels for the height of the screen.
The program contains the definition for the method (member function)
This method is in the class Component. The paint method is called automatically
during an applet’s execution and is used to display information on the screen. The
paint method’s parameter list indicates that it requires a Graphics object (that is
named g in our program) to perform its task. The keyword public is required so
the browser can automatically call the paint method.
The left brace { begins the method definition’s body. A corresponding right brace
} must end the method definition’s body.
The line
g.drawString("Welcome to JAVA",25,25);
to draw the text given by the specified string using this graphics context’s current
font and color. Thus the method drawString is provided in the Graphics class.
The scope of an identifier is the portion in which the identifier can be referenced.
For example, when we declare a local variable in a block, it can be referenced only
in that block or in the blocks nested within that block. The scopes for an identifier
are class scope and block scope. Block begins are indicated by the left brace { and
the block end by the right brace }. An exception from this rule are static methods.
In a sense, all instance variables and methods of a class are global to the methods
of the class in which they are defined, i.e. the methods can modify the instance
variables directly and invoke other methods of the class.
2.3. BASIC DATA TYPES 11
The operator
(type)
byte a = (byte) 7;
int i = (int) a;
to
byte l = j + k;
c = (short)(a + b);
to
c = a + b;
// Types1.java
// Arithmetic operations:
// addition +, subtraction -
short a = (short) 8;
short b = (short) -17;
short c;
c = (short)(a + b);
System.out.println(c); // => -9
int d = -2000000;
int e = 2000001;
int f = d + e;
System.out.println(f); // => 1
byte g = -5;
int h = (int) g;
System.out.println(h); // => -5
long p = 900000000000002L;
long q = 100000000000003L;
long s = p - q;
System.out.println(s); // => 799999999999999
}
}
2.3. BASIC DATA TYPES 13
double u = 20.1E+10;
double v = 17.157;
double w = u*v;
System.out.println(w); // => 3.448557e+12
// type conversion
double x = -10.345;
int nx = (int) x; // type conversion
System.out.println(nx); // => -10
int i = 10;
int j = 3;
double y = 10/3; // integer division on right-hand side,
// then type conversion to double
System.out.println(y); // => 3.0
double b = ((double) i)/((double) j);
System.out.println(b); // => 3.3333333333333335
}
}
14 CHAPTER 2. JAVA BASICS
The char type uses single quotes to denote a character. For example
char ch = ’A’;
The size of of data type char is 2 bytes compared to 1 byte for a character in
C and C++. The char type denotes character in the Unicode encoding scheme.
Unicode was designed to handle essentially all characters in all written languages in
the world. It is a 2-byte code. This allows 65536 characters, unlike ASCII/ANSI,
which is a 1-byte code allowing only 255 characters. The ASCII/ANSI code is a
subset of Unicode. It is the first 255 characters on the Unicode coding scheme. For
example
The boolean data type has two values: false and true. It is used for logical
testing using the relational operators that Java, like C and C++, supports. Type
conversion from boolean to byte, short, int, long is not possible. The storage
requirement for the boolean data type is 1 byte.
Basic data types in Java, C, and C++ are compared for equality using the equality
operator
==
For example
char c1 = ’X’;
char c2 = ’x’;
boolean b = (c1 == c2);
System.out.println(b); // => false (Java is case sensitive)
A string is an array of characters. The data type String is an abstract data type
in Java. Strings in Java are immutable. They cannot be changed. We have two
methods to create a string, namely
String s1 = "abc";
String s2 = new String("abc");
The equals method provided in the String class compares two strings (case sen-
sitive) for equality. The method returns true if the objects are equal and false
otherwise. The method equals uses a lexicographical comparsion the integer Uni-
code values that represent each character in each String are compared. Thus the
method equals is case sensitive.
2.3. BASIC DATA TYPES 15
// Types3.java
int r2;
char ch3 = ’A’; char ch4 = ’A’;
if(ch3 == ch4) r2 = 0;
else r2 = 1;
System.out.println(r2); // => 0
int x = 7; int y = 8;
boolean bool = true;
if(x == y) System.out.println(bool);
else
System.out.println(!bool); // => false
String d1 = "Cape";
String d2 = "cup";
boolean b2 = d1.equals(d2);
System.out.println(b2); // => false
+, -, *, /, %, ++, --
where % is the remainder operator (also called modulus operator). For example
23%7 = 2, since 23/7 = 3 in integer division and the remainder is 2. The operators
++ and -- are the increment and decrement operators, respectively. We have a
preincrement operator ++i and a postincrement operator i++ and analogously for
the decrement operator. The combined operators are
a += b;
is equivalent to
a = a + b;
The support for constants in Java is not as mature as that provided by C++. In Java
one can define constant data members of a class. The keyword used for constants
is final. For example
// Arith.java
int d = 23;
int e = -25;
int f = d - e;
System.out.println(f); // => 48
int dd = 5;
dd++; // increment operator
System.out.println(dd); // => 6
2.4. ARITHMETIC OPERATIONS 17
int xx = -17;
xx--; // decrement operator
System.out.println(xx); // => -18
short k = (short) 5;
short j = (short) 7;
short l = (short) (k*j);
System.out.println(l); // => 35
long n = 3000000001L;
long m = 2L;
long result = n/m; // integer division
System.out.println(result); // => 1500000000
int x = 7;
x += -9; // short cut for x = x - 9;
System.out.println(x); // => -2
double z1 = 1.0;
double z2 = 3.0;
// floating point division
double z3 = z1/z2;
System.out.println("z3 = " + z3); // => 0.333333...
double d1 = 3.14159;
double d2 = 2.1;
d1 /= d2; // short cut for d1 = d1/d2;
System.out.println(d1); // => 1.4959952...
int u = 27;
int v = 12;
u %= v; // short cut for u = u%v;
System.out.println(u); // => 3
}
}
18 CHAPTER 2. JAVA BASICS
// Unicode.java
char a = (char) 3;
System.out.println(a);
In the following program we show how to display degree Fahrenheit, degree Celsius,
infinity (hex 221E) and the Euro (hex 20AC).
// UniCode.java
import java.awt.*;
import java.awt.event.*;
UniCode(String s)
{
super(s);
setSize(200,200);
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent event)
{ System.exit(0); }});
setLayout(new FlowLayout());
label1 = new Label(" ");
label1.setFont(new Font("TimesRoman 12 point bold.",20,20));
add(label1);
label2 = new Label(" ");
label2.setFont(new Font("TimesRoman 12 point bold.",20,20));
add(label2);
label3 = new Label(" ");
label3.setFont(new Font("TimesRoman 12 point bold.",20,20));
add(label3);
label4 = new Label(" ");
label4.setFont(new Font("TimesRoman 12 point bold.",20,20));
add(label4);
label1.setText("\u00B0F");
label2.setText("\u00B0C");
label3.setText("\u221E");
label4.setText("\u20AC");
setVisible(true);
}
int a = 5;
int b = 6;
int c = -1;
int r = a*b + c; // => 29
int s = a*(b + c); // => 25
contains three operations, namely =, *, +. After the precedence table the multi-
plication operators is applied first, then the addition operator and finally the as-
signment. Thus r takes the value 29. In the expression a*(b+c) we first evaluate
b+c and then multiply with a. Thus the output for s is 25.
The access operator . is higher in the precedence table than the multiplication
operator.
int m = 27;
int n = 8;
int p = 5;
Fill in the output for the following program. Then run the program and compare.
int b = 5, c = 7;
int r1 = c*b++;
System.out.println(r1); // =>
System.out.println(b); // =>
int d = 5, e = 7;
int r2 = d*(e++);
System.out.println(r2); // =>
int f = 5, g = 7;
int r3 = f*++g;
System.out.println(r3); // =>
int n = 23;
int m = 5;
int s1 = n/m;
System.out.println(s1); // =>
int s2 = n%m;
System.out.println(s2); // =>
int p = 3;
int s3 = n/m%p;
System.out.println(s3); // =>
int i = 12;
int j = 12;
System.out.println(i++); // =>
System.out.println(++j); // =>
}
}
22 CHAPTER 2. JAVA BASICS
2.7 Arrays
An array is a set of elements with the same data type. The first subscript of a
Java, C and C++ array is 0 and the last subscript is 1 less than the number used to
declare the array. Thus an array is a contiguous region of storage, large enough to
hold all its elements. The elements in the array are accessed using the rectangular
bracket [].
allocates memory for four integer variables, initializes these memory positions for
the integer values. The length of an array of basic data types or abstract data types
can be found with the length command. For example
int l = vec.length;
System.out.println(l); // => 4
We can also use the new operator to allocate memory for the array and then assign
the values. Any valid data type can be allocated using new. For example
To access array elements one uses the index notation and the rectangular bracket
[]. For example
The class Arrays can be used to do operations on arrays of basic data types, for
example
// Marray.java
// one-dimensional arrays
int sum = 0;
for(int i=0;i<intnumbers.length;i++)
{
sum += intnumbers[i];
}
System.out.println(sum);
// Histogram.java
// Histogram printing program
import java.awt.Graphics;
import java.applet.Applet;
g.drawString("Element",24,yPosition);
g.drawString("Value",100,yPosition);
g.drawString("Histogram",175,yPosition);
for(int i=0;i<n.length;i++)
{
yPosition += 15;
g.drawString(String.valueOf(i),25,yPosition);
g.drawString(String.valueOf(n[i]),100,yPosition);
xPosition = 175;
for(int j=1;j<=n[i];j++)
{
g.drawString("*",xPosition,yPosition);
xPosition += 7;
} // end for loop j
} // end for loop i
} // end paint
}
2.7. ARRAYS 25
// Matrix.java
// two-dimensional arrays
int trace = 0;
trace = mat[0][0] + mat[1][1];
System.out.println(trace);
// ThreeArr.java
// three dimensional arrays
int sum = 0;
int i, j, k;
for(i=0;i<=1;i++)
for(j=0;j<=1;j++)
for(k=0;k<=1;k++)
{
sum += three[i][j][k];
}
System.out.println(sum);
int array[][][] =
{{{ -1, 1 }, { -9, 11 }}, {{ 2, -7 }, { 20, 8 }}};
int result = 0;
for(i=0;i<=1;i++)
for(j=0;j<=1;j++)
for(k=0;k<=1;k++)
{
result += array[i][j][k];
}
System.out.println(result);
}
}
// In C++ the new operator
// must be applied three times
// to allocate the memory.
2.7. ARRAYS 27
Arrays of basic data types in Java are classes. This means the array identifier is
actually a handle to a true object that is created on the heap. The heap object can
be created either implicitly, as part of the array initialization syntax, or explicitly
with a new expression.
The following two programs demonstrate this behaviour. In the first program we
override the method
from the Object class to make a copy of the array. Overriding occurs when a method
is defined in a class and also in one of its subclasses.
Class Object is the root of the class hierarchy. Every class has Object as a super-
class. All objects, including arrays, implement the methods of this class.
In the second program we show how assignment of two arrays works. Assignment
of two arrays can be very dangerous as the output of the program shows.
// ArrClone.java
for(int i=0;i<vecClone.length;i++)
System.out.println(vecClone[i]);
}
}
28 CHAPTER 2. JAVA BASICS
// ArrAssign.java
y = x;
int i;
for(i=0;i<y.length;i++)
{
System.out.println("y[" + i + "] = " + y[i]);
}
x[0] = -17.4;
for(i=0;i<y.length;i++)
{
System.out.println("y[" + i + "] = " + y[i]);
}
}
}
// output
// y[0] = 2.2 y[1] = 4.5 y[2] = 3.1
// y[0] = -17.4 y[1] = 4.5 y[3] = 3.1
2.8. CONTROL STATEMENTS 29
== equal to
!= not equal to
For example
int x = 234567;
int y = 234568;
if(x == y) ...
boolean b1 = false;
boolean b2 = true;
if(b1 != b2) ...
To compare strings the operator == should not be used instead we have to use the
methods equals().
class Mif
{
public static void main(String[] args)
{
int x = -5;
if(x != 0)
System.out.println("value is nonzero"); // => value is nonzero
int y = 7;
if(y > 0)
System.out.println("positive");
else System.out.println("negative"); // => positive
while(cond-exp) t-st
The loop statement, t-st, will be executed repeatedly until the conditional expres-
sion, cond-exp, compares to zero (false). The cond-exp is evaluated and tested first.
If this value is nonzero (true), t-st, is executed. If no jump statements that exit
from the loop is encountered, cond-exp is evaluated again. This cycle repeats until
cond-exp is zero.
The while loop offers a concise method for scanning strings (end of string indicate
by the null character ’\0’) and other null-terminated data structures.
do do-st while(cond-exp);
The do-st statement is executed repeatedly until cond-exp compares equal to zero
(false). The main difference from the while statement is that cond-exp is tested
after, rather than before, each execution of the loop statement. At least one execu-
tion of do-st is assured.
for(<init-exp>;<test-exp>;<increment-exp>) statement
One can break out of a block of statements (typically an iterative block) using Java’s
break statement. This is usually not the preferred method and should only be used
if other methods are excessively cumbersome.
32 CHAPTER 2. JAVA BASICS
The while loop is the most general loop and can be used to replace the other two;
in other words, a while loop is all we need, and the others are just there for our
convenience.
// Loops.java
// for loop, while loop, do-while loop
// we apply the for-loop, while-loop and do-while-loop
// to find the sum 1 + 2 + 3 + ... + 9 + 10
class Loops
{
public static void main(String[] args)
{
int n = 10;
int s1 = 0;
int j;
for(j=1;j<=n;j++)
{
s1 = s1 + j; // can also be written as s1 += j;
}
System.out.println(s1); //=> 55
int i = 0;
int s2 = 0;
while(i <= n)
{
s2 = s2 + i;
i++;
}
System.out.println(s2); // => 55
int k = 0;
int s3 = 0;
do
{
s3 += k;
k++;
} while(k <= n);
System.out.println(s3); // => 55
}
}
2.8. CONTROL STATEMENTS 33
In the following program we use three for loops to generate all combinations for
three capital letters, i.e.
There are
26 × 26 × 26 = 17576
combinations. We compare them to a given string consisting of three capital letters.
If the string is found we display it. The method equals() in the String class is
used.
// Password.java
A polygon is a closed plane figure with n sides. If all sides and angles are equivalent
the polygon is called regular. The area of a planar convex polygon with vertices
1 n−1
X
A= (xi yi+1 − xi+1 yi ), xn ≡ x0 , yn ≡ y0
2 i=0
The following program finds the area of a given planar convex polygon. The polygon
in the program is the unit square. We apply the modulus operator % to identify n
and 0.
// Polygon.java
for(int i=0;i<x.length;i++)
{
area += (x[i]*y[(i+1)%length] - x[(i+1)%length]*y[i]);
}
area = 0.5*area;
Thus if one has a large decision tree and all the decisions depend on the value
of the same variable we use a switch statement instead of a series of if ... else
constructions. The switch statement transfers control to one of several case-labeled
statements, depending on the value of the switch expression. Note that if the break
is omitted, execution will continue over the remaining statements in the switch
block. The break statement can also be used to break out of an iteration loop.
switch(sw-expression) case-st
case const-exp-i:case-st-i
default:default-st
The program illustrates the syntax of the Java selection statement switch.
36 CHAPTER 2. JAVA BASICS
// SwitchT.java
import java.awt.*;
import java.io.DataInputStream;
import java.io.IOException;
class SwitchT
{
public static void main(String[] args) throws IOException
{
System.out.println("enter character: ");
// The command
// char c = s.readChar();
// will not properly work.
// It always gives the output
// you did not enter ’a’ or ’b’. Explain why !
System.out.println(c);
switch(c)
{
case ’a’:
System.out.println("you entered ’a’ ");
break;
case ’b’:
System.out.println("you entered ’b’ ");
break;
default:
System.out.println("you did not enter ’a’ or ’b’ ");
break;
}
}
}
2.8. CONTROL STATEMENTS 37
The method char charAt(int) is in the String class and returns the charac-
ter at the position specified in the argument counting from zero. The method
int length() is in the String class and finds the length of a string.
// MSwitch.java
for(int i=0;i<s.length();i++)
{
char c = s.charAt(i);
System.out.print("i = " + i);
switch(c)
{
case ’a’: System.out.println("character is ’a’ ");
break;
case ’b’: System.out.println("character is ’b’ ");
break;
default: System.out.println("character is not ’a’ or ’b’ ");
break;
}
}
for(int j=0;j<array.length;j++)
{
switch(array[j])
{
case 1: System.out.println("number is 1");
break;
case 3: System.out.println("number is 3");
break;
default: System.out.println("number is not 1 or 3");
break;
}
}
}
}
38 CHAPTER 2. JAVA BASICS
The logical operators work with logical values (true and false) allowing us to
combine relational expressions. In Java the logical operators always produce a result
of either false or true. In C and C++ we have 0 and 1. The logical operators &&
and || are short circuit. Suppose that we have the expression
If exp1 is false, then the entire expression is false, so exp2 will never be evaluated.
Likewise given the expression
exp1 || exp2
int x = -5;
int y = 7;
boolean result = ((x > 0) && (y > 0));
System.out.println(result); // => false
The first expression is false thus the second expression is not evaluated.
Warning. Look out for the operator precedence. For example the relational op-
erators ( < > ==) have higher precedence than the logical AND operator. Note
that
if(!n)
is equivalent to
if(n==0)
The logical operators should not be confused with the bitwise operators &, |, ~. In
Java, C and C++ the bitwise AND operator is &, the bitwise OR operator is |, and
the bitwise NOT is ~.
2.9. LOGICAL AND, LOGICAL OR AND LOGICAL NOT 39
// Logic.java
int b = 7;
if((b > 0) || (b%2 == 0))
System.out.println("number is positive or even");
char d = ’A’;
char e = ’B’;
char f = ’C’;
if((d != e) && (d != f) && (e != f))
System.out.println("characters are different");
int c = 1;
if(!(c == 0))
System.out.println("number is nonzero");
14 = 1 · 23 + 1 · 22 + 1 · 21 + 0 · 20 .
Thus in binary we can express 14 (base 10) as bitstring 1110. If 14 is of type int (4
bytes = 32 bits) the binary representation is 00000000000000000000000000001110.
The bitwise operations are as follows.
bitwise inclusive OR |
1 1 => 1
1 0 => 1
0 1 => 1
0 0 => 0
As an example consider the two (decimal) numbers 14 and 9 of data type int, i.e.
the size is 4 bytes (32 bits). In binary 9 is given by 1001. Thus the bitwise AND of
these integers is
All modern CPU’s use the two complement to find the negative number of a given
integer number, for example 23 -> -23 and -14 -> 14. The two complement con-
sists of the one complement ~ and then adding a 1 to the least significant bit.
// Bitwise.java
// Shift.java
int r3 = 3; // binary 11
int r4 = (r3 << 3);
System.out.println(r4); // => binary 11000 = decimal 24 = 3*8
// shift by 3 is multiplication by 8 = 2^3
The following program we pass two integers to the function swap. Obviously no
swapping of the two numbers takes place since we pass by value.
// Refer.java
class Refer
{
public static void swap(int x,int y)
{
int temp;
temp = x; x = y; y = temp;
}
swap(x,y);
System.out.println(x); // => 7
System.out.println(y); // => 3
}
}
44 CHAPTER 2. JAVA BASICS
// Trick.java
// swapping two integers
// arrays passed by reference
swap(x,y);
System.out.println("after swapping");
System.out.println("x[0] = " + x[0]); // => 3
System.out.println("y[0] = " + y[0]); // => 7
}
}
where ^ is the bitwise XOR operation. This avoids the introduction of the temporary
(local) variable temp.
2.12. PASS BY VALUE, PASS BY REFERENCE 45
// Shell.java
class Shell
{
public static void sort(int[] a) // can the public be omitted ?
{
int n = a.length; // finds length of array
int incr = n/2;
while(incr >= 1)
{
for(int i=incr;i<n;i++)
{
int temp = a[i];
int j = i;
while((j >= incr) && (temp < a[j-incr]))
{
a[j] = a[j-incr];
j -= incr;
}
a[j] = temp;
}
incr /= 2; // short cut for: incr = incr/2;
}
}
int i;
// fill the array with random numbers
for(i=0;i<a.length;i++)
a[i] = (int)(Math.random()*100);
Java passes everything by value. When we are passing basic data types into a
method, we get a distinct copy of the basic data type. When we are passing a handle
into a method, we get a copy of the handle. In other words Java manipulates objects
by reference, but it passes object references to methods by value. The following
program demonstrates this.
// PassString.java
surprise(str1,str2,str3,str4);
In the following program the calling method and the called method have an object
in common, and both methods can change the object. The object reference arg1
is passed by value. Then a copy of it is made into the stack frame for the method
inverse(). But both the original and the copy are object references, and they point
to a common object in memory that can be modified.
// Reference.java
class Help
{
public double y;
public Help(double y)
{
this.y = y;
}
class Reference
{
static void inverse(Help arg1)
{
arg1.y = -arg1.y;
}
2.13 Recursion
Recursion plays a central role in computer science. A recursive function is one whose
definition includes a call to itself. More generally, a recursive method is a method
that calls itself either directly or indirectly through another method. A recursion
needs a stopping condition. Of course, it is not allowed to use the main function in
a recursive call. Java, C and C++ allow recursion.
We consider three examples. In the first example we show how the factorial function
can be implemented using recursion. The second example shows an implementation
the recursively display of elements of an array. In the third example the Fibonacci
numbers are calculated using recursion.
// Recur.java
class Recur
{
public static long fac(long n)
{
if(n > 1L)
return n*fac(n-1L);
else
return 1L;
}
import java.awt.*;
import java.applet.Applet;
<HTML>
<APPLET code="RDisplay.class" width=275 height=150>
</APPLET>
</HTML>
50 CHAPTER 2. JAVA BASICS
xt+2 = xt+1 + xt
where t = 0, 1, 2, . . . and x0 = 0, x1 = 1. We find
x2 = 1, x3 = 2, x4 = 3, x5 = 5, x6 = 8, . . .
Thus we can apply recursion to obtain the Fibonacci numbers. It is left as an
exercise to rewrite the program using iteration.
// Fibo.java
However goto cannot be used in Java. A break statement can be used only inside
an iteration (while, do-while and for loops) or switch statement. It terminates
the iteration or switch statement. Since iteration and switch statements can be
intermixed and nested to any depth, we have to take care that the break exits from
the correct loop or switch. The rule is that a break terminates the nearest enclosing
iteration or switch statement.
continue
Java lacks a goto statement, although there is a keyword goto. In C and C++ the
syntax for the goto statement is
goto Label
The goto statement transfers control to the statement labeled Label, which must
be in the same function. One good use for the goto is to exit from a deeply nested
routine. A simple break statement would not work here, because it would only
cause the program to exit from the innermost loop. In Java nested do-while loops
can replace the goto’s. The following programs one in C++ using goto’s and one
in Java using do-while demonstrate this.
Unless the function return type is void, a function body must contain at least one
return statement with the following format
return return-expression;
// didact.cpp
// C++ program using goto
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
int main()
{
time_t t;
srand((unsigned long) time(&t)); // seed
L3:
int a = rand()%100;
int b = rand()%100;
int result;
L1:
cout << a << " + " << b << " = ";
cin >> result;
if(result == (a+b))
goto L2;
cout << "sorry you are not correct: try again" << endl;
goto L1;
L2:
cout << "congratulations you are correct" << endl;
char c;
cout << "Do you want to add again: Press y for yes and n for no: ";
cin >> c;
return 0;
}
2.14. JUMP STATEMENTS 53
import java.io.*;
class Gotorau
{
public static void main(String[] args) throws IOException
{
BufferedReader kbd;
kbd = new BufferedReader(new InputStreamReader(System.in));
String input;
do
{
int a = randomInt(0,99); int b = randomInt(0,99);
int r;
do
{
if(b < 0)
System.out.print(a + " " + b + " = ");
else
System.out.print(a + " + " + b + " = ");
r = Integer.parseInt(kbd.readLine());
if(r != (a + b))
System.out.println("try again!");
} while(r != (a + b));
System.out.println("Congratulations: correct.");
System.out.println("Do you want to add again ? (y/n) ");
input = kbd.readLine();
} while(input.equals("y"));
} // end main
BufferedReader(Reader in)
creates a buffering character-input stream that uses a default-size input buffer. The
method
String readLine()
// Readin1.java
import java.io.*;
class Readin1
{
public static void main(String[] args) throws IOException
{
System.out.print("Enter the first integer = ");
BufferedReader kbd =
new BufferedReader(new InputStreamReader(System.in));
String str1 = kbd.readLine();
int sum = a + b;
In the following example we read in a string from the keyboard and then convert it
to a double.
// Readin2.java
import java.io.*;
class Readin2
{
public static void main(String[] args) throws IOException
{
System.out.print("Calculating Square root of a = ");
BufferedReader kbd =
new BufferedReader(new InputStreamReader(System.in));
String str = kbd.readLine();
do
{
xold = xnew;
xnew = (xold + a/xold)/2.0;
System.out.println(xnew);
}
while(Math.abs(xnew-xold) > 1E-4);
}
}
The method abs is a method in class Math. It finds the absolute value of a double.
What happens if we enter a negative number?
56 CHAPTER 2. JAVA BASICS
javac MCommand.java
where
// MCommand.java
String t1 = argv[0];
String t2 = argv[1];
String t3 = argv[2];
String t = t1.concat(t2.concat(t3));
System.out.println("t = " + t); // => GoodMorningEgoli
String s = s1.concat(s2.concat(s3));
System.out.println("s = " + s); // => GoodMorningEgoli
}
}
2.17. SYSTEM CLASS 57
which terminates the currently running Java Virtual Machine and the method
long currentTimeMillis()
which returns the current time in milliseconds between the current time and mid-
night, January 1, 1970 UTC.
Furthermore the class provides standard input, standard output, and error output
streams. The fields are
static PrintStream in
A utility method for quickly copying a portion of an array is also provided. The
method
copies an array from the specified source array, beginning at the specified position,
to the specified position of the destination array.
The method
// MySystem.java
import java.util.Properties;
System.out.println(System.getProperty("java.class.path"));
System.out.println(System.getProperty("os.arch"));
System.out.println(System.getProperty("user.name"));
System.out.println(System.getProperty("java.version"));
int[] a = { 7, 6, 5, 4, 3, 2, 1, 0, 1, 2 };
int[] b = new int[a.length];
System.arraycopy(a,0,b,1,a.length-1);
for(int k=0;k<a.length;k++)
System.out.println(b[k]); // => 0 7 6 5 4 3 2 1 0 1
The method String getProperty(String) can be used to find the name of the
underlying operating system. The path in different operating systems is different.
Thus we can use this information to select the operating system in use.
// NoOfLines.java
import java.io.*;
import java.util.*;
if(s.equals("Windows 98"))
{
fstring = "c:\\books/db/data.dat";
}
if(s.equals("Linux"))
{
fstring = "/root/javacourse/data.dat";
}
int count = 0;
while(in.readLine() != null)
{
count++;
}
System.out.println("count = " + count);
} // end main
}
60 CHAPTER 2. JAVA BASICS
which gets the systems security interface. If a security manager has already been
established for the current application, then that security manager is returned; oth-
erwise null is returned. The security manager is an abstract class that allows
applications to implement a security policy. It allows an application to determine,
before performing a possibly unsafe or sensitive operation, what the operation is
and whether the operation is being performed by a class created via a class loader
rather than installed locally. Classes loaded via a class loader (especially if they
have been downloaded over a network) may be less trustworthy than classes from
files installed locally. The application can allow or disallow the operation.
// Security.java
2.18 Assertions
Assertions are a new feature in Java 1.4. An assertion is a program statement con-
taining a boolean expression, that a programmer believes to be true at the time the
statement is executed. Thus the new keyword assert is introduced and support in
the library java.lang.AssertionError. The following program gives an example.
We compile with
// Parameters.java
import java.awt.*;
import java.applet.*;
<HTML>
<APPLET CODE="Parameters.class" width=275 height=135>
<PARAM NAME="parameter1" VALUE="Egoli">
<PARAM NAME="parameter2" VALUE="17">
<PARAM NAME="parameter3" VALUE="-5">
</APPLET>
</HTML>
Chapter 3
String Manipulations
String s1 = "abcdef";
String s2 = new String("abcdef");
In the second method we use the constructor in the String class. Since String
objects are immutable they can be shared. We demonstrate the use of the following
methods
The method length() finds the length of this string. The method
returns a hashcode for this string. This is a large number of the character values in
the string.
64
3.1. STRING CLASS 65
// Mstring.java
char c;
c = city.charAt(2);
System.out.println(c); // => o
// array of Strings
String keys[] = { "Red", "Green", "Blue" };
System.out.println(keys[1]); // => Green
Next we discuss how to convert strings to numbers (integer type or floating point
type) and numbers to strings. This technique is important when we read in a number
from the keyboard as a string. The abstract class Number is the superclass of the
wrapper classes
These subclasses of class Number must provide methods to convert the represented
numeric value to byte, short, int, long, float and double.
returns a new Integer object initialized to that value. The method throws an
exception if the String cannot be parsed as an int. The radix is assumed to be 10.
The method
returns the value of this Integer as an int. It overrides intValue() in class Number.
Analogously we can consider the methods
floatValue(), doubleValue()
The method
in class Integer returns a new String object representing the specified integer. The
radix is assumed to be 10. Analogously we have the method
All these classes have the data fields MAX_VALUE and MIN_VALUE. For example, for
the class Double MAX_VALUE is the largest positive finite value of type double.
68 CHAPTER 3. STRING MANIPULATIONS
// Convert.java
class Convert
{
public static void main(String[] args)
{
String str;
str = "25";
int i = Integer.valueOf(str).intValue();
System.out.println(" i = " + i); // => 25
str = "25.6";
float f = Float.valueOf(str).floatValue();
System.out.println(f); // => 25.6
double d = Double.valueOf(str).doubleValue();
System.out.println(d); // => 25.6
String m;
double j = 1234.7;
m = Double.toString(j);
System.out.println(m); // => 1234.7
int k = 3412;
String n = new String("000000000000000");
n = Integer.toString(k);
System.out.println(n); // => 3412
String name;
name = "Olli";
int x = Integer.valueOf(name).intValue();
System.out.println(x); // => NumberFormatException
}
}
3.2. STRINGTOKENIZER CLASS 69
The constructor
constructs a string tokenizer for a specified string. The tokenizer uses the default
delimiter set, which is
" \t\n\r\f"
the space character, the tab character, the newline character, the carrige-return
character, and the form-feed character.
The constructor
constructs a string tokenizer for a specified string. The characters in the delim
arguments are the delimiters for separating tokens. Delimiter characters themselves
will not be treated as tokens.
The method
returns the next token in this string tokenizer’s string. The method
boolean hasMoreTokens()
tests if there are more token available from the tokenizer’s string. The method
int countTokens()
calculates the number of times that this tokenizer’s nextToken() method can be
called before it generates an exception.
70 CHAPTER 3. STRING MANIPULATIONS
The next program shows how the StringTokenizer class can be applied.
// Tokenizer.java
import java.util.*;
String s = tok.nextToken();
System.out.println(s); // => Egoli
s = tok.nextToken();
System.out.println(s); // => Gauteng
s = tok.nextToken();
System.out.println(s); // => Africa
int i;
for(i=1; i <= 7; i++)
{
v = tok.nextToken();
if(v.equals(name))
{
found = true;
break;
}
} // end for loop
if(found == true)
System.out.println("name in string"); // => name in string
else
System.out.println("name not in string");
3.2. STRINGTOKENIZER CLASS 71
if(in == true)
System.out.println("number in string");
else
System.out.println("number not in string");
} // end main
}
The constructor
// Buffer.java
buf.append("Good Morning");
System.out.println("buf = " + buf);
System.out.println("buf.length() = " + buf.length()); // => 12
System.out.println("buf.capacity() = " + buf.capacity()); // => 20
4.1 Introduction
A Java program is a collection of one or more text files that contains Java classes,
at least one of which is public and contains a method named main() that has this
form
A Java class is a specific category of objects, similar to a Java basic data type (e.g.
int, double). Thus a class is a Java aggregate that may contain methods and types
in addition to data. It can also be a user-defined data type. A service offered by
most classes is that of allowing the user to create instances of the class. These
services are called constructors and have the name of the class, no return value and
any arguments. The default constructor takes no argument. An unfortunate aspect
of Java inherited from C++ is that the compiler writes a default constructor if and
only if no other constructors has been defined for the class. A Java class specifies
the range of the objects of that class can have. Thus a class includes
Constructors
Methods
Fields
The programmmer can add his own classes to the built-in classes.
that can appear in the declaration of classes, fields, local variables, and methods.
73
74 CHAPTER 4. CLASSES AND OBJECTS
Class Modifiers
Modifier Meaning
public It is accessible from all other classes
abstract The class cannot be instantiated
final No subclasses can be declared
Constructor Modifiers
Modifier Meaning
public It is accessible from all classes
protected It is accessible only from within its own class
and its subclasses
private It is accessible only from within its own class
Field Modifiers
Modifier Meaning
public It is accessible from all classes
protected It is accessible only from within its own class
and its subclasses
private It is accessible only from within its own class
static Only one value of the field exists for all instances
of the class
transient It is not part of the persistent state of an object
volatile It may be modified by asynchronous threads
final It must be initialized and cannot be changed
Method Modifiers
Modifier Meaning
public It is accessible from all classes
protected It is accessible only from within its own class
and its subclasses
private It is accessible only from within its own class
and its subclasses
abstract It has no body and belongs to an abstract class
final No subclasses can override it
static It is bound to the class itself instead of an instance
of the class
native Its body is implemented in another programming language
synchronized It must be locked before a thread can invoke it
4.2. WRAPPER CLASSES 75
Elements in these classes are objects. Each type wrapper class enables us to
manipulate basic data types as objects. The Boolean class includes the fields
static Boolean TRUE, static Boolean FALSE, and static Class TYPE (the class
object representing the basic data type boolean).
inherits from the class Number. Each of the type wrappers is declared final, so
their methods are implicitly final and may not be overridden.
// Wrap.java
class Wrap
{
public static void main(String[] args)
{
Integer i = new Integer(5);
Integer j = new Integer(123);
int result = i.intValue() + j.intValue();
Integer k = new Integer(result);
System.out.println("result = " + result); // => 128
System.out.println("k = " + k); // => 128
double x = 3.14;
double y = 2.79;
Double X = new Double(x);
Double Y = new Double(y);
double sum = X.doubleValue() + Y.doubleValue();
System.out.println("sum = " + sum); // => 5.93
}
}
76 CHAPTER 4. CLASSES AND OBJECTS
The Character class wraps a value of the basic data type char in an object. An
object of type Character contains a single field whose type is char. This class
provides several methods for determing the type of a character and converting up-
percase to lowercase and vice versa. First we look at the constructors and methods
in the Character class. The constructor
Character(char)
returns the numeric value of the character digit using the specified radix. The
method
compares this object against the specified object. Thus the class Character over-
rides the equals() method from the Object class. The method
maps the given character to its lowercase equivalent. The class also overrides the
method
String toString()
returns the numeric value of a character digit, using the value specified in an inter-
nal table called the Unicode Attribute Table. For example, \u217c is the Roman
Numeral L, which has the value of 50.
4.2. WRAPPER CLASSES 77
// Charact.java
class Charact
{
public static void main(String[] args)
{
Character k = new Character(’#’);
System.out.println(k); // => #
char c = k.charValue();
System.out.println(c); // => #
char m = ’5’;
Character j = new Character(m);
boolean b1 = j.isDigit(m);
System.out.println(b1); // => true
char n = ’9’;
Character z = new Character(n);
int a = z.digit(n,10);
System.out.println(a); // => 9
boolean b2 = z.equals(j);
System.out.println(b2); // => false
Vector(int intialCapacity)
constructs an empty vector with the specified initial capacity. To insert elements
into the container class we apply the method
adds the specified component to the end of this vector. The method
removes an element and shifts down all elements above it. The method
boolean isEmpty()
// Vec.java
import java.util.*;
class Vec
{
public static void main(String[] args)
{
Vector v = new Vector(5);
v.addElement(x); // position 0
v.addElement(c); // position 1
v.addElement(z); // position 2
v.addElement(n); // position 3
v.addElement(st); // position 4
boolean b = v.isEmpty();
System.out.println(b); // => false
v.removeElementAt(3);
Integer zz = (Integer) v.elementAt(3);
System.out.println(zz); // => -14
v.removeElementAt(4);
String k = new String("New York");
v.addElement(k);
boolean b1 = v.contains(k);
System.out.println(b1); // => true
boolean b2 = v.contains("New York");
System.out.println(b2); // => true
boolean b3 = v.contains("New Year");
System.out.println(b3); // => false
}
}
80 CHAPTER 4. CLASSES AND OBJECTS
for the real numbers 3.14159... and 2.71828..., respectively. The class includes the
overloaded function
The Math class also contains all the standard mathematical functions such as
The data type passed to these functions is double and the return data type is also
double. Furthermore, we have the functions
and
The class also includes a method to generate random number (data type double)
in the interval [0, 1])
// MathClass.java
class MathClass
{
public static void main(String[] args)
{
double g = Math.PI;
System.out.println(" Pi = " + g); // => 3.14159...
double f = Math.cos(g);
System.out.println(f); // => -1.0
int a = -7;
int b = Math.abs(a);
System.out.println(b); // => 7
double c = -8.9;
double d = Math.abs(c);
System.out.println(d); // => 8.9
long i = Math.max(123L,23456789L);
System.out.println(i); // => 23456789
double r1 = Math.random();
System.out.println(r1); // => 0.62872...
double r2 = Math.random();
System.out.println(r2); // => 0.33179...
double j = Math.pow(Math.E,2.0);
System.out.println(" j = " + j); // => 7.38905...
double k = 7.34;
double l = Math.floor(k);
double m = Math.ceil(k);
System.out.println(l); // => 7.0
System.out.println(m); // => 8.0
double n = 5.1;
double p = 2.1;
double q = Math.IEEEremainder(n,p); // => 0.899999999999995
// returns the remainder of n divided by p
// as defined by IEEE 754 => 0.9 (rounding errors)
System.out.println(q);
double v = 2.0;
double z = Math.sqrt(v);
System.out.println(z); // => 1.41...
double r = -2.0;
double s = Math.sqrt(r);
System.out.println(s); // => NaN
}
}
82 CHAPTER 4. CLASSES AND OBJECTS
// MyBitSet.java
bits.set(2); bits.set(5);
System.out.println("bits = " + bits);
} // end main
}
The output is
bits = { }
bits = {2, 5}
address
instructor
4.6. BIGINTEGER AND BIGDECIMAL CLASS 83
BigInteger(String val)
BigInteger b1 = BigInteger.ZERO;
BigInteger b2 = BigInteger.ONE;
BigInteger b3 = b1.add(b2);
The class BigDecimal provides immutable arbitrary precision signed decimal num-
bers. The constructor
BigDecimal(String val)
The following program shows how to use the BigDecimal and BigInteger class.
// MyDecimal.java
import java.math.*;
BigInteger c1 = BigInteger.ZERO;
BigInteger c2 = BigInteger.ONE;
BigInteger c3 = c1.add(c2);
System.out.println(c3); // => 1
BigDecimal d4 = d1.multiply(d2);
System.out.println("d4 = " + d4);
}
}
4.7. OBJECT CLASS 85
are intended to be overriden. Thereby they provide clean and consistent facilities
for duplicating objects and determining when they are the same.
The class Object does not define any data members. It defines only the default
constructor (taking no arguments) and a number of methods. Since all classes are
directly or indirectly derived from Object they all inherit these methods.
The equals() method in the class Object simply checks whether the object itself
and the argument are the same object in the sense they share the same memory
position. The method is very often overriden for more meaningful comparisons. For
example, the String class overides equals() for string comparison.
The clone() method is Java’s copy construtor. It allocates memory for a new
instance of the class and makes an identical copy of the object itself. As it is the
case for the copy constructor in C++, the default behaviour of the clone() method
is to make a byte-for-byte copy of our object. If our object contains other objects,
the class members are actually pointers to these objects and making a byte-by-byte
copy would only copy the pointers and would not create copies of the contained
objects. For this reason the clone() method is declared protected and Java forces
override the clone() method.
The toString() method returns a string which represents the value of the object.
The method is overriden frequently. When we call the print() or println() meth-
ods to display an object in text mode on the screen, Java calls the toString()
method automatically to obtain a string representing the state of the object.
The method finalize() is Java’s version of the destructor in C++. This method
has to be overriden by any class that requires specialized processing when the object
is destroyed.
The methods wait() and notify are used for multithreading and will be discussed
later.
86 CHAPTER 4. CLASSES AND OBJECTS
// MyObject.java
System.out.println(a[3]);
boolean b = a[4].equals(a[3]);
System.out.println("b = " + b); // => false
methods.
4.7. OBJECT CLASS 87
// MyClone.java
//
// protected Object clone() // in Object class
// creates a new object of the same class as this object
class Point
{
private double x, y;
Point(double a,double b) { x = a; y = b; }
class MyClone
{
public static void main(String args[])
{
Point p = new Point(2.0,3.0);
System.out.println("p = " + p);
Point q = (Point) p.clone();
System.out.println("q = " + q);
if(q == p)
System.out.println("q == p");
else System.out.println("q != p"); // => q != p
if(q.equals(p))
System.out.println("q equals p"); // => q equals p
else System.out.println("q does not equal p");
}
}
88 CHAPTER 4. CLASSES AND OBJECTS
// Pair.java
public Pair(int x)
{
a = x;
b = x + 1;
}
Pair Q;
Q = new Pair(55);
Q.increment_pair();
Q.print_pair(); // => 5657
}
}
4.8. THE THIS OBJECT 89
Thus the this reference is not instance data stored in an object itself. Rather, the
this reference is passed into the object as an implicit argument in every non-static
method call.
// ThisTest.java
import java.awt.Graphics;
import java.applet.Applet;
<HTML>
<APPLET CODE="ThisTest.class" width=275 height=35>
</APPLET>
</HTML>
The output is
i = 12 this.i = 12
90 CHAPTER 4. CLASSES AND OBJECTS
The following C++ program demonstrates how the this pointer works. The reader
should compare this and the addresses of the objects x and y.
// myclass.cpp
#include <iostream.h>
class X
{
public:
X();
~X();
};
X::X()
{
cout << "this = " << this << endl;
}
X::~X()
{
cout << "this = " << this << endl;
cout << "destructor called" << endl;
}
int main()
{
X x;
cout << "&x = " << &x << endl;
X y;
cout << "&y = " << &y << endl;
return 0;
}
The output is
this = 0x0063FDF4
&x = 0x0063FDF4
this = 0x0063FDF0
&y = 0x0063FDF0
this = 0x0063FDF0
destructor called
this = 0x0063FDF4
destructor called
4.9. THE CLASS CLASS 91
The method
returns the Class object associated with the class with the given string name. The
method
Class[] getClasses()
returns an array containing Class objects representing all the public classes and
interfaces that are members of the class represented by this Class object. The
methods
Constructors[] getConstructors()
Method[] getMethods()
Field[] getFields
return an array containing Constructor (Method, Field) objects reflecting all the
public constructors of the class represented by this Class object.
The method
boolean isPrimitive()
determines if the specified Class object represents a primitive (basic) data type.
The method
Class[] getSuperclass()
returns the object that represents the superclass of that class if this object represents
any class other than the class Object.
92 CHAPTER 4. CLASSES AND OBJECTS
The following application takes as command line argument the name of a class and
lists the public attributes, constructors and methods of the class.
// MyClass.java
import java.lang.reflect.*;
if(constructors.length > 0)
System.out.println("Constructors = ");
int i;
for(i=0; i < constructors.length; ++i)
System.out.println(constructors[i]);
if(methods.length > 0)
System.out.println("\nMethods = ");
for(i=0; i < methods.length; i++)
System.out.println(methods[i]);
if(fields.length > 0)
System.out.println("\nFields = ");
for(i=0; i < fields.length; i++)
System.out.println(fields[i]);
}
}
4.10. THE CALENDAR CLASS 93
A Date object represents a specific instant in time with millisecond precision. Sub-
classes of the Calendar class interpret a Date according to the rules of a spe-
cific calendar system. One concrete subclass of Calendar is provided, namely
GregorianCalendar. The method
Calendar getInstance()
returns a GregorianCalendar object whose time fields given above have been ini-
tialized with current date and time. The method
in the class Calendar gets the value for a given time field.
A Calendar object can produce all the time field values needed to implement the
date-time formatting for a particular language and calendar style. The interpreta-
tion of noon and midnight is as follows: 24:00:00 belongs to the following day and
is am, noon belongs to pm.
The Calendar class provides support for date conversion that were previously imple-
mented by the Date class. The support provided by Calendar is more comprehensive
and international. The Calendar class is an abstract class that can be extended to
provide conversions for specific calendar systems. The GregorianCalendar subclass
supports the predominant Calendar class used by many countries. It supports the
eras B.C. and A.D. by defining them as class constants. It provides seven construc-
tors that allow GregorianCalendar objects to be created using a combination of
different date, time zone, and local values. It methods override those provided by
the Calendar class.
In the following program using the Calendar class we measure the time in seconds
we need to run two nested for loops and then we provide the present time in hours,
minutes, seconds, and milliseconds.
94 CHAPTER 4. CLASSES AND OBJECTS
// MyCalendar.java
import java.util.Calendar;
for(i=0;i<40000;i++)
{
for(j=0;j<40000;j++)
{
j++;
} // end for loop j
j = 0;
} // end for loop i
time = Calendar.getInstance();
t2 = time.get(Calendar.SECOND);
We can also use the Calendar class to find the age of a person, where the birthdate
of the person is given.
// Person.java
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.Calendar;
import java.util.GregorianCalendar;
class Person
{
final String name;
final GregorianCalendar dob;
int age()
{
final GregorianCalendar today = new GregorianCalendar();
final int diff = today.get(Calendar.YEAR) - dob.get(Calendar.YEAR);
final int this_day = today.get(Calendar.DAY_OF_YEAR);
final int dob_day = dob.get(Calendar.DAY_OF_YEAR);
if(this_day > dob_day) { return diff; }
else { return (diff - 1); }
}
To get the current date and time the class Timestamp from java.sql can be used.
// TimeTest.java
import java.sql.Timestamp;
import java.util.Date;
2003-07-16 17:54:27.601
4.11. DESTROYING OBJECTS 97
class Destroy
{
static public void main(String[] args)
{
String s = new String("Egoli");
System.out.println("s = " + s); // => Egoli
s = null;
System.out.println("s = " + s); // => null
s = new String("Gauteng");
System.out.println("s = " + s); // => Gauteng
}
}
The next program shows how to use the method finalize().
// Final.java
class End
{
int myId;
public End(int sequenceNumber) { myId = sequenceNumber; }
public void finalize() { System.out.println(myId); }
}
class Final
{
public static void main(String args[])
{
End sampleObject;
for(int k=0;k < 5;k++) sampleObject = new End(k);
}
}
98 CHAPTER 4. CLASSES AND OBJECTS
We have is one class to define the regular expression we want to match (the Pattern),
and another class (the Matcher) for searching a pattern in a given string. Most of
the work of using the regular expression library is understanding its pattern syntax.
The actual parsing is the easy part. The simplest kind of regular expression is
a literal. A literal is not simply a character within the regular expression, but a
character that is not part of some special grouping or expression within the regular
expression. For instance, the literal "x" is a regular expression. Using the literal,
a matcher, and a string, we can ask ”Does the regular expression ’x’ match the
entire string?” Here’s an expression that asks the question
boolean b = Pattern.matches("x",someString);
If the pattern "x" is the string referenced by someString, then b is true. Otherwise,
b is false. The matcher is defined by the Pattern class, not the Matcher class. The
matches method is defined by the Pattern class as a convenience for when a regular
expression is used just once. Normally, we would define a Pattern class, a Matcher
class for the Pattern, and then use the matches method defined by the Matcher
class
Regular expressions can be more complex than literals. Adding to the complexity
are wildcards and quantifiers. There is only one wildcard used in regular expressions.
It is the period (.) character. A wildcard is used to match any single character,
possibly even a newline. The quantifier characters are the + and *. The question
mark is also a quantifier character. The + character placed after a regular expression
allows for a regular expression to be matched one or more times. The * is like the
+ character, but works zero or more times. For instance, if we want to find a string
with a j at the beginning, a z at the end, and at least one character between the two,
4.12. REGULAR EXPRESSION 99
we use the expression "j.+z". If there doesn’t have to be any characters between the
j and the z, we use "j.*z" instead. The pattern matching tries to find the largest
possible hit within a string. So if we request a match against the pattern "j.*z", us-
ing the string "jazjazjazjaz", it returns the entire string, not just a single "jaz".
This is called greedy behaviour. It is the default in a regular expression unless we
specify otherwise. By placing multiple expressions in parentheses, we can request a
match against multi-character patterns. For instance, to match a j followed by a
z, we can use the "(jz)" pattern. It is the same as "jz". But, by using parenthe-
sis, we can use the quantifiers and say match any number of "jz" patterns: "(jz)+".
Another way of working with patterns is through character classes. With character
classes, we specify a range of possible characters instead of specifying individual
characters. For instance, if we want to match against any letter from j to z, we
specify the range j-z in square brackets: "[j-z]". We could also attach a quantifier
to the expression, for example, "[j-z]+", to get an expression matching at least
one character between j and z, inclusively. Certain character classes are predefined.
These represent classes that are common, and so they have a common shorthand.
Some of the predefined character classes are
\d A digit ([0-9])
\D A non-digit ([^0-9])
\s A whitespace character [ \t\n\x0B\f\r]
\S non-whitespace character: [^\s]
\w A word character: [a-zA-Z_0-9]
\W A non-word character: [^\w]
For character classes, ^ is used for negation of an expression. There is a second
set of predefined character classes, called POSIX character classes. These are taken
from the POSIX specification, and work with US-ASCII characters only
\p{Lower} A lower-case alphabetic character: [a-z]
\p{Upper} An upper-case alphabetic character:[A-Z]
\p{ASCII} All ASCII:[\x00-\x7F]
\p{Alpha} An alphabetic character:[\p{Lower}\p{Upper}]
\p{Digit} A decimal digit: [0-9]
\p{Alnum} An alphanumeric character:[\p{Alpha}\p{Digit}]
\p{Punct} Punctuation: one of !"#$%&’()*,-./:;<=>?@[\]^_‘{|}~
\p{Graph} A visible character: [\p{Alnum}\p{Punct}]
\p{Print} A printable character: [\p{Graph}]
\p{Blank} A space or a tab: [ \t]
\p{Cntrl} A control character: [\x00-\x1F\x7F]
\p{XDigit} A hexadecimal digit: [0-9a-fA-F]
\p{Space} A whitespace character: [ \t\n\x0B\f\r]
The final set of character classes listed here are the boundary matchers. These are
meant to match the beginning or end of a sequence of characters, specifically a line,
word, or pattern.
100 CHAPTER 4. CLASSES AND OBJECTS
The key thing to understand about all the character class expressions is the use of
the \. When we compose a regular expression as a Java string, we must escape the \
character. Otherwise, the character following the \ will be treated as special by the
javac compiler. To escape the character, specify a double \\. By placing a double
\\ in the string, we are saying we want the actual \ character there. For instance, if
we want to use a pattern for any string of alphanumeric characters, simply having
a string containing \p{Alnum}* is not sufficient. We must escape the \ as follows
boolean b = Pattern.matches("\\p{Alnum}*",someString);
The Pattern class is for defining patterns, that is, it defines the regular expression
we want to match. Instead of using matches to see if a pattern matches the whole
string, what normally happens is we check to see if a pattern matches the next part
of the string. To use a pattern we must compile it. The commmand is
The matches method of the Pattern class compiles the pattern with each call. If
we want to use a pattern many times, we can avoid multiple compilation by getting
a Matcher class for the Pattern class and then using the Matcher class. After we
compile the pattern, we can request to get a Matcher for a specific string.
The Matcher provides a matches method that checks against the entire string. The
class also provides a find() method that tries to find the next sequence, possibly
not at the beginning of the string, that matches the pattern. After we know we have
a match, we can get the match with the group() method
if(matcher.find()) {
System.out.println(matcher.group());
}
We can also use the matcher as a search and replace mechanism. For instance, to
replace all occurrences of a pattern within a string, we use the following expression
The following program takes three command line arguments. The first argument is
a string to search. The second is a pattern for the search. The third is the replace-
ment string. The replacement string replaces each occurrence of the pattern found
in the search string.
// MyRegExp.java
import java.util.regex.*;
For example, if we compile the program, and then run it like this
java MyRegExp "the cat jumps over the cat" "cat" "dog"
It returns:
In next example we replace all small letter in the string Hello World by x.
// MyRegExp1.java
import java.util.regex.*;
if(m.find())
{
System.out.println(m.replaceAll("x"));
}
} // end main
}
The output is
Hxxxx Wxxxx
4.13. THE BYTECODE FORMAT 103
For example consider the following Java program Exp1.java that finds the first 9001
digits of the number e.
// Exp1.java
while((--n != 0))
a[n] = 1 + 1/n;
javac Exp1.java
Method Exp1()
0 aload_0
1 invokespecial #1 <Method java.lang.Object()>
4 return
With the exception of two table lookup instruction, all instructions are fixed length
based on the opcode.
106 CHAPTER 4. CLASSES AND OBJECTS
The bytecode instruction set was designed to be compact. All instructions, except
two that deal with table jumping, are aligned on byte boundaries. The total num-
ber of opcodes is small enough so that opcodes occupy only one byte. This helps
minimize the size of class files that may be traveling across networks before being
loaded by a JVM. It also helps keep the size of the JVM implementation small. All
computation in the JVM centers on the stack. Because the JVM has no registers
for storing abitrary values, everything must be pushed onto the stack before it can
be used in a calculation. Bytecode instructions therefore operate primarily on the
stack. For example,
dup
duplicates top single-word items on the stack. Thus dup pops the top single-word
value off te operand stack, and then pushes that value twice - i.e. it makes an extra
copy of the top item on the stack. The command
ifne <label>
pops the top int off the operand stack. If the int does not equal zero, execution
branches to the address (pc + branchoffset), where pc is the address of the ifne
opcode in the bytecode and branchoffset is a 16-bit signed integer parameter follow-
ing the ifne opcode in the bytecode. If the int on the stack equals zero, execution
continues at the next instruction. The command
if_icmpgt <label>
pops the top two ints off the stack and compares them. If value2 is greater than
value1, execution branches to the address (pc + branchoffset), where pc is the
address of the if_icmpgt in the bytecode and branchoffset is a 16-bit signed integer
parameter following the if_icmpgt opcode in the bytecode. If value2 is less than
or equal to value1, execution continues at the next instruction.
Primitive types
As described in chapter 2 the JVM supports seven primitive data types. Java
programmers can declare and use variables of these data types, and Java bytecodes
operate upon these data types. The seven primitive types are listed in the following
table
Type Definition
==== ==========
byte one-byte signed two’s complement integer
short two-byte signed two’s complement integer
int 4-byte signed two’s complement integer
long 8-byte signed two’s complement integer
float 4-byte IEEE 754 single-precision float
double 8-byte IEEE 754 double-precision float
char 2-byte unsigned Unicode character
4.13. THE BYTECODE FORMAT 107
The primitive types appear as operands in bytecode streams. All primitive types
that occupy more than 1 byte are stored in big-endian order in the bytecode stream,
which means higher-order bytes precede lower-order bytes. For example, to push
the constant value 256 (hex 0100) onto the stack, we would use the sipush opcode
followed by a short operand. The short appears in the bytecode stream as 01
00 because the JVM is big-endian. If the JVM were little-endian, the short would
appear as 00 01.
Java opcodes generally indicate the type of their operands. This allows operands to
just be themselves, with no need to identify their type to the JVM. For example,
instead of having one opcode that pushes a local variable onto the stack, the JVM
has several. Opcodes iload, lload, fload, and dload push local variables of type
int, long, float, and double, respectively, onto the stack.
Many opcodes push constants onto the stack. Opcodes indicate the constant value
to push in three different ways. The constant value is either implicit in the opcode
itself, follows the opcode in the bytecode stream as an operand, or is taken from
the constant pool. Some opcodes by themselves indicate a type and constant value
to push. For example, the iconst_1 opcode tells the JVM to push integer value
one. Such bytecodes are defined for some commonly pushed numbers of various
types. These instructions occupy only 1 byte in the bytecode stream. They increase
the efficiency of bytecode execution and reduce the size of bytecode streams. The
opcodes that push ints and floats are shown in the following table
Opcode Operand(s) Description
====== ========== ===========
iconst_m1 none pushes int -1 onto the stack
iconst_0 none pushes int 0 onto the stack
iconst_1 none pushes int 1 onto the stack
iconst_2 none pushes int 2 onto the stack
iconst_3 none pushes int 3 onto the stack
iconst_4 none pushes int 4 onto the stack
iconst_5 none pushes int 5 onto the stack
fconst_0 none pushes float 0 onto the stack
fconst_1 none pushes float 1 onto the stack
fconst_2 none pushes float 2 onto the stack
The opcodes shown in the previous table push ints and floats, which are 32-bit
values. Each slot on the Java stack is 32 bits wide. Therefore each time an int
or float is pushed onto the stack, it occupies one slot. The opcodes shown in the
next table push longs and doubles. Long and double values occupy 64 bits. Each
time a long or double is pushed onto the stack, its value occupies two slots on the
stack. Opcodes that indicate a specific long or double value to push are shown in
the following table:
108 CHAPTER 4. CLASSES AND OBJECTS
Local variables are stored in a special section of the stack frame. The stack frame is
the portion of the stack being used by the currently executing method. Each stack
frame consists of three sections – the local variables, the execution environment,
and the operand stack. Pushing a local variable onto the stack actually involves
moving a value from the local variables section of the stack frame to the operand
section. The operand section of the currently executing method is always the top
of the stack, so pushing a value onto the operand section of the current stack frame
is the same as pushing a value onto the top of the stack. The Java stack is a
last-in, first-out stack of 32-bit slots. Because each slot in the stack occupies 32
bits, all local variables occupy at least 32 bits. Local variables of type long and
double, which are 64-bit quantities, occupy two slots on the stack. Local variables
of type byte or short are stored as local variables of type int, but with a value
that is valid for the smaller type. For example, an int local variable which repre-
sents a byte type will always contain a value valid for a byte (−128 ≤ value ≤ 127).
Each local variable of a method has a unique index. The local variable section of a
method’s stack frame can be thought of as an array of 32-bit slots, each one address-
able by the array index. Local variables of type long or double, which occupy two
slots, are referred to by the lower of the two slot indexes. For example, a double
that occupies slots two and three would be referred to by an index of two. Several
opcodes exist that push int and float local variables onto the operand stack. Some
opcodes are defined that implicitly refer to a commonly used local variable position.
For example, iload_0 loads the int local variable at position zero. Other local
variables are pushed onto the stack by an opcode that takes the local variable index
from the first byte following the opcode. The iload instruction is an example of
this type of opcode. The first byte following iload is interpreted as an unsigned
8-bit index that refers to a local variable. Unsigned 8-bit local variable indexes,
such as the one that follows the iload instruction, limit the number of local vari-
ables in a method to 256. A separate instruction, called wide, can extend an 8-bit
index by another 8 bits. This raises the local variable limit to 64 kilobytes. The
wide opcode is followed by an 8-bit operand. The wide opcode and its operand
110 CHAPTER 4. CLASSES AND OBJECTS
can precede an instruction, such as iload, that takes an 8-bit unsigned local vari-
able index. The JVM combines the 8-bit operand of the wide instruction with the
8-bit operand of the iload instruction to yield a 16-bit unsigned local variable index.
The opcodes that push int and float local variables onto the stack are shown in the
following table:
The next table shows the instructions that push local variables of type long and
double onto the stack. These instructions move 64 bits from the local variable
section of the stack frame to the operand section.
The final group of opcodes that push local variables move 32-bit object references
from the local variables section of the stack frame to the operand section. These
opcodes are shown in the following table:
For each opcode that pushes a local variable onto the stack there exists a correspond-
ing opcode that pops the top of the stack back into the local variable. The names
of these opcodes can be formed by replacing load in the names of the push opcodes
with store. The opcodes that pop ints and floats from the top of the operand stack
to a local variable are listed in the following table. Each of these opcodes moves one
32-bit value from the top of the stack to a local variable.
The next table shows the instructions that pop values of type long and double into
a local variable. These instructions move a 64-bit value from the top of the operand
stack to a local variable.
and vindex+1
lstore_0 none pops long to local variable positions zero and one
lstore_1 none pops long to local variable positions one and two
lstore_2 none pops long to local variable positions two and three
lstore_3 none pops long to local variable positions three and four
dstore vindex pops double to local variable positions vindex
and vindex+1
dstore_0 none pops double to local variable positions zero and one
dstore_1 none pops double to local variable positions one and two
dstore_2 none pops double to local variable positions two and three
dstore_3 none pops double to local variable positions three and four
The final group of opcodes that pops to local variables are shown in the following
table. These opcodes pop a 32-bit object reference from the top of the operand
stack to a local variable.
Opcode Operand(s) Description
====== ========== ===========
astore vindex pops object reference to local variable position vindex
astore_0 none pops object reference to local variable position zero
astore_1 none pops object reference to local variable position one
astore_2 none pops object reference to local variable position two
astore_3 none pops object reference to local variable position three
Type conversions
The Java virtual machine has many opcodes that convert from one primitive type
to another. No opcodes follow the conversion opcodes in the bytecode stream. The
value to convert is taken from the top of the stack. The JVM pops the value at the
top of the stack, converts it, and pushes the result back onto the stack. Opcodes
that convert between int, long, float, and double are shown in the following table.
There is an opcode for each possible from-to combination of these four types:
Opcode Operand(s) Description
====== ========== ===========
i2l none converts int to long
i2f none converts int to float
i2d none converts int to double
l2i none converts long to int
l2f none converts long to float
l2d none converts long to double
f2i none converts float to int
f2l none converts float to long
f2d none converts float to double
d2i none converts double to int
d2l none converts double to long
d2f none converts double to float
4.13. THE BYTECODE FORMAT 113
Opcodes that convert from an int to a type smaller than int are shown in the
following table. No opcodes exist that convert directly from a long, float, or
double to the types smaller than int. Therefore converting from a float to a
byte, for example, would require two steps. First the float must be converted to
an int with f2i, then the resulting int can be converted to a byte with int2byte.
Although opcodes exist that convert an int to primitive types smaller than int
(byte, short, and char), no opcodes exist that convert in the opposite direction.
This is because any bytes, shorts, or chars are effectively converted to int before
being pushed onto the stack. Arithmetic operations upon bytes, shorts, and chars
are done by first converting the values to int, performing the arithmetic operations
on the ints, and being happy with an int result.
The maximum value for a byte is 127. The minimum value is −128. Values of type
int that are within this range convert directly to byte. Consider now the case,
when the int gets beyond the valid range for byte, things get interesting. The JVM
converts an int to a byte by truncating and sign extending. The highest order bit,
the sign bit, of longs, ints, shorts, and bytes indicate whether or not the integer
value is positive or negative. If the sign bit is zero, the value is positive. If the sign
bit is one, the value is negative. Bit 7 of a byte value is its sign bit. To convert an
int to a byte, bit 7 of the int is copied to bits 8 through 31. This produces an int
that has the same numerical value that the int’s lowest order byte would have if it
were interpreted as a byte type. After the truncation and sign extension, the int
will contain a valid byte value. What happens when an int that is just beyond the
valid range for byte types gets converted to a byte. For example, when the variable
has a value of 128 (0x00000080) and is converted to byte, the resulting byte value
is −128 (0xffffff80). Later, when the variable has a value of −129 (0xffffff7f) and is
converted to byte, the resulting byte value is 127 (0x0000007f).
Chapter 5
5.1 Introduction
Inheritance is an integral part of Java and any OOP language such as C++. In Java
we are always using inheritance when we create a class, because if we do not override
we inherit from Java’s standard root class Object. When we use inheritance we
say
An abstract class is a class that has at least one abstract method. An abstract
method is a method that is declared with only its signature; it has no implementa-
tion. Since it has at least one abstract method, an abstract class cannot be instan-
tiated. Classes and methods are declared to be abstract by means of the abstract
modifier. A number of Java classes are declared abstract. For example
We also allowed to write our own abstract class and then in the derived classes give
the implementations.
In the following section we give examples for the use of abstract classes and inheri-
tance.
114
5.2. ABSTRACT CLASS 115
// MTest.java
import java.math.*;
double area()
{
return Math.PI*radius*radius;
}
double area()
{
return side*side;
}
double area()
{
return 0.5*base*altitude;
}
class MTest
{
public static void main(String[] args)
{
Circle circle = new Circle(2.5);
System.out.println("area of circle is: " + circle.area());
5.3 Inheritance
Inheritance is the creation of one class by extending another class so that instances
of the new class automatically inherit the fields and methods of its parent class.
The keyword is extends. In the following program the line
class ClassB extends ClassA
defines class ClassB to be a subclass of class ClassA. We override toString().
// Inher.java
class ClassA
{
protected double x;
class Inher
{
public static void main(String[] args)
{
ClassA a = new ClassA();
System.out.println("a = " + a);
ClassB b = new ClassB();
System.out.println("b = " + b);
}
}
// output
// (4.5)
// (0.0,1.5)
118 CHAPTER 5. INHERITANCE AND ABSTRACT CLASSES
The following program shows how a subclass’s fields and methods override those
of its superclass. In the following program we override the methods void g() and
String toString().
// Inher1.java
class ClassA
{
protected int m;
protected int n;
void f()
{
System.out.println("In ClassA method f() ");
m = 15;
}
void g()
{
System.out.println("In ClassA method g() ");
n = 31;
}
void g()
{
System.out.println("In ClassB method g() ");
n = 2.789;
}
class Inher1
{
public static void main(String[] args)
{
ClassA a = new ClassA();
a.f();
a.g();
System.out.println("a = " + a);
The output is
5.4 Composition
Inheritance uses a - is a relationship -. Composition is the creation of one class
using another class for its component data. It uses the - has a relationship -. For
example a person has a name. It is very common to use composition and inheri-
tance together. The following program shows such a case. Both composition and
inheritance allow to place subobjects inside our new class. The protected keyword
says ”this is private as far as the class user is concerned”, but available to anyone
who inherits from this class.
Java uses the keyword super to refer to members of the parent class. When used
in the form super() it invokes the superclass’s constructor. When used in the form
super.f() it invokes the function f() declared in the superclass. Thus we can
override the override. The method String trim() in the String class removes
white space from both ends of this string.
// MInher.java
class Name
{
private String first;
private String middle;
private String last;
Name() { }
{
String s = new String();
if(first != null) s+= first + " ";
if(middle != null) s += middle + " ";
if(last != null) s += last + " ";
return s.trim();
}
}
class Person
{
protected Name name;
protected char sex; // ’M’ or ’F’
protected String id; // e.g., social Security number
super(name,sex);
this.credits = credits;
this.gpa = gpa;
}
class MInher
{
public static void main(String[] args)
{
Name fc = new Name("Francis", "Harry Compton", "Crick");
System.out.println(fc + " won the 1962 Nobel in Physiology.");
System.out.println("His first name was " + fc.first());
5.5 Constructors
When an object is created, its member can be initialized by a constructor method.
A constructor is not a method but a special operator which is executed when a new
instance of a class is created. Depending on the arguments passed to the class when
the instance is generated, a different constructor can be called. By default, every
class has a single constructor with no parameters the so-called default constructor.
Besides the default constructor we can define other constructors. We note that
constructors, unlike methods, are not inherited.
In the following program we provide for the class MPoint a default constructor
and a constructor which takes as argument two double. We override the methods
toString() and equals() from the Object class.
// MPoint.java
else
return false;
}
boolean b = P.equals(Q);
System.out.println("b = " + b);
String st = P.toString();
System.out.println("st = " + st);
The above program the class MPoint contains the main method. In the follow-
ing program we have two classes in one file. The class MMain contains the main
method. The class MPoint is standealone. In order that we can use construc-
tors, methods and data members of class MPoint in class MMain they have to be
declared public.
// MMain.java
class MPoint
{
private double x;
private double y;
class MMain
{
public static void main(String[] args)
{
MPoint P;
P = new MPoint(4.5,5.5);
double distance_square = P.square_length(P);
System.out.println(distance_square); // 50.5
public double z;
private double z;
javac MMain.java
MPoint.class MMain.class
Next we put the two classes into two different files. The file MMPoint.java contains
the class MMPoint. It does not contain a main method. To use it we have to compile
it using javac MMPoint.java. This provides us with the class file MMPoint.class.
The file MMain.java contains the main method.
5.5. CONSTRUCTORS 127
// MMPoint.java
public MMPoint()
{
x = 0.0;
y = 0.0;
z = 0.0;
}
The class MMMain calls the class MMPoint which is in a separate file. To run the
program we first have to compile the file MMPoint.java, i.e.
javac MMPoint.java
MMPoint.class
javac MMMain.java
java MMMain
The file MMMain.java only includes the class MMMain with the main method. It
uses the constructor
MMPoint(double,double)
square_length(MMPoint)
of the class MMPoint. Furthermore we access the public data member z of class
MMPoint. This can be done, because double z is declared public.
// MMMain.java
// Employee.java
// inner class
class Address
{
int number = 0;
String street = "";
String city = "";
void printDetails()
{
130 CHAPTER 5. INHERITANCE AND ABSTRACT CLASSES
// inner class
class Wage
{
int hoursWorked = 0;
Wage(int hours)
{
hoursWorked = hours;
}
void printDetails()
{
System.out.println("Pay packet = " + hoursWorked*rate);
}
e[0].printInformation();
e[1].printInformation();
}
5.7 Interfaces
Subclasses are used to redefine the behaviour and data structures of a superclass.
As mentioned before Java supports single inheritance while C++ supports multiple
inheritance. Multiple inheritance is where a subclass can inherit from more than
one superclass. However, problems can arise when attempting to determine which
methods are executed. Java introduces the concept of interfaces to overcome one of
the most significant problems with single inheritance. Thus the interface keyword
takes the abstract concept one step further. Thus the interface is used to establish
a protocol between classes. The Java interface construct is essentially a skeleton
which specifies the protocol that a class must provide if it implements that interface.
That is, it indicates which must be available from any class which implements that
interface. The interface itself does not define any functionality. The format for
an interface is
For example
// ColorConstants.java
We compile the file ColorConstants.java to obtain the class file. We can now
apply the interface with the following program
// ColorImpl.java
6.1 Introduction
The AWT (Abstract Window Tookit) allows Java developers to quickly build Java
applets and applications using a group of prebuilt user interface components. A
number of Java IDE’s are available which support the creation of user interfaces
using the AWT by dragging-and-dropping components off a toolbar. These IDE’S
actually generate Java code on the fly based on what we do in the graphical design
environment. This is in contrast to toolset such as Microsoft Visual Basic which
separate user interface design from the application code. The advantage of the Java
approach is that we can edit our GUI either through a graphical IDE or by simple
modifying the Java code and recompiling.
1. Creation of a container
3. Handling of events
This container object is actually derived from the java.awt.Container class and
is one of (or inherited from) three primary classes:
132
6.1. INTRODUCTION 133
Container objects are derived from Component. The main ones derived from that
are
GUI components can be arranged on a container using one of two methords. the first
method involves the exact positioning (by pixel) of components on the container.
the second method involves the use of what Java calls Layout Managers. If we think
about it, vitually all GUIs arrange components based on the row-column metaphor.
In other words, buttons, text boxes, and list generally are not located at random
all over a form. Instead, they are usually neatly arranged in rows or columns with
an OK or Cancel button arranged at the bottom or on the side. Layout Managers
allow us to quickly add components to the manager and then have it arrange them
automatically. The AWT provides six layout managers for our use:
1. java.AWT.BorderLayout
2. java.awt.FlowLayout
3. java.awt.CardLayout
4. java.awt.GridLayout
5. java.awt.GridBagLayout
6. java.awt.BoxLayout
The Container class contains the setLayout() method so that we can set the
default LayoutManager to be used by our GUI. To actually add components to the
container, we use the container’s add() method.
The class Button provides buttons. Buttons are for clicking. We can specify their
labels and control what happens when they are clicked.
The Choice class presents a pop-up menu of choices. The current choice is displayed
as the title of the menu. Thus their are drop-down lists from which the user can
select one option.
The List component presents the user with a scrolling list of text items. The list
can be set up so that the user can choose either one item or multiple items.
A TextField object is a text component that allows for the editing of a single line
of text. The constructor Textfield(String text,int cols) constructos a new
Textfield, text is the text to be displayed and cols is the number of columns.
A TextArea object is a multiline region that displays text. It can be set to allow
editing or to be read-only. With the TextArea constructor we can control whether
a TextArea will have scroll bars: vertical, horizontal, both or neither.
6.2. CLASS COMPONENT AND CLASS CONTAINER 135
in class Container adds the specified component to the end of the container. The
component could be for example a Button or a TextField.
The method
resizes this component so that it has width width and height height. The method
adds the specified window listener to receive window events from this window. In a
method, the keyword this refers to the object on which the method operates. The
method
Layout managers help to produce portable, presentable user interfaces. There are a
number of different layout managers which use different philosophies to handle the
way in which they lay out components. They are
BorderLayout()
creates a new BorderLayout with the default horizontal and vertical gaps of zero.
The constructor
136 CHAPTER 6. THE GUI AND ITS COMPONENTS
creates a new BoderLayout with the specified horizontal and vertical gaps between
the components. The BorderLayout class contains the following data fields
The GridLayout class divides the container area into a rectangular grid. Every new
compnent we add goes into a single grid cell. The cells are filled from left to right
and top to bottom. The GridLayout() constructor creates a grid layout with a
default of one column per component, in a single row. The constructor
creates a grid layout with the specified number of columns and rows. This class is a
flexible layout manager that aligns components vertically and horizontally without
requiring that the components be the same size. The CardLayout object is a layout
manager for a container. It treats each component in the container as a card. Only
one card is visible at the time, and the containter acts as a stack of cards.
The method
The method
The following two programs show an application of the classes Container and
Component togther with the classes Button, Checkbox, Choice, Label, List and
TextField.
6.2. CLASS COMPONENT AND CLASS CONTAINER 137
// GUI.java
import java.awt.*;
import java.awt.event.*;
// GUI1.java
import java.awt.*;
import java.awt.event.*;
setLayout(new FlowLayout());
add(choice);
add(lst);
} // end default constructor GUI1
is the listener interface for receiving action events. The class that is interested in
processing an action event implements this interface and the object created with that
class is registered with a component using the component’s addActionListener
method. When the action event occurs that object’s actionPerformed method
is invoked. The class ActionEvent provides for a semantic event which indicates
that a component-defined action occured. This high-level event is generated by a
component (such as a button) when the component specific action occurs (such as
being pressed). The event is passed to every ActionListener object that registered
to receive such events using the component’s addActionListener method. The
method
// ButtonWA.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
{
t.setText("Button 1");
}
} // end class B1
applet.init();
applet.start();
aFrame.setVisible(true);
}
}
6.4. CLASS PANEL 141
// ButtonGame.java
import java.awt.*;
import java.awt.event.*;
public ButtonGame()
{
setSize(200,200);
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent event)
{ System.exit(0); }});
for(int nRow=0;nRow<nRows;nRow++)
{
for(int nCol=0;nCol<nCols;nCol++)
{
buttons[nRow][nCol] = new Button("");
buttons[nRow][nCol].addActionListener(this);
panel.add(buttons[nRow][nCol]);
}
}
142 CHAPTER 6. THE GUI AND ITS COMPONENTS
add("Center",panel);
textField = new TextField("",80);
textField.setEditable(false);
add("South",textField);
for(int i=0;i<nButtons;i++)
{
boolean labelUsed;
int label;
do
{
label = random(nButtons)+1;
labelUsed = false;
for(int j=0;j<i;j++)
labelUsed = ((labelUsed) || (label==labelsUsed[j]));
} while (labelUsed);
labelsUsed[i] = label;
int nRow = i/nCols;
int nCol = i - nRow*nCols;
buttons[nRow][nCol].setLabel((new Integer(label)).toString());
}
getButtonPosition((new Integer(nButtons)).toString());
blankRow = clickedRow; blankCol = clickedCol;
Button blank = buttons[clickedRow][clickedCol];
blank.setLabel(""); blank.setBackground(Color.green);
} // end constructor ButtonGame
}
}
}
// ColorDraw.java
import java.util.*;
import java.awt.*;
import java.awt.event.*;
public ColorDraw()
{
setTitle("Mouse Drawing Application");
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent event)
{ System.exit(0); }});
int nGradingsInEachColor = 4;
int nColors =
nGradingsInEachColor*nGradingsInEachColor*nGradingsInEachColor;
add("West",colorButtons);
add("Center",drawCanvas);
} // end constructor ColorDraw()
class Line
{
public Point start, end;
public Color color;
public DrawCanvas()
{
addMouseListener(this);
addMouseMotionListener(this);
}
g.setColor(penColor);
g.drawLine(lineStart.x,lineStart.y,newX,newY);
lines.addElement(new Line(lineStart,new Point(newX,newY),penColor));
lineStart.move(newX,newY);
} // end mouseDragged
} // end class DrawCanvas
Point getPoint()
in class MouseEvent returns the (x, y) position of the event relative to the source
component. The method
int getClickCount()
returns the number of mouse clicks associated with this event. The methods
// Mouse.java
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.*;
import java.awt.event.*;
posX = 150;
posY = 0;
if(mouseEvent != null)
{
g.drawString("Mouse Position: "+ mouseEvent.getPoint(),posX,posY+=15);
g.drawString("Mouse Clicks: "+ mouseEvent.getClickCount(),posX,posY+=15);
g.drawString( "Mouse Button: "+ whichButton,posX,posY+=15);
}
if(bMoved)
{
g.drawString("mouseMoved(): " + spin("mouseMoved"),posX,posY+=15);
bMoved = false;
}
if(bDragged)
{
g.drawString("mouseDragged(): " + spin("mouseDragged"),posX,posY+=15);
bDragged = false;
}
posX = 5;
posY = 0;
int x;
for(x=0;x<message.length;x++)
150 CHAPTER 6. THE GUI AND ITS COMPONENTS
switch(pos) {
case 1:
c = ’|’; break;
case 2:
c = ’/’; break;
case 3:
c = ’-’; break;
case 4:
c = ’\\’; break;
default:
c = ’|’;
pos = 1; break;
}
return c;
} // end spin
whichButton = WhichButton();
ButtonTrail("mouseClicked");
repaint();
} // end mouseClicked
return str;
} // end WhichButton
void InitButtonTrail()
{
index = 0; message = new String[10];
}
void paint(Graphics g)
has one parameter of type Graphics. It paints this component. The Graphics class
contains all the drawing methods. The method
draws a line between the coordinates (x1,y1) and (x2,y2). The line is drawn below
and to the left of the logical coordinates. x1 - the first point x coordinate, y1 - the
first point y coordinate, x2 - the second point x coordinate, y2 - the second point y
coordinate. The method
draws the outline of the specified rectangle. The left and right edges of the rectangle
are at x and x+width. The top and buttom edges are at y and y+height. The
method
draws the outline of an oval. The result is a circle or ellipse that fits within the
rectangle specified by the x, y, width and height argument. The method
draws the outline of a circular or elliptical arc covering the specified rectangle. The
method
draws a closed polygon defined by the arrays xPoint and yPoint. Each pair of
(xPoint[i],yPoint[i]) coordinates defines a point. The lines of the polygon can
intersect.
The method
disposes of this graphics context and releases any system resources that it is using.
A graphics object cannot be used after dispose has been called. The method
154 CHAPTER 6. THE GUI AND ITS COMPONENTS
Graphics getGraphics()
The following program shows the use of the methods drawLine and drawRect.
// GraphA.java
import java.awt.Graphics;
The second and third pieces of the applet tag indicate the width and the height of
the applet in pixel. The upper left corner of the applet is always at x-coordinate 0
and y-coordinate 0. The values for height and width are provided in the HTML
file.
<HTML>
<COMMENT> HTML file GraphA.html for GraphA.java </COMMENT>
<TITLE> Graph of Mathematical Function </TITLE>
<APPLET CODE="GraphA.class" width=300 height=120>
</APPLET>
</HTML>
The following program shows the use of the method drawArc. We use this method
twice to draw a circle, where half of the circle is filled with color gold and the other
half with the color blue.
6.6. CLASS GRAPHICS 155
// Arc.java
import java.awt.*;
import java.awt.Frame;
import java.awt.event.*;
import java.awt.Graphics;
In the following program we find the time evolution of the logistic map
ut+1 = 4ut (1 − ut ), t = 0, 1, 2, . . .
where u0 ∈ [0, 1]. We display ut as a function of t
// DrawLogistic.java
import java.awt.Frame;
import java.awt.event.*;
import java.awt.Graphics;
The class GeneralPath represents a geometric path constructed from straight lines,
quadratic and cubic (Bezier) curves. It can contain multiple subpaths. The method
adds a point to the path by moving to the specified coordinates. The method
// Path.java
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
test.setBounds(0,0,300,200);
test.setVisible(true);
}
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(4.0f));
GeneralPath polygon =
new GeneralPath(GeneralPath.WIND_EVEN_ODD);
polygon.moveTo(40,40);
polygon.lineTo(250,180);
polygon.quadTo(120,100,50,160);
polygon.curveTo(20,90,180,160,220,40);
polygon.closePath();
g2.draw(polygon);
}
}
The Shape interface provides definitions for objects that represent some form of
geometric shape. The Java 2D definition of a shape does not require the shape
to enclose an area. A Shape object may represent an open curve such as a line
or parabola. For example, RectangularShape is an implementation of this inter-
face with the subclasses Arc2D, Ellipse2D, Rectangle2D, RoundRectangle2D. An
application is given below.
// Path1.java
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
test.setBounds(0,0,300,200);
test.setVisible(true);
}
6.7. GRAPHICS2D CLASS 159
// Affine.java
import java.awt.geom.AffineTransform;
import java.util.*;
at.rotate(Math.PI);
// transforms an array of double precision coordinates
// by this transform (rotate)
// and stores the result in to an array of floats.
// Each point is stored as a pair of x, y coordinates.
// srcOff(set) = 0 dstOff(set) = 0
// numPts = 2 number of point objects are to be transformed
at.transform(src,0,dst,0,2);
System.out.print("source points: ");
for(int i=0; i<4; i++)
if((i%2) == 0)
System.out.print("(" + src[i] + "," + src[i+1] + ")");
System.out.println("");
The class RenderingHints contains rendering hints that can be used by the class
Graphics2D.
// Graph2D2.java
import java.awt.Frame;
import java.awt.event.*;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.Font;
import java.awt.RenderingHints;
6.7. GRAPHICS2D CLASS 161
Color.black (0,0,0)
Color.blue (0,0,255)
Color.cyan (0,255,255)
Color.darkGray (64,64,64)
Color.gray (128,128,128)
Color.green (0,255,0)
Color.lightGray (192,192,192)
Color.magenta (255,0,255)
Color.orange (255,200,0)
Color.pink (255,175,175)
Color.red (255,0,0)
Color.white (255,255,255)
Color.yellow (255,255,0)
The constructor
creates an opaque sRGB color with the specified red, green and blue values in the
range (0, 255). The method
void setColor(Color)
in class Graphics sets this graphics context’s current color to the specified color.
6.8. COLOR CLASS 163
In the next program we show an application of the Color class. We draw a pink,
blue and red polygon. The lines of the ”polygon” intersect. Explain why ? Try to
fix it so that it is really a polygon. In this case a rectangle.
// FrameW.java
import java.awt.*;
import java.awt.Frame;
import java.awt.event.*;
import java.awt.Graphics;
}
}
A Frame is a top-level window with a title and a border. The class Frame inherts
the method
from class Component. This method shows or hides this component depending on
the value of the parameter b.
Another application of the Color class is shown in the next program. It also demon-
strates the use of the method
This method sets the paint mode of this graphics context to alternate between this
graphics context’s current color and the new specified color.
// XOR.java
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
addMouseListener(
new MouseAdapter() {
public void mousePressed(MouseEvent e) {
Graphics g = getGraphics();
g.setColor(chocolate);
g.setXORMode(scoop);
6.8. COLOR CLASS 165
g.fillOval(xStart,yStart,diameter,diameter);
g.setPaintMode();
}
}
); // end addMouseListener
} // end init
g.setColor(strawberry);
g.fillRect(0,0,width,height);
g.setColor(vanilla);
g.fillRect(dim.width-width,0,width,height);
} // end paint
} // end class XOR
166 CHAPTER 6. THE GUI AND ITS COMPONENTS
The
in the Component class creates an image from the specified image producer. The
interface
is an interface for objects which can produce the image data for Images. Each image
contains an ImageProducer which is used to reconstruct the image whenever it is
needed. When a image file has been read into an Image object, the Image object
can be displayed using the drawImage methods in the Graphics class. The method
draws as much of the specified image as is currently available. The image is drawn
with its top-left corner at (x, y) in the graphics context’s coordinate space. The
method
draws an image inside the specified rectangle of this graphics context’s coordinate
space and is scaled if necessary, where width is the width of the rectangle and
height is the height of the rectangle. The interface
// HappyFace.java
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
Image happy;
In the next program we display a 400 x 400 image representating a fade from black
to blue along the x-axis and a fade from black to red along the y-axis.
// Pixel.java
import java.awt.*;
import java.awt.event.*; // includes WindowEvent, WindowListener
import java.awt.Graphics;
import java.awt.image.*;
The Java image display mechanism has the ability to shrink or stretch images to fit
a particular size. Normally, when we display an image, we only specify the x and
y coordinates for the upper left corner of the image. We can, however, specify, an
alternate width and height for the image. Java automatically scales the images to
fit the new width and height. The following applet takes an image and displays it
stretched and shrunk.
// Media.java
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
try { tracker.waitForAll(); }
catch(Exception ignore) { }
}
getToolkit()
method to give a reference to the toolkit. The toolkit for the system will be a
subclass of the abstract Toolkit class created for our host. Toolkit uses various
native peer code to access the system GUI. There is also the static method
java.awt.Toolkit.getDefaultToolkit()
java.awt.Toolkit.getScreenSize()
java.awt.Toolkit.getScreenResolution()
java.awt.Toolkit.beep()
java.awt.Toolkit.loadSystemColors(int[] systemColors)
For example,to create a frame that is sized to a particular proportion to the screen’s
size and in particular location is illustrated by the following code:
6.10. CLASS TOOLKIT 171
// PlaceFrame.java
import java.awt.*;
import java.awt.event.*;
pf.addWindowListener(listener);
pf.setVisible(true);
}
}
172 CHAPTER 6. THE GUI AND ITS COMPONENTS
// Beep.java
import java.util.Timer;
import java.util.TimerTask;
import java.awt.Toolkit;
Exception Handling
7.1 Introduction
An exception is an error that occurs at run time. An example is division by zero.
Another example is if we try to open a file which does not exist an error will occur.
We can catch this, display an error message and ask for another filename to be
specified. When an error of this type occurs an exception is generated and Java
provides a set of language constructs which allow us to handle them. Using Java’s
exception-handling subsystem we can in a structered and controlled manner handle
run-time error. Java exception handling like C++ is built upon three keywords
To respond to an exception, the call to the method that produces it must be placed
within a try block. Thus the try block indicates the code which is to be monitored
for the exceptions listed in the catch expressions. A try block is a block of code
beginning with the try keyword followed by a left and right curly brace. Every
try block is associated with one or more catch blocks. When any method in
the try block throws any type of exception, execution of the try block ceases.
Program control passes immediately to the associated catch block. We can use an
catch expression to indicate what to do when certain classes of exception occur
(e.g. resolve the problem or generate a warning message). If no catch expression is
included, the defining methods must use the throw clause.
In C++ we can throw an instance of any class when an expectional situation arises.
This is not the case in Java. In Java an exception is always an instance of the class
Throwable, i.e. it must be directly or indirectly derived from Throwable.
173
174 CHAPTER 7. EXCEPTION HANDLING
7.3 Examples
Besides using the built-in exceptions of Java we can also create our own exceptions.
In the following program an exception is thrown when the first int number is larger
than the second int number in the method numbers. The second call to the method
numbers throws an exception since the first integer is larger than the second integer.
// Except.java
import java.io.*;
import java.lang.Exception;
// method numbers
static boolean check(int first,int second) throws Exception
{
boolean returnCode = false;
if(first > second)
{
throw new Exception("invalid values");
}
if(first <= second) { returnCode = true; }
return returnCode;
} // end method check
}
The output is:
true
Caught exception: invalid values
176 CHAPTER 7. EXCEPTION HANDLING
To define an exception we can also create a subclass of the Exception class or one
of its subclasses. We apply this to the DivideByZeroException class.
// DivideByZeroException.java
// DivideZero.java
try { temp.test(); }
catch(DivideByZeroException e) { System.out.println("Oops"); }
} // end main
The following example shows the use of multiple catch clauses and of the keyword
finally .
The keyword finally is used to specify a control block to be executed after all
processing of a try block, including the processing for any exceptions (regardless
of whether those exceptions are handled by a catch clause within the try block or
not). Multiple catch clauses are typically used in file input and output operations.
// Copy.java
import java.io.*;
int aByte = 0;
do
{
aByte = fin.read();
if(aByte != -1)
fout.write((byte) aByte);
}
while(aByte != -1);
finally
{
try
{
fin.close();
fout.close();
}
catch(Exception e)
{ }
} // end finally
} // end main
}
Chapter 8
File Manipulations
8.1 Introduction
The Java IO stream library allows to perform reading and writing with the console, a
file, a block of memory, or even across the Internet. It is possible by inheriting from
InputStream and OutputStream to create new types of input and output objects.
DataInputStream allows us to read all basic data types as well as String objects.
All the methods names start with read such as
readFloat(), readDouble(),
writeFloat(), writeDouble()
179
180 CHAPTER 8. FILE MANIPULATIONS
The method
The method
flushes this data output stream. This forces any buffered ouput bytes to be written
out to the stream. The method
closes this output stream and releases any system resources with the stream.
byte readByte()
returns the next byte of this input stream as a signed 8 bit byte. In most applications
we type convert the byte to char after reading the byte. The method
double readDouble()
reads eight input bytes and returns a double value. The method
String readUTF()
The method
String readLine()
String readLine()
8.1. INTRODUCTION 181
void writeByte(int v)
writes out a byte to the underlying output stream as 1-byte value. If no exception
is thrown the counter written is incremented by 1. The method
void writeBytes(String s)
writes out the string to the underlying output stream as a sequence of bytes. Each
character in the string is written out, in sequence, by discarding its high eight bits.
If no exception is thrown the counter written is incremented by the length of s.
For writing strings we can also use the method
It writes a string to the underlying output stream using UTF-8 encoding in a ma-
chine independent manner. The method
void writeInt(int v)
writes an int to the underlying output stream as four bytes, high byte first. The
method
void writeDouble(double v)
8.2 Examples
We show how to write an int, char, String, and boolean to a file. Then we read
the contents back and display it. The file name is myout.dat.
// WriteTo.java
import java.io.*;
import java.util.*;
output.flush(); output.close();
int y;
char d;
String t;
boolean bool;
DataInputStream input =
new DataInputStream(new FileInputStream("myout.dat"));
y = input.readInt();
d = input.readChar();
t = input.readUTF();
bool = input.readBoolean();
input.close();
}
}
8.2. EXAMPLES 183
// FileExc.java
import java.io.*;
import java.lang.Exception;
DataOutputStream output;
try
{
output = new DataOutputStream(new FileOutputStream("mydata.dat"));
output.writeInt(i);
output.writeUTF(name1);
output.writeDouble(x);
output.writeUTF(name2);
output.writeInt(j);
try
{
output.flush(); output.close();
}
catch(IOException e)
{
System.err.println("File not opened properly\n" + e.toString());
System.exit(1);
}
}
catch(IOException e)
184 CHAPTER 8. FILE MANIPULATIONS
{
System.err.println("File not opened properly\n" + e.toString());
System.exit(1);
}
try
{
DataInputStream in;
boolean moreRecords = true;
try
{
m = in.readInt();
System.out.println("m = " + m);
name3 = in.readUTF();
System.out.println("name3 = " + name3);
y = in.readDouble();
System.out.println("y = " + y);
name4 = in.readUTF();
System.out.println("name4 = " + name4);
n = in.readInt();
System.out.println("n = " + n);
}
catch(EOFException eof)
{
moreRecords = false;
}
catch(IOException e)
{
System.err.println("Error during read from file\n" + e.toString());
System.exit(1);
}
}
catch(IOException e)
{
System.err.println("File not opened properly\n" + e.toString());
System.exit(1);
}
}
}
8.2. EXAMPLES 185
In the following program we use a for loop to write data of data type double to
a file. Then we read the data back using a while loop. Exception handling is
included.
// FileMani.java
import java.io.*;
import java.lang.Exception;
try
{
output = new DataOutputStream(new FileOutputStream("timeev.dat"));
int T = 10;
double x0 = 0.618;
double x1;
output.writeDouble(x0);
System.out.println("The output is " + x0);
int t;
try
{
output.flush();
output.close();
}
catch(IOException e)
{
System.err.println("File not closed properly\n" + e.toString());
System.exit(1);
}
186 CHAPTER 8. FILE MANIPULATIONS
catch(IOException e)
{
System.err.println("File not opened properly\n" + e.toString());
System.exit(1);
}
System.out.println("\nReading file:");
try
{
FileInputStream fin = new FileInputStream("timeev.dat");
DataInputStream in = new DataInputStream(fin);
while(true)
System.out.print(in.readDouble() + " ");
}
catch(Exception e) { }
}
}
8.2. EXAMPLES 187
In the following three programs we show how the method readLine() in class
BufferedReader is used. In the first program we read in the file as a string using
readLine() from the class BufferedReader. The ASCII file test.dat contains
The class StringTokenizer allows an application to break a string into tokens. The
method String nextToken() returns the next token from this string tokenizer.
// FileIn.java
import java.io.*;
import java.util.*;
import java.math.*;
String s = tokenizer.nextToken();
s = tokenizer.nextToken();
System.out.println("s = " + s);
s = tokenizer.nextToken();
int i = new Integer(s).intValue();
System.out.println("i = " + i);
s = tokenizer.nextToken();
BigInteger bi = new BigInteger(s);
System.out.println("bi = " + bi);
fin.close();
}
}
188 CHAPTER 8. FILE MANIPULATIONS
The following program finds the number of lines in the file data.dat. For example
if the file data.dat contains the lines
xxx yyy
123
olloo illi
the output will be 3. In Java the null keyword is used to identify a variable as not
referencing any object. The null keyword cannot be assigned to a variable that
is declared with a basic data type. It is left as an exercise to include exception
handling for the program.
// NoOfLines.java
import java.io.*;
import java.util.*;
int count = 0;
while(in.readLine() != null)
{
count++;
}
System.out.println("count = " + count);
} // end main
}
8.2. EXAMPLES 189
The following program counts the number of occurrences of the name Miller in the
file data.dat. All the lines in the file data.dat are read using the command
// NoOfNames.java
import java.io.*;
import java.util.*;
int count = 0;
String buffer;
while(tok.hasMoreTokens())
{
String s = tok.nextToken();
if(s.equals(name))
count++;
}
}
System.out.println("Name " + name + " occurse " + count + " times");
}
}
190 CHAPTER 8. FILE MANIPULATIONS
In the following three programs we show how readByte is used in file manipulation.
A file can be considered as a sequence of bytes.
In the following program we read in the file character by character or more precisly
byte by byte. Then we do type conversion to char. Everytime we read a byte
we test for the end of the file. This is done with the method available(). The
program counts the number of characters in the file.
// EndOfFile.java
import java.io.*;
try
{
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream("EndOfFile.java")));
while(in.available() != 0)
{
System.out.print((char) in.readByte()); // type conversion
count++;
}
in.close();
} // end try block
catch(IOException e)
{
System.err.println("IOException");
}
In the following program we find the number of curly brackets to the left { and
number of curly brackets to the right } in a file. This program can be used to check
for Java, C and C++ programs whether the number of left and right curly brackets
match. We recall that the curly bracket to the left { indicates a block begin and a
curly bracket to the right } indicates a block end.
// Oops.java
import java.io.*;
try
{
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream("Oops.java")));
while(in.available() != 0)
{
char c = (char) in.readByte();
catch(IOException e)
{ System.err.println("IOException"); }
In the following program we find the checksum (modulo 65535) of a file using the
ASCII table. Again we read the data input stream byte by byte.
// ReadFile.java
import java.io.*;
try
{
DataInputStream in =
new DataInputStream(
new BufferedInputStream(
new FileInputStream("ReadFile.java")));
while(in.available() != 0)
{
c = (char) in.readByte();
checksum += (int) c; // type conversion ASCII table
while(checksum > 65535)
{
checksum -= 65535;
}
System.out.print(c);
count++;
}
}
catch(IOException e)
{
System.err.println("Error readin file");
}
import java.io.*;
class Copy
{
static public void main(String[] args)
{
if(args.length != 2)
{
System.out.println("Usage: java Copy inputfile outputfile");
System.exit(0);
}
FileInputStream fin = null;
FileOutputStream fout = null;
try
{
fin = new FileInputStream(args[0]);
fout = new FileOutputStream(args[1]);
int inputByte = fin.read();
while(inputByte != -1)
{
fout.write((byte) inputByte);
inputByte = fin.read();
}
} // end try
catch(EOFException eofError) { }
catch(FileNotFoundException notFoundError)
{ System.err.println("File " + args[0] + " not found!"); }
catch(IOException ioError)
{ System.err.println(ioError.getMessage()); }
finally
{
try
{
if(fin != null) fin.close();
if(fout != null) fout.close();
}
catch(IOException error) { }
} // end finally
} // end main
}
194 CHAPTER 8. FILE MANIPULATIONS
// WriteLine.java
import java.io.*;
DataOutputStream dos =
new DataOutputStream(new FileOutputStream("out2.dat"));
String t1 = new String("willi");
dos.writeUTF(t1);
dos.flush(); dos.close();
}
}
void update(byte[] b)
8.3. FILEREADER AND FILEWRITER 195
updates checksum with specified bytes. In the String class we have the method
byte[] getBytes()
which converts this String into bytes according to the platform’s default character
encoding, storing the result into a a new byte array. The method
public long getValue()
is in class CRC32 and returns a CRC-32 value.
In the following two programs we show how the classes FileReader, BufferedReader,
FileWriter, BufferedWriter and CRC32 can be used.
// WriteSum.java
import java.io.*;
import java.util.zip.CRC32;
bw.write(Integer.toString(stringlist.length));
bw.newLine();
int i = 0;
while(i < stringlist.length)
{
String name = stringlist[i];
bw.write(name);
bw.newLine();
sum.update(name.getBytes());
i++;
}
bw.write(Long.toString(sum.getValue()));
bw.newLine();
bw.close();
} // end main
}
196 CHAPTER 8. FILE MANIPULATIONS
// ReadSum.java
import java.io.*;
import java.util.zip.CRC32;
int i = 0;
while(i < len)
{
stringlist[i] = br.readLine();
sum.update(stringlist[i].getBytes());
i++;
}
long cs = Long.parseLong(br.readLine());
br.close();
if(cs != sum.getValue())
{
System.err.println("bad checksum");
}
else
{
for(i=0; i < len; i++)
{
System.out.println(stringlist[i]);
}
}
} // end main
}
8.4. FILE CLASS 197
The File class can be used to open an disc file and write and read data to the file.
It also provides information about the file. There are three constructors in the class.
In the constructor
File(String)
the String is a file path name which is converted to an abstract path name. In the
constructor
File(File parent,String child)
the parent is a directory which contains the child file. In the constructor
File(String parent,String child)
the parent directory is specified as a String and contains the child file.
Furthermore the class has the methods boolean mkdir() to create the directory
named by this abstract pathname and boolean delete() which deletes the file or
directory denoted by this abstract pathname.
and
The Linux operating system is made up of several directories and many different
files. The /dev directory contains special files known as device files. These files are
used to access all of the different types of hardware on our Linux system.
// FileClass.java
import java.io.*;
if(!f.exists())
{
tempFile = f.createNewFile();
System.out.println("try to create temp file");
}
if(f.exists()) printFileDetails(f);
else
System.out.println("File does not exist and cannot be created");
if(tempFile)
{
deleted = f.delete();
if(deleted) System.out.println("temp file deleted");
else System.out.println("temp file not deleted");
}
} // end constructor FileClass
{
System.out.println("File name: " + f.getName());
System.out.println("Absolute File: " + f.getAbsoluteFile());
System.out.println("Path: " + f.getAbsolutePath());
System.out.println("File length: " + f.length());
To obtain the properties of a file or directory one uses Java’s File class. For example,
the following code displays the directory tree of the file system. Recursion is used
for the method subTree(). After compiling the file DirTree we run the program
with
// DirTree.java
import java.io.*;
class DirTree
{
static int nDir, nFiles; // number of directories, files
if(!root.exists())
{
System.err.println("directory " + root + " not found");
System.exit(0);
}
subTree(root,"");
System.out.println(nDir + " directories with " + nFiles + " files");
} // end main
{
String entryName = root.getAbsolutePath() + File.separatorChar
+ dirList[entryNo];
Finally we show how the File class can be used to copy a file.
// Copy1.java
import java.io.*;
return;
}
try
{
FileInputStream src = new FileInputStream(src_f);
FileOutputStream dst = new FileOutputStream(dst_f);
byte[] buffer = new byte[512];
while(true) {
int count = src.read(buffer);
if(count == -1) break;
dst.write(buffer,0,count);
}
src.close();
dst.close();
} catch(IOException e) {
System.out.println("error during copy: " + e.getMessage());
if(dst_f.exists()) dst_f.delete();
}
}
}
8.5. SERIALIZATION 203
8.5 Serialization
When we save object information to a file without serialization, we can only save
the ASCII version of the data held by the object. We have to reconstruct the data
into objects when we read the text file, which means we have to indicate that cer-
tain data is associated with certain objects and that certain objects are related.
This is time consuming and error prone. Java 1.1 onwards supports the powerful
feature of object serialization which allows to serialize objects of any class which
implements the Serializable interface. Furthermore if our class subclasses other
classes, all inherited data fields are serialized automatically. Serialization allows
to create persistent objects, that is, objects that can be stored in a file and then
reconstituted for later use. For example, if we want to use an object with a pro-
gram and then use the object again with a later invocation of the same program.
Declaring a member transient tells Java that this member should not be serialized.
// StringsToStore.java
import java.io.*;
// Transient.java
import java.io.*;
// Book.java
import java.io.*;
// WriteBook.java
import java.io.*;
class WriteBook
{
public static void main(String[] args)
{
Book b = new Book("SymbolicC++","Steeb",1852332603);
ObjectOutputStream oos = null;
try
{
oos = new ObjectOutputStream(new FileOutputStream("Book.ser"));
oos.writeObject(b);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if(oos != null)
{
try { oos.flush(); }
catch(IOException ioe) { }
try { oos.close(); }
catch(IOException ioe) { }
} // end if
} // end finally
} // end main
} // end class
206 CHAPTER 8. FILE MANIPULATIONS
// ReadBook.java
import java.io.*;
class ReadBook
{
public static void main(String[] args)
{
ObjectInputStream ois = null;
try
{
ois = new ObjectInputStream(new FileInputStream("Book.ser"));
Object o = ois.readObject();
System.out.println("Read object " + o);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if(ois != null)
{
try
{
ois.close();
}
catch(IOException ioe)
{ }
} // end if
} // end finally
} // end main
} // end class
8.5. SERIALIZATION 207
ObjectInputStream
Persistent storage of objects can be accomplished by using a file for the stream.
The class Book represents data we would like to make persistent. We want to
archive it to disk and reload in a later session. We had to declare that the Book
class implements the
java.io.Serializable
interface. The Serializable interface does not have any methods. It is simply a
signal interface that indicates to the Java virtual machine that we want to use the
default serialization mechanism.
javac Book.java
javac WriteBook.java
to get the file WriteBook.class. Then we run this file. WriteBook creates an
ObjectOutputStream
for the Book object and writes it to a FileOutputStream named Book.ser. This
means it formats the object as a stream of bytes and saves it in the file Book.ser.
Next we compile the file ReadBook.java
javac ReadBook.java
java ReadBook
The meaning of the modifier transient is that it is not part of the persistent state
of an object.
208 CHAPTER 8. FILE MANIPULATIONS
The extension to arrays is given in the next programs. We also add as an other
attribute to Book the price as a floating point number.
// Book.java
import java.io.*;
// WriteBook.java
import java.io.*;
import Book;
class WriteBook
{
public static void main(String[] args)
{
Book[] b = new Book[2];
b[0] = new Book("SymbolicC++","Steeb",(float) 123.45);
b[1] = new Book("Workbook","Willi",(float) 45.60);
ObjectOutputStream oos = null;
try
{
oos = new ObjectOutputStream(new FileOutputStream("Book.ser"));
oos.writeObject(b[0]);
oos.writeObject(b[1]);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if(oos != null)
{
try { oos.flush(); }
catch(IOException ioe) { }
try { oos.close(); }
catch(IOException ioe) { }
} // end if
} // end finally
} // end main
} // end class
210 CHAPTER 8. FILE MANIPULATIONS
// ReadBook.java
import java.io.*;
class ReadBook
{
public static void main(String[] args)
{
ObjectInputStream ois = null;
try
{
ois = new ObjectInputStream(new FileInputStream("Book.ser"));
Object[] o = new Object[2];
o[0] = ois.readObject();
o[1] = ois.readObject();
for(int i=0; i < o.length; i++)
System.out.println("Read object: " + o[i]);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
if(ois != null)
{
try
{
ois.close();
}
catch(IOException ioe)
{ }
} // end if
} // end finally
} // end main
} // end class
8.6. GZIP AND ZIP COMPRESSION 211
constant identifies the magic number of the GZIP header. Magic numbers are used
to uniquely identify files of a given format. The GZIPInputStream() constructor
allow the InputStream object and the input buffer size to be specified.
The size of the compressed file myfile.gz is 390 bytes compared to the size of 733
bytes of the original file Graph2D1.java.
// GZIP.java
import java.io.*;
import java.util.zip.*;
{
BufferedReader in1 =
new BufferedReader(
new FileReader(args[0]));
BufferedOutputStream out =
new BufferedOutputStream(
new GZIPOutputStream(
new FileOutputStream("myfile.gz")));
System.out.println("writing file");
int c;
while((c = in1.read()) != -1)
out.write(c);
in1.close();
out.close();
System.out.println("reading file");
BufferedReader in2 =
new BufferedReader(
new InputStreamReader(
new GZIPInputStream(
new FileInputStream("myfile.gz"))));
String s;
while((s = in2.readLine()) != null)
System.out.println(s);
}
catch(Exception e)
{
e.printStackTrace();
}
} // end main
}
8.6. GZIP AND ZIP COMPRESSION 213
The next two programs show the application of these classes, their methods and
data fields.
// MyZip.java
//
// use: java MyZip FileName.zip FileName.txt
import java.io.*;
import java.util.*;
import java.util.zip.*;
for(int i=1;i<args.length;i++)
{
System.out.println(args[i]);
try
{
byte[] b = new byte[1];
ZipEntry ze = new ZipEntry(args[i]);
FileInputStream is = new FileInputStream(args[i]);
f.putNextEntry(ze);
while(is.available()>0)
{
is.read(b);
f.write(b,0,1);
}
214 CHAPTER 8. FILE MANIPULATIONS
f.closeEntry();
is.close();
}
catch(Exception e)
{
System.out.println("Exception "+e.toString());
}
}
f.close();
}
catch(Exception e)
{
System.out.println("Exception "+e.toString());
}
}
}
// MyUnzip.java
//
// use: java MyUnzip FileName.zip
import java.io.*;
import java.util.*;
import java.util.zip.*;
System.out.println(ze.toString());
while(is.available()>0)
8.6. GZIP AND ZIP COMPRESSION 215
{
b[0]=(byte)is.read();
os.write(b,0,1);
}
is.close();
os.close();
}
catch(Exception e)
{
System.out.println("Exception "+e.toString());
}
}
else
for(int i=1;i<args.length;i++)
{
try
{
ZipEntry ze = f.getEntry(args[i]);
InputStream is = f.getInputStream(ze);
FileOutputStream os = new FileOutputStream(ze.getName());
System.out.println(ze.toString());
while(is.available()>0)
{
b[0] = (byte)is.read();
os.write(b,0,1);
}
is.close();
os.close();
}
catch(Exception e)
{
System.out.println("Exception "+e.toString());
}
}
}
catch(Exception e)
{
System.out.println("Exception "+e.toString());
}
}
}
216 CHAPTER 8. FILE MANIPULATIONS
JPEG codec encodes bitmaps as JPEG files. JPEG is designed for compressing ei-
ther full-color or gray-scale images of natural, real-world scenes. JPEG handles only
still images, but there is a related standard called MPEG for motion pictures. The
fundamental advantage of JPEG is that it stores full color information: 24bits/pixel
(16 million colors). GIF, the other image format widely used on the net, can only
store 8bits/pixel (256 colors or fewer colors).
3) Save the BufferedImage into a file using the JPEG package and FileOutputStream.
The following program shows an application. It stores the phase portrait of the
Ikeda Laser map as a jpg file. The data field TYPE_INT_RGB represents an image
with 8-bit RGB Color Components packed into integer pixels.
// JPEG1.java
import com.sun.image.codec.jpeg.*;
import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
public JPEG1()
{
bi = new BufferedImage(400,400,BufferedImage.TYPE_INT_RGB);
g2 = bi.createGraphics();
try
{
FileOutputStream jpegOut = new FileOutputStream("output.jpg");
JPEGImageEncoder jie = JPEGCodec.createJPEGEncoder(jpegOut);
jie.encode(bi);
jpegOut.close();
System.exit(0);
}
catch(Exception e) { }
} // end constructor JPEG1()
8.8 Internationalization
With Internationalization our Java program can be adapted to various languages
and regions without code changes. The term Internationalization is abbreviated as
I18N, since there are 18 letters between the first I and the last N. Support for new
languages does not require recompilation or code changes.
In the following two programs we show how Internationalization works. In the first
example we have a JFrame with two buttons Yes and No. We want these buttons to
display Ja and Nein for its German version and Oui and No for its French version.
First we write an ASCII file (text file) with the contents
yesMessage=Yes
noMessage=No
and save this file as Messages_en_UK.properties. The we write another ASCII file
for the German version
yesMessage=Ja
noMessage=Nein
yesMessage=Oui
noMessage=No
java I18N de DE
or
java I18N fr FR
and so on.
8.8. INTERNATIONALIZATION 219
// I18N.java
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
yesCaption = captions.getString("yesMessage");
noCaption = captions.getString("noMessage");
getContentPane().add(yesButton,BorderLayout.WEST);
getContentPane().add(noButton,BorderLayout.EAST);
} // end default constructor
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{ System.exit(0); }
});
frame.setBounds(0,0,200,100);
frame.setVisible(true);
} // end main
}
greetings=Hello
inquiry=How are you?
farewell=Goodbye
greetings=Hallo
inquiry=Wie geht es Ihnen?
farewell=Auf Wiedersehen
greetings=Bonjour
inquiry=Commet allez-vous?
farewell=Au revoir
// I18N1.java
import java.util.*;
if(args.length != 2)
{
language = new String("en");
country = new String("GB");
}
else
{
language = new String(args[0]);
country = new String(args[1]);
}
Locale currentLocale;
ResourceBundle messages;
System.out.println(messages.getString("greetings"));
System.out.println(messages.getString("inquiry"));
System.out.println(messages.getString("farewell"));
} // end main
}
222 CHAPTER 8. FILE MANIPULATIONS
We compile the program LockFile.java which accesses the file data.dat for read
and write. Then we run the program. The program gets an exclusive lock on the
file data.dat, reports when it has the lock, and then waits until we press the Enter
key. Before we press the Enter key we start a new process by compiling and running
the program NoOfLines.java. This program counts the numbers of lines in the file
data.dat. Since the file data.dat is locked it cannot access the file only after we
press the Enter key in the first process. Then the lock is released.
// LockFile.java
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
// NoOfLines.java
import java.io.*;
import java.util.*;
int count = 0;
while(in.readLine() != null)
{
count++;
}
System.out.println("count = " + count);
} // end main
}
224 CHAPTER 8. FILE MANIPULATIONS
1) key generation
2) signature creation
3) signature verification
DSA is a public key algorithm; the secret key operates on the message hash gen-
erated by SHA-1; to verify a signature, one recomputes the hash of the message,
uses the public key to decrypt the signature and then compare the results. The
key size is variable from 512 to 1024 bits which is adequate for current computing
capabilities as long as we use more than 768 bits. Signature creation is roughly
the same speed as with RSA, but is 10 to 40 times as slow for verification. How-
ever, these numbers depend partially on the assumptions made by the benchmarker.
Since verification is more frequently done than creation, this is an issue worth noting.
The only known cracks (forgery) are easily circumvented by avoiding the particular
moduli (prime factor of p−1 where p is the public key) that lead to weak signatures.
DSS is less susceptible to attacks than RSA; the difference is that RSA depends on
a secret prime while DSA depends on a public prime. The verifier can check that
the prime number is not a fake chosen to allow forgery. It is possible to implement
the DSA algorithm such that a “subliminal channel” is created that can expose key
data and lead to forgable signatures so one is warned not to used unexamined code.
8.10. SECURITY API, SIGNATURE AND DSA ALGORITHM 225
KeyPairGenerator
is used to generate pairs of public and private keys. Key pairs generators are con-
structed using the getInstance() factory method. The Signature class is used
to provide applications the functionality of a digital signature algorithm. Digital
signature are used for the authorization and integrity assurance of digital data. The
method
byte[] sign()
returns the signature bytes of all the data updated. The method
void initSign(PrivateKey)
initializes this object for signing. The interface PrivateKey merely serves to group
(and provide type safety for) all private key interfaces. The method
boolean verify(byte[])
For the following example assume that we have a text file data.dat containing the
line
amount: 2000
then the program stops and waits for input from the keyboard. If we change at this
stage the file data.dat, for example to
amount: 3000
The program is
// MySignature.java
import java.io.*;
import java.security.*;
class MySignature
{
public static void main(String[] args)
{
try {
// generate a key pair
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
keyGen.initialize(1024,new SecureRandom());
KeyPair pair = keyGen.generateKeyPair();
// sign it
byte[] sig = dsa.sign();
while(fis.available() != 0) {
b = (byte) fis.read();
dsa.update(b);
} // end while
fis.close();
boolean verifies = dsa.verify(sig);
System.out.println("signature verifies: " + verifies);
} // end main
}
Chapter 9
Threads
9.1 Introduction
Multitasking and multithreading are two types of concurrencies. Multitasking refers
to the ability of executing more than one program at the time. It is usually supported
on the operating system level. Multithreading, on the other hand, refers to a single
pogram which has more than one execution thread running concurrently. Each of
these independent subtasks is called a thread. An execution thread refers to the
execution of a single sequence of instructions. In Java support for multithreaded
programmming is built into the language.
Threads are sequences of code that can be executed independently alongside one
another. The Java Virtual Machine allows an application to have multiple threads
of execution running concurrently. Thus a thread is an independent sequential flow
of control within a process. Threads run with programs. A single application or
applet can have many threads doing different things independently. The Thread
class is defined in java.lang as a subclass of the Object class. To use Threads
in a program, one needs to define a local subclass of the Thread class and therein
override its void run() method. We put the code that we want the threads of that
subclass to execute in that void run() method.
There are two ways in which to initiate a new thread of execution. The first is to
create a subclass of the Thread class and redefine the run() method to perform the
set of actions that the thread is intended to do. The second one is to define a new
class that implements the Runnable interface. It must define the run() method and
can be started by passing an instance of the class to a new Thread instance. In both
cases we define a class which specifies the operations or actions that the new thread
(of execution) performs.
228
9.1. INTRODUCTION 229
1) New: the thread object has been created but it has not been started yet so it
cannot run.
2) Runnable: this means that a thread can be run when the time-slicing mecha-
nism has CPU cycles available for the thread. Thus, the thread might or might not
be running, but there is nothing to prevent it from being run if the scheduler can
arrange it. It is not dead or blocked.
3) Dead: the normal way for a thread to die is by returning from its run() method.
4) Blocked: the thread could be run but there is something that prevents it. While
a thread is in the blocked state the scheduler will simply skip over it and not give
any CPU time. Until a thread re-enters the runnable state it will not perform any
operations. A thread can be blocked for five reasons. First we have put the thread
to sleep by calling the method sleep(milliseconds), in which case it will not be
run for the specified time. Second we have suspended the execution of the thread by
calling the method suspend(). It will not become runnable again until the thread
gets the resume() message. Third we have suspended the execution of the thread
with the method wait(). The method
waits to be notified by another thread of a change in this object. It will not become
runnable again until the thread gets the notify() or notifyAll() message. The
method
wakes up a single thread that is waiting on this object’s monitor. A thread waits
on an object’s monitor by calling one of the wait methods. The method
wakes up all threads that are waiting on this object’s monitor. A thread waits
on an object’s monitor by calling one of the wait methods. Fourth the thread is
waiting for some Input/Output to complete. Finally the thread is trying to call
a synchronized method on another object and that object’s lock is not available.
The keyword synchronized indicates that while a method is accessing an object,
other synchronized methods are blocked from accessing that object.
230 CHAPTER 9. THREADS
void start()
method in class Thread causes this thread to begin execution. The Java Virtual
Machine calls the run() method of this thread. The Runnable interface has a single
method called run(). The class which implements the Runnable interface must
therefore supply its own run() method. Starting a thread causes the run() method
to be executed. This method is executed for a brief time and then another thread
of the application is executed. This thread runs briefly and is then suspended so
another thread can run and so on. If this thread was constructed using a separate
Runnable object, then that Runnable object’s run() method is called; otherwise,
this method does nothing and returns. The method
in the Thread class causes the currently executing thread to sleep (temporarily cease
execution) for the specified number of milliseconds. The method
void yield()
causes the currentlty executing thread object to temporarily pause and allow other
threads to execute. The method
void destroy()
There are a number of methods in the class Thread that provide information about
the status of the process. The method
boolean isAlive()
tests to see if the thread has started execution. On the other hand the method
boolean isInterrupted()
Every thread has a unique name. If we do not provide one, then a name is auto-
matically generated by the system. There are two methods that access and set a
thread’s name. The method
String getName() // in Thread class
9.2. THREAD CLASS 231
The field
The methods
are deprecated. Instead of using the stop() method, it is recommended that threads
monitor their execution and stop by returning from their run() method.
void repaint()
inside the run() method. The method repaint() is in class Component. It repaints
this component, i.e. it calls the method paint(). The method paint() is in class
Component. It paints this component. The method
repaints the component. This will result in a call to update() within tm milliseconds,
i.e. tm is the maximum time in milliseconds before update.
232 CHAPTER 9. THREADS
9.3 Examples
In our first two examples we implement two balls one moving in x direction the
other in y direction. In the first program for loops are used to pass the time. In
the second program we use the Calendar class.
// MoveBalls1.java
import java.awt.Graphics;
import java.awt.*;
import java.applet.Applet;
// MoveBalls2.java
import java.awt.Graphics;
import java.awt.*;
import java.applet.Applet;
import java.util.Calendar;
In our third example we define a new class called Counter that implements the
Runnable interface. It defines a run() method and will be started by passing an
instance of the class to a new Thread instance.
// Counter.java
import java.awt.*;
import java.applet.*;
<HTML>
<COMMENT> Counter.html </COMMENT>
public TestThread(String s)
{
super(s);
sleepTime = (int) (500*Math.random());
System.out.println("Name: " + getName() + "\t Sleep: " + sleepTime);
} // end constructor TestThread
} // end main
} // end class MyThread
236 CHAPTER 9. THREADS
A typical output is
first run:
Name: 0 Sleep: 223
Name: 1 Sleep: 55
Name: 2 Sleep: 401
Name: 3 Sleep: 482
Thread 0
Thread 2
Thread 3
Thread 1
second run
Name: 0 Sleep: 36
Name: 1 Sleep: 145
Name: 2 Sleep: 345
Name: 3 Sleep: 290
Thread 0
Thread 3
Thread 1
Thread 2
9.4. PRIORITIES 237
9.4 Priorities
The priority of a thread tells the scheduler how important this thread is. If there
are a number of threads blocked and waiting to be run, the scheduler will run
the one with the highest priority first. However, this does not mean that threads
with lower priority do not get run. This means we cannot deadlocked because of
priorities. Lower priority threads just tend to run less often. In Java we can read the
priority of a thread with the method getPriority() and change it with the method
setPriority(). The following program shows an application of these methods.
// Bounce.java
import java.awt.*;
import java.awt.event.*;
public Bounce()
{
setTitle("BouncingBalls");
addWindowListener(this);
b = new Button("Close");
b.addActionListener(this);
panel.add(b);
} // end constructor Bounce()
238 CHAPTER 9. THREADS
Any method can be preceded by the word synchronized. The rule is: no two
threads may be executing synchronized methods of the same object at the same
time. The Java system enforces this rule by associating a monitor lock with each
object. When a thread calls a synchronized method of an object, it tries to grab the
object’s monitor lock. If another thread is holding the lock, it waits until that thread
releases it. A thread releases the monitor lock when it leaves the synchronized
method. Of one synchronized method of a call contains a call to another, a thread
may have the same lock multiple times. Java keeps track of that correctly.
Thus there is a lock with every object. The synchronized statement computes a
reference to an object. It then attempts to perform a lock operation on that object
and does not proceed further until the lock operation has successfully completed. A
lock operation may be delayed because the rules about locks can prevent the main
memory from participating until some other thread is ready to perform one or more
unlock operations. After the lock operation has been performed, the body of the
synchronized statement is executed. Normally, a compiler ensures that the lock
operation implemented by a monitorenter instruction executed prior to the execu-
tion of the body of the synchronized statement is matched by an unlock operation
implemented by a monitorexit instruction whenever the synchronized statement
completes, whether completion is normal or abrupt. The Java Virtual Machine pro-
vides separate monitorenter and monitorexit instructions that implements the lock
and unlock operations.
In the following program we start two threads f1 and f2. The method display()
is synchronized. The output the program Synchronized.java is
in the program to
void display()
the output is
// Synchronized.java
Synchronized()
{
f1 = new Count(this);
f2 = new Count(this);
f1.start();
f2.start();
} // end constructor Synchronized
Count(Synchronized thread)
{
current = thread;
}
// BankAccount.java
// Transfer.java
import BankAccount;
t.start();
Thread.yield(); // the thread on which yield() is invoked would
// move from running state to ready state
public BankAccount A, B;
public double amount;
Producer.java
Consumer.java
Buffer.java
Main.java
give a solution to this problem. The methods wait() and notify() are in the class
Object. Class Object is the root of the class hierarchy. Every class has Object
as a superclass. All objects, including arrays, implement the methods of this class.
The method wait() causes the current thread to wait until another thread invokes
the notify() method or the notifyAll() method for this object. The method
notify() wakes up a single thread that is waiting on this object’s monitor. If any
threads are waiting on this object, one of them is chosen to be awakend. The choice
is arbitrary and occurs at the discretion of the implementation. A thread waits on
an object’s monitor by calling one of the wait methods.
// Producer.java
public Producer(Buffer b)
{
buffer = b;
}
buffer.put(i);
System.out.println("Producer put: " + i);
try
{
sleep((int) (Math.random()*100));
}
catch(InterruptedException e) { }
}
}
}
// Consumer.java
public Consumer(Buffer b)
{
buffer = b;
}
// Buffer.java
while(available == false)
{
try
{
wait();
}
catch(InterruptedException e) { }
}
available = false;
notify();
return contents;
}
// Main.java
9.7 Deadlock
Deadlock is a mutual starvation between at least two threads that cannot satisfy each
other. We cause deadlock between two threads that are both trying to acquire locks
for the same two resources. To avoid this sort of deadlock when locking multiple
resources, all threads should always acquire their locks in the same order. There are
two resource objects (strings) we will try to get locks for. The first thread tries to
lock resource1 then resource2. The second thread tries to lock resource2 and then
resource1.
// MyDeadLock.java
// first thread
Thread t1 = new Thread() {
public void run() {
// Lock resource 1
synchronized(resource1) {
System.out.println("Thread 1: locked resource 1");
// Pause for a bit something.
// We give the other thread a chance to run.
// Threads and deadlock are asynchronous things,
// but we are trying to force deadlock to happen here.
try {
Thread.sleep(50);
} catch(InterruptedException e) { }
// second thread
Thread t2 = new Thread() {
public void run() {
// This thread locks resource 2 right away
9.7. DEADLOCK 249
synchronized(resource2) {
System.out.println("Thread 2: locked resource 2");
// Then it pauses, for the same reason as the first
// thread does
try {
Thread.sleep(50);
} catch(InterruptedException e) {}
and then the program freezes up. Using the debugger jdb and run we get
Animation
10.1 Introduction
Animation involves changing a picture over and over to simulate movement of some
sort. There are several different types of animation we can perform in a Java ap-
plet. We can display a sequence of images, or we can display a single image while
changing a portion of it. We can change an image by running it through a filter
of by changing the colours in the image. We can also perform animation with the
basic graphics classes.
Animation is a powerful technique for applets. Having a portion of our display that
moves can make our application or our Web page much livelier.
Animation is frequently used in video games. In facet, it is probably one of the most
common factors in computer games. Modern adventure games often use sequences
of real-life images to give the game a modern feel. Arcade games frequently employ
graphical animation, although some have begun to integrate images into the games
as well.
250
10.1. INTRODUCTION 251
Like Web browsers, Java is designed to handle graphics files in two formats - GIF
(including animated GIFs) with extension .gif and JPEG (with either a .jpeg or
a .jpg extension).
JPEG stands for Joint Photographic Experts Group. Java cannot cope with the
standard Windows formats BMP and PCX. If we want to create our own images,
we need a suitable graphics application, such as Paint ShopPro or CorelDraw. Corel-
Draw allows then to convert the .cdr file into a .gif or .jpg file. We can use this
for drawing new images, or for converting pictures created in Paint ShopPro or
CorelDraw or almost anywhere else - into the GIF and JPEG formats.
GIF files are significantly smaller than JPEG files, and therefore faster to load - an
important consideration, especially where files have to be transferred over the World
Wide Web. The main reason why JPEG files are larger is that they have palettes of
An animated GIF is a set of images, which are displayed in sequence, with a de-
fined delay between each. They are used in exactly the same way as still images
- the animation is entirely built into the image file, so all Java has to do is dis-
play it. The files tend to be large, and that the animation speed is defined within
the GIF. There are plenty of ready-made animated GIFs freely available on the Web.
JDK 1.1 provided the capability for applets to play audio files that were in the
SunAudio (.au) format. JDK 1.2 provides a new sound engine that allows audio
files to be played by both applets and applications. The sound engine also provides
support for the Musical Instrument Digital Interface (MIDI), the Microsoft Windows
audio format (WAVE), the Rich Music Format (RMF), and the Audio Interchange
File Format (AIFF).
252 CHAPTER 10. ANIMATION
is the superclass of all classes that represent graphical images. The image must be
obtained in a platform-specific manner. The method
in class Applet returns an Image object that can be painted on the screen. Thus
method getImage() takes as its parameter a URL - Uniform Resource Locator - the
standard means of identifying a file anywhere on the Internet or in a computer. The
method
URL getCodeBase()
in class Applet gets the base URL. This is the URL of the applet itself. The easiest
way to handle the URL is with the method getCodeBase(). This works out the URL
of the directory in which the program is stored. If the image file is in the same
directory, then we would simply follow it up with the filename. If the file is in a
sub-directory, we also need to add its name. The method getCodeBase() will give
the right URL when the files are on our system and when they are uploaded to our
Web space on our access provider’s server. The method getDocumentBase() returns
the URL of the Web page in which the applet is embedded.
If the image file is stored in a completely different place from the code, then we have
to define the URL using the java.net.URL class. This throws an exception that we
must catch. For example
import jave.net.*;
try
{
pic = getImage(new URL("http://zeus.rau.ac.za/diploma/globe.gif"));
}
catch(MalformedURLException e)
{ }
...
The address is written in full, then converted to a URL object. The catch block
might get an alternative image from a more secure source.
10.2. IMAGE CLASS AND ANIMATION 253
// Animate.java
//
// The files
// figure1.jpg figure2.jpg figure3.jpg figure4.jpg
// are in the same directory as the file
// Animate.java
import java.awt.*;
import java.applet.*;
while(animator != null)
{
i += 10;
if(i > 400) { i = 0; }
current++;
if(current > 3) current = 0;
repaint(); // repaint() calls paint()
254 CHAPTER 10. ANIMATION
try
{
Thread.sleep(100);
} // end try
catch(InterruptedException e) { }
} // end while
} // end run()
<HTML>
<APPLET CODE="Animate.class" width=275 height=135>
</APPLET>
</HTML>
import java.awt.*;
import java.applet.*;
import java.awt.Graphics;
In the following applet we have a background picture (file Image0.jpg) and a moving
picture (file Actor.jpg).
// FigMotion.java
import java.awt.*;
import java.applet.*;
Another application shows the following program, where a jpg picture is rotated
and scaled.
// Animation.java
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.*;
import java.net.URL;
}
}
AnimationCanvas(URL codeBase)
{
setBackground(Color.green);
try {
eiffelURL = new URL(codeBase,"/home/java/Eiffel_Tower.JPG");
}
catch(java.net.MalformedURLException e)
{
System.out.println("bad URL");
}
if(image.getWidth(this)==-1)
{ System.out.println("Make sure the image exists"
+ "(Eiffel_TOWER.JPG) file in the same directory");
System.exit(0);
}
{
if(thread != null) thread.interrupt();
thread = null;
}
AIFF
AU
WAV
MIDI (type 0 and type 1 file)
RMF
The .au audio clip format was developed by Sun. Windows uses the .wav format.
For testing purposes, we can use the .au files in the Audio folders of the JumpingBox
and TicTacToe demos. The
Interface java.applet.AudioClip
public abstract interface AudioClip
The sound engine can handle 8- and 16-bit audio data at virtually any sample rate.
In JDK 1.2 audio files are rendered at a sample rate of 22 kHz in 16-bit stereo. If
the hardware doesn’t support 16-bit data or stereo playback, 8-bit or mono audio
is output. The Java Sound engine minimizes the use of a system’s CPU to process
sound files. A full-featured Java Sound API is now available.
There are two ways to play sounds. The simplest uses the play() method, taking
as its parameter the URL of the file
play(getCodeBase(),"ding.au");
This loads and plays the file immediately. The alternative is to set up an AudioClip
object, load the file into there, and then play it later in the program
AudioClip music;
...
music = getAudioClip(getCodeBase(),"beep.au");
The method
void loop()
262 CHAPTER 10. ANIMATION
void play()
void stop()
// Sound1.java
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
The classes for the Java Sound demo are contained in the JavaSound.jar file. To
extract the contents of JavaSound.jar we run the command
jar xf JavaSound.jar
from the JavaSound directory. To run the Java Sound demo we enter
The JavaSound demo consists of a set of demos housed in one GUI framework that
uses JTabbedPane. We can access different groups of demos by clicking the tabs at
the top of the pane. There are demo groups for Juke Box, Capture and Playback,
Midi Synthesizer and Rhythm Groove Box. Using the Juke Box we can play sam-
pled (au, wav, aif) and midi (rmf, midi) sound files. Using Capture and Playback
we can record audio in different formats and then playback the recorded audio. The
captured audio can be saved either as a wav, au or aiff file. We can load an audio
file for streaming playback.
MIDI stands for musical instrument digitial interface. This connectivity standard
enables us to hook together computers, musical instruments, and synthesizers to
make and orchestrate digital sound. The term is used to describe the standard it-
self, the hardware that supports the standard, and the files that store information
that the hardware can use. MIDI files are like digital sheet music. They contain
instructions for musical notes, tempo, and instrumentation. They are widely used
in game soundtracks and recording studios.
AIFF stands for Audio Interchange File Format. This audio file format was developed
by Apple Computer for storing high-quality sampled audio and musical instrument
information.
WAV is the Windows standard for waveform sound files. WAV files predictably have
the extension .wav.
Juke Box: A Juke Box for sampled (au, wav, aif) and midi (rmf, midi) sound files.
Features duration progress, seek slider, pan and volume controls.
Midi Synthesizer: Illustrates general MIDI melody instruments and MIDI controllers.
A piano keyboard represents notes on and off. Features capture and playback of
note on and off events.
Rhythm Groove Box: Illustrates how to build a track of short events. Features a
tempo dial to increase or descrease the beats per minute.
// AniSoun.java
import java.awt.*;
import java.applet.*;
while(animator != null)
10.3. AUDIOCLIP CLASS 265
{
i += 10;
if(i > 400) { i = 0; }
current++;
if(current > 3) current = 0;
repaint();
try
{
Thread.sleep(100);
} // end try
catch(InterruptedException e) { }
} // end while
} // end run()
<HTML>
<APPLET CODE="AniSoun.class" width=275 height=135>
</APPLET>
</HTML>
Chapter 11
Networking
11.1 Introduction
A network client retrieves data from a server and shows it to a user. Web browsers
are limited. They can only talk to certain kinds of servers (generally Web, FTP, Go-
pher, and perhaps main and news servers). They can only understand and display
certain kinds of data (generally text, HTML, and a couple of standard image for-
mats). A web browser cannot send SQL commands to a database server to perform
interactive queries. Java programms can do this and a lot more. A Java program
embedded in an HTML page (an applet) can give a Java-enabled web browser ca-
pabilities the browser did not have to begin with.
Java programs are flexible because Java is a general programming language. Java
programs see network connections as streams of data which can be interpreted and
responded to in any way that is necessary. Web browsers see only certain kinds
of data streams and can interpret them only in certain ways. If a browser sees a
data stream that it is not familiar with (for example, a binary response to an SQL
query), its behavior is unpredictable.
Thus, a Java program can connect to a network time server to synchronize itself
with an atomic clock. A web browser cannot. A Java program can connect to an
Oracle database to ask for the salespeople for some data. A web browser cannot.
Finally, a Java program can use the full power of a modern graphical user interface
to show this data to the user.
Java includes built-in classes that connect to other Internet hosts, using the TCP
and UDP protocols of the TCP/IP family. We tell Java what IP address and port
we want, and Java handles the low-level details.
266
11.1. INTRODUCTION 267
A network is a collection of computers and other devices that can send data to
and receive data from each other, more or less in real time. A network is nor-
mally connected by wires, and the bits of data are turned into electrons that move
through the wires. However, wireless networks that transmit data through infrared
light or microwaves are beginning to appear, and many long-distance transmissions
are now carried over fiber optic cables that send visible light through glass filaments.
Each machine on a network is called a node. Most nodes are computers, but print-
ers, routers, bridges, gateways and dumb terminals. Nodes that are fully functional
computers are also called hosts. We will use the word node to refer to any device
on the network, and host to mean that subset of devices which are general-purpose
computers.
There are several different layer modes, each organized to fit the needs of a par-
ticular kind of network. Separating the network into layers lets us modify or even
replace one layer without affecting the others, as long as the interfaces between the
layers stay the same. Thus, applications talk only to the transport layer. The trans-
port layer talks only to the application layer and the Internet layer. The Internet
layer in turn talks only to the host-to-network layer and the transport layer, never
directly to the application layer. The host-to-network layer moves the data across
the wires, fiber-optic cables or other medium to the host-to-network layer on the
remote system.
1) The familiar DNS (Domain Name Service) form. The domain name of SUN is
sun.com. My domain name is whs.rau.ac.za.
2) We can also use the dotted quad form, which is four numbers separated by dots,
such as 207.25.71.25.
The Internet is not the only IP-based network, but it is the largest one. Other IP
networks are called internets with a little i; for example, a corporate IP network
that is not connected to the Internet. Intranet is a current buzzword that loosely
describes corporate practices of putting lots of data on internal web servers. Since
web browsers use IP, most intranets do too (though some tunnel it through existing
AppleTalk or IPX installations).
To make sure that hosts on different networks on the Internet can communicate with
each other, a few rules that do not apply to purely internal internets need to be fol-
lowed. The most important rules deal with the assignment of addresses to different
organizations, companies, and individuals. If everyone randomly picked the Internet
addresses they wanted, conflicts would arise when different computers showed up on
the Internet with the same address. To avoid this problem, Internet addresses are
assigned to different organizations by the Internet Network Information Center (In-
terNIC), generally acting through intermediaries called Internet Service Providers
(ISPs). When an organization wants to set up an IP-based network, they are as-
signed a block of addresses by the InterNIC. Currently, these blocks are available
in two sizes called Class B and Class C. A Class C address block specifies the first
three bytes of the address, for example, 199.1.32. This allows room for 254 individ-
ual addresses (from 1999.1.32.1 to 199.1.32.254). A Class B address block only
specifies the first two bytes of the addresses an organization may use, for instance,
167.1. Thus a Class B address has room for roughly 65,000 different hosts (in block
167.1, the hosts would have addresses from 167.1.0.1 to 167.1.255.254).
11.2 Addresses
Every network node has an IP (Internet protocoll) address: a series of bytes that
uniquely identify it. Computers connected on the Internet are called hosts. Each
host is identitfied by at least one unique 32-bit number called an Internet address,
an IP address, or a host address. We write an IP as four unsigned bytes, each
ranging from 0 to 255, with the most significant byte first. Bytes are separated by
periods for human convenience. For example
152.106.50.60
Addressing becomes important when we want to restrict access to our site. For
instance, we may want to prevent a competing company from having access to our
web site. In this case we would find out our competitor’s address block and throw
away all requests that come from there. More commonly, we might want to make
sure that only people within our organization can access our internal web servers.
In this case we would deny access to all requests except those that come from within
our own address block.
There is no available block of addresses with a size between a Class B block and a
Class C block. This has become a problem because there are many organizations
with more than 254 and less than 65,000 computers, connected to the Internet. If
each of these organizations is given a Class B address, a lot of IP addresses are
wasted. This is a problem since the number of addresses is limited to about 4.2 bil-
lion. That sounds like a lot, but it gets crowded quickly when we waste fifty or sixty
thousand addresses at a shot. The temporary solution is to assign multiple Class C
addresses to these organizations, inconvenient though this is for packet filtering and
routing.
270 CHAPTER 11. NETWORKING
Several address blocks and patterns are special. All Internet addresses beginning
with 10. and 192. are deliberately unassigned. They can be used on internal
networks, but no host using addresses in these blocks is allowed onto the global
Internet. These non-routable addresses are useful for building private networks that
can not be see from the rest of the Internet, or for building a large network when
we have only been assigned a class C address block. Addresses beginning with 127
(most commonly 127.0.0.1) always mean the local loopback address. That is, these
addresses always point to the local computer, no matter which computer we are run-
ning on. The hostname for this address is generally localhost. The address 0.0.0.0
always refers to the originating host, but may only be used as a source address, not
a destination. Similarly, any address that begins with 0.0 is assumed to refer to a
host on the same local network.
On some kinds of networks, nodes also have names that help human beings identify
them. A particular name normally refers to exactly one address. The Domain Name
System (DNS) was developed to translate hostnames that humans can remember
such as
issc.rau.ac.za
152.106.50.232
However, names are not locked to addresses. Names can change while addresses
stay the same or addresses can change while the names stay the same. It is not un-
common for one address to have several names, and it is possible, though somewhat
less common, for one name to refer to several different addresses.
When data is transmitted across the network, the packet’s header includes the ad-
dress of the machine for which the packet is intended (the destination address),
and the address of the machine that sent the packet (the source address). Routers
along the way choose the best route by which to send the packet by inpecting the
destination address. The source address is included.
To get the IP address of the host machine we enter at the command prompt the
command (Windows)
ipconfig
This provides us with the network configuration for the host machine. For example
Ethernet adapter
IP address 152.106.50.60
Subnet Mask 255.255.255.0
Default Gateway 152.106.50.240
11.2. ADDRESSES 271
Under Linux the command is ifconfig. The Linux and Windows command ping
sends echo request packets to a network host to see if it is accessible on the network.
For example
ping 152.106.50.27
When Java programs access the network, they need to process both these numeric
addresses and their corresponding hostnames. There are a series of methods for
doing this in the InetAddress class. This class contains the methods
byte[] getAddress()
static InetAddress getByName(String name)
String getHostAddress()
String getHostName()
http://zeus.rau.ac.za/diploma.html
We can access HTML files locally by replacing the http: scheme with the file:
scheme and omitting the Internet address.
In the package java.net Java provides a number of classes useful for network pro-
gramming. The classes are
272 CHAPTER 11. NETWORKING
DatagramPacket
DatagramSocket
HttpURLConnection
MulticastSocket
ServerSocket
Socket
URL
The URL class allows a URL instance to act as a reference for a resource available
either locally or via the Web. The URL class has four constructors. The constructor
creates a URL object from the specified protocol, host, port number and file. The
constructor
creates an absolute URL from the specified protocol name, host name and file name.
The constructor
creates a URL by parsing the specification spec within a specified context. The
constructor
URL(String spec)
Besides HTTP URLs we have File URLs, Gopher URLs, News URLs and others.
Suppose there is a document called mytext.txt and it sits on an anonymous ftp
server called ftp.companyxxx.com in the directory /pub/files. The URL for this
file is then
ftp://ftp.companyxxx.com/pub/files/mytext.txt
Gopher URLs are a little more complicated than file URLs, since Gopher servers
are a little tricker to deal with than FTP servers. To visit a particular gopher server
say the gopher server on gopher.companyxxx.com we use this URL
gopher://gopher.companyxxx.com/
Some gopher servers may reside on unusual network ports on their host machine.
The default gopher port number is 70. To point to a Usenet newsgroup (News
URLs) for example science.physics the URL is simply
news:science.physics
11.3. PORTS 273
11.3 Ports
Thus addresses would be all we needed if each computer did no more than one thing
at a time. However, modern computers do many different things at once. Email
needs to be separated from FTP requests, which need to be separated from web
traffic. This is accomplished through ports. Each computer with an IP address
has 216 − 1 = 65535 ports. These are provided in the computer’s memory, and do
not represent anything physical like a serial or parallel port. Each port is identified
by a number between 1 and 65535. Each port can be allocated to a particular service.
For example, the HTTP service, which is used by the Web, runs on port 80 - we
say that a Web server listens on port 80 for incoming connections. SMTP or email
servers run on port 25. When data is sent to a Web server on a particular machine
at a particlar IP address, it is also sent to a particular port (usually port 80) on
that machine. The receiver checks each packet for both the address and the port.
If the address matches, the data is sent to the program interested in data sent to
that port. This is how different types of traffic are sorted out.
Port numbers between 1 and 1023 are reserved for well-known services like finger,
FTP, HTTP, and email. On UNIX systems, we must be “root” to receive data on
one of these ports, but we may still send data to them. On Windows (including
Windows NT) and the Mac, any user may use these ports without special privileges.
Table 1 shows the well known ports for the protocols. These assignments are not
absolutely guaranteed; in particular, Web servers often run on ports other than 80,
either because multiple servers need to run on the same machine, or because the
person who installed the server doesn’t have the root privileges needed to run it on
port 80.
We should of course avoid these common ports for our applications/applets except
when specifically writing applications for these. It is generally recommended that
we use ports in the range between 4000 and 8000 for our non-standard TCP/IP
applications.
On UNIX machines, a fairly complete listing of assigned ports is stored in the file
/etc/services.
274 CHAPTER 11. NETWORKING
11.4 Examples
After we compiled the following program using javac Net1.java we enter at the
command line:
// Net1.java
import java.io.*;
import java.net.*;
for(int i=0;i<ipAddress.length;++i)
System.out.print((ipAddress[i]+256)%256+".");
System.out.println();
}
catch(UnknownHostException ex)
{
System.out.println("Unkown host");
return;
}
}
}
276 CHAPTER 11. NETWORKING
The following program finds the IP address of the local machine. If I run this
program on my machine I find: My address is: 152.106.50.60
// Net2.java
import java.net.*;
try
{
InetAddress thisComputer = InetAddress.getLocalHost();
byte[] address = thisComputer.getAddress();
System.out.println("My address is: ");
for(int i=0; i<address.length; i++)
{
int unsignedByte = address[i] < 0 ? address[i] + 256 : address[i];
System.out.print(unsignedByte + ".");
}
System.out.println();
} // end try block
catch(UnknownHostException e)
{
System.out.println("Sorry. I do not know my own address.");
} // end catch block
} // end main
}
11.4. EXAMPLES 277
In the following program we get the domain name for a given IP address in the
present case 152.106.50.232. If we run this program we find the output
issc.rau.ac.za/152.106.50.232
// Net3.java
import java.net.*;
try
{
InetAddress address = InetAddress.getByName("152.106.50.232");
System.out.println(address);
} // end try block
catch(UnknownHostException e)
{
System.out.println("Could not find 152.106.50.232");
} // end catch block
}
}
278 CHAPTER 11. NETWORKING
In the following program we find the IP address of a given domain name. When we
run this program we find
issc.rau.ac.za/152.106.50.232
// Net4.java
import java.net.*;
try
{
InetAddress[] addresses =
InetAddress.getAllByName("issc.rau.ac.za");
for(int i=0; i<addresses.length; i++)
{
System.out.println(addresses[i]);
}
} // end try block
catch(UnknownHostException e)
{
System.out.println("Could not find issc.rau.ac.za");
} // end catch block
}
}
11.5. URL CLASS 279
The getProtocol() method returns a String containing the protocol portion of the
URL, for example http or file. The getRef() method returns the named anchor of
the URL. If the URL does not have an anchor, the method returns null. The following
program shows how these methods are applied.
// URLmethods.java
import java.net.*;
With the following program we can download an HTML file using the URL class.
After compiling Viewsource.java, i.e. we generated the file
Viewsource.class
this will download the HTML file lpd.html from AMD (Advanced Micro Devices).
If we want redirect to output to the file mylpd.htm on our hard disc type:
// Viewsource.java
import java.net.*;
import java.io.*;
try
{
BufferedReader theHTML =
11.5. URL CLASS 281
try
{
while((thisLine = theHTML.readLine()) != null)
{
System.out.println(thisLine);
} // while loop ends here
} // end try
catch(Exception e) { System.err.println(e); }
} // end try
catch(Exception e) { System.err.println(e); }
} // end try
catch(MalformedURLException e)
{
System.err.println(args[0] + " is not a parseable URL");
System.err.println(e);
} // end catch
} // end if
} // end main
}
Under Microsoft Internet Explorer we can directly get the HTML file from the
server. After we loaded the HTML file in our Web browser we click at View. Then
we click at Source and we are provided with the HTML file.
282 CHAPTER 11. NETWORKING
Socket()
The method
int getLocalPort()
int getPort()
// MySocket.java
import java.net.*;
import java.io.*;
if(args.length > 0)
{
host = args[0];
}
int i = 0;
while(i < 1024)
{
try
{
s = new Socket(host,i);
System.out.println("There is a server on port " + i + " of " + host);
} // end try
catch(UnknownHostException e)
{
System.err.println(e);
}
catch(IOException e)
{ }
i++;
} // end while
} // end main
}
284 CHAPTER 11. NETWORKING
The IPC operations are based on socket pairs, one belonging to a communication
process. IPC is done by exchanging some data through transmitting that data in
a message between a socket in one process and another socket in another process.
When messages are sent, the messages are queued at the sending socket until the
underlying network protocol has transmitted them. When they arrive, the messages
are queued at the receiving socket until the receiving process makes the necessary
calls to receive them.
There are two communication protocols that one can use for socket programming:
datagram communication and stream communication.
What protocol we should use depends on the client/server application we are writing.
In UDP every time we send a datagram, we have to send the local descriptor and
the socket address of the receiving socket along with it. Since TCP is a connection-
oriented protocol, on the other hand, a connection must be established before com-
munications between the pair of sockets start. So there is a connection setup time
in TCP. In UDP, there is a size limit of 64 kilobytes on datagrams we can send to a
specified location, while in TCP there is no limit. Once a connection is established,
the pair of sockets behaves like streams: All available data are read immediately in
the same order in which they are received. UDP is an unreliable protocol – there is
no guarantee that the datagrams we have sent will be received in the same order by
the receiving socket. On the other hand, TCP is a reliable protocol; it is guaran-
teed that the packets we send will be received in the order in which they were sent.
In short, TCP is useful for implementing network services – such as remote login
(rlogin, telnet) and file transfer (FTP) – which require data of indefinite length to
be transferred. UDP is less complex and incurs fewer overheads. It is often used in
implementing client/server applications in distributed systems built over local area
networks.
Socket MyClient;
MyClient = new Socket("Machine name",PortNumber);
Where Machine name is the machine we are trying to open a connection to, and
PortNumber is the port (a number) on which the server we are trying to connect to is
running. When selecting a port number, we should note that port numbers between
0 and 1023 are reserved for privileged users (that is, super user or root). These
port numbers are reserved for standard services, such as email, FTP, and HTTP.
When selecting a port number for our server, select one that is greater than 1023.
Obviously we should also include exception handling. The above can be written as:
286 CHAPTER 11. NETWORKING
Socket MyClient;
try {
MyClient = new Socket("Machine name",PortNumber);
}
catch(IOException e) {
System.out.println(e);
}
ServerSocket MyService;
try {
MyServerice = new ServerSocket(PortNumber);
}
catch(IOException e) {
System.out.println(e);
}
When implementing a server we need to create a socket object from the ServerSocket
in order to listen for and accept connections from clients.
On the client side, we can use the DataInputStream class to create an input stream
to receive response from the server
DataInputStream input;
try {
input = new DataInputStream(MyClient.getInputStream());
}
catch(IOException e) {
System.out.println(e);
}
The class DataInputStream allows us to read lines of text and Java primitive data
types in a portable way. It has methods such as
Use whichever function we think suits our needs depending on the type of data that
we receive from the server. On the server side, we can use DataInputStream to
receive input from the client
DataInputStream input;
try {
input = new DataInputStream(serviceSocket.getInputStream());
}
catch(IOException e) {
System.out.println(e);
}
On the client side, we can create an output stream to send information to the server
socket using the class PrintStream or DataOutputStream of java.io
PrintStream output;
try {
output = new PrintStream(MyClient.getOutputStream());
}
catch(IOException e) {
System.out.println(e);
}
The class PrintStream has methods for displaying textual representation of Java
primitive data types. Its write() and println() methods are important here.
Also, we may want to use the DataOutputStream
DataOutputStream output;
try {
output = new DataOutputStream(MyClient.getOutputStream());
}
catch(IOException e) {
System.out.println(e);
}
The class DataOutputStream allows us to write Java primitive data types; many of
its methods write a single Java primitive type to the output stream. The method
writeBytes is a useful one. On the server side, we can use the class PrintStream
to send information to the client.
PrintStream output;
try {
output = new PrintStream(serviceSocket.getOutputStream());
}
catch(IOException e) {
System.out.println(e);
}
288 CHAPTER 11. NETWORKING
We should always close the output and input stream before we close the socket. On
the client side
try {
output.close();
input.close();
MyClient.close();
}
catch(IOException e) {
System.out.println(e);
}
try {
output.close();
input.close();
serviceSocket.close();
MyService.close();
}
catch(IOException e) {
System.out.println(e);
}
The following two programs show an application. We first compile the two programs
javac MyClient.java
javac MyServer.java
Then we start the server with java MyServer. Under Unix (Linux) we start the
server as background process
java MyClient
In the following example we run the two programs on the same machine. Under
Windows we open first a window for the server process and start it at the prompt
with java MyServer. Then we open another window and start at the prompt the
client java MyClient.
11.7. CLIENT-SERVER APPLICATION 289
// MyClient.java
import java.io.*;
import java.net.*;
Socket connection;
InputStream fromServer;
fromServer = connection.getInputStream();
fromServer.close();
connection.close();
}
}
290 CHAPTER 11. NETWORKING
// MyServer.java
import java.io.*;
import java.net.*;
try
{
servSocket = new ServerSocket(5321);
} catch(IOException e) { }
while(true)
{
try
{
connection = servSocket.accept();
toClient = connection.getOutputStream();
sLength = sendString.length();
for(int i=0;i<sLength;i++)
{
toClient.write((int) sendString.charAt(i));
}
toClient.close();
connection.close();
} catch(IOException e) { }
} // end while
} // end main
} // end class
11.7. CLIENT-SERVER APPLICATION 291
• AppRMI.java, on the client site and the server site, describes the interface used
by the server and client to cooperate. The precise interaction is described by
the methods of the AppRMI interface.
• AppRMIClient.java on the client site is the source for the client program.
• AppRMIServer.java on the server site is the source for the server program.
• java.policy on the server and client sites, describes the security restrictions
placed on the JAVA programs.
• CLIENT the directory on the client site local filesystem where compiled classes
will be placed. For example under Windows it could be c:\client\rmi and
under Linux ~/client/rmi.
• SERVER the directory on the server site local filesystem where compiled classes
will be placed. For example under Windows it could be c:\serverrmi and
under Linux ~/serverrmi.
• WEBDIR the directory on the server site local filesystem where compiled classes,
which need to be accessed via http, will be placed. For example under Win-
dows it could be c:\webdocs\rmi and under Linux ~/public_html/.
issc.rau.ac.za
• CODEBASE the http URL specifying where the necessary server classes can be
obtained by the client, for example
http://issc.rau.ac.za/rmi/
For javac and java the -classpath path option specifies where to find .class files.
The option overrides the CLASSPATH environment variable. To run the above exam-
ple program with the classpath specified by the environment variable CLASSPATH we
would enter on the command line
java -classpath directory;%CLASSPATH% someclass
in Windows and
java -classpath directory:$CLASSPATH someclass
in UNIX and Linux.
The program rmiregistry (rmiregistry.exe), provided with the JDK (and lo-
cated in the jdk1.4/bin directory), is used to provide an interface between clients
and servers. Using the RMI registry a server can register services (make them avail-
able to clients) in the form of implementations of interfaces. The client can use the
registry to determine if a service is available, and obtain a reference to an Object
which can be cast into the appropriate interface, which allows the service to be used.
The program rmic (rmic.exe) or RMI compiler program (located in the jdk1.4/bin
directory) is used to generate the stub classes used by the rmiregistry program.
The stub classes facilitate the intercation between client and server programs. For
rmic the option -v1.2 is used to generate only JAVA 1.2 compatible stub class files.
For example
294 CHAPTER 11. NETWORKING
directory\someclass_Skel.class
directory\someclass_Stub.class
in Windows and
directory/someclass_Skel.class
directory/someclass_Stub.class
directory\someclass_Stub.class
in Windows and
directory/someclass_Stub.class
For java (execute file) the option -Dproperty=value sets the system property
property to value. The system properties we use are
java -Djava.rmi.server.codebase=http://issc.rau.ac.za/rmi/
-Djava.rmi.server.hostname=issc.rau.ac.za
-Djava.security.policy=java.policy
someclass
runs the program someclass with the security policy specified by java.policy in
the current directory, the RMI server codebase at
http://issc.rau.ac.za/rmi/
issc.rau.ac.za
Next we have to compile the programs. On the server site we do the following.
We use the following sequence of commands on the command line
where WEBDIR is (in our case) for Windows c:\webdocs\rmi. In Linux we could
use ~/public_html/rmi. The first line makes the interface AppRMI available to
the server program and implementation class. The second line makes the interface
AppRMI available to client programs and the rmiregistry program. The third and
fourth lines compile the server program and implementation class. The fifth line
uses the rmic compiler to generate a stub class for remote access to the AppRMIImpl
class. The stub class is used by the rmiregistry program and the client program.
On the client site we do the following. We use the following sequence of commands
on the command line
The first line makes the interface AppRMI available to the client program. The sec-
ond line compiles the client program.
Next we run the programs. To start the server we do the following. First we must
start the rmiregistry program (rmiregistry.exe). This must be done without a
classpath, and in a directory where none of the server .class files exist. To unset
the classpath we can use
set CLASSPATH=
in Windows and
unsetenv CLASSPATH
296 CHAPTER 11. NETWORKING
export -n CLASSPATH
start rmiregistry
in Windows and
rmiregistry &
in UNIX and Linux. The ampersand (&) in Unix and Linux indicates that the
program is to be run in the background, i.e. the current shell continues to run
immediately after the command and more commands can be issued.
Now we can set the CLASSPATH again if necessary. Lastly we start the server program
with the command (single line)
The option
-classpath SERVER;WEBDIR
is in the Windows path format, for UNIX and Linux we would use
-classpath SERVER:WEBDIR
instead. Next we have to start the client. We start the client program using (single
line)
Example
Let us give an example. We use all the previous instructions for building and running
the programs. In this case the filenames begin with Lotto instead of App since we
created a Lottery number generating system. The java.policy file used is given
below
grant {
permission java.net.SocketPermission "*:1024-65535", "connect,accept";
permission java.net.SocketPermission "*:80", "connect";
};
which provides enough network access to retrieve the necessary .class files via http
(port 80), and to use the RMI registry (usually on port 1099).
The interface LottoRMI.java specifies that the only method we can use to commu-
nicate with the server is the findnumbers() method. The file LottoRMI.java is on
the server and client site.
// LottoRMI.java
The client program must create a SecurityManager to allow access to the server
codebase via http. This is achieved by creating a RMISecurityManager() which im-
plements the security restrictions defined in the file specified by java.security.policy.
The method Naming.lookup(String) is used to refer to a class on a RMI server.
The string argument is an URL of the form
rmi://host:port/name
where host is the name of the RMI server machine, port is a port number and
name specifies the class the client wishes to refer to. The rmi: part of the URL is
not required, if the :port part of the URL not given, the port is assumed to be
1099. The method Naming.lookup() return type is Remote, which must be cast
into the appropriate interface (LottoRMI in this case). This service is provided by
the rmiregistry program. The file LottoRMIClient.java is on the client site.
// LottoRMIClient.java
import java.rmi.*;
298 CHAPTER 11. NETWORKING
import java.rmi.registry.*;
import java.rmi.server.*;
The server program must create a SecurityManager in the same way as the client.
The server only makes the implementation class LottoRMIImpl available to client
programs. The file LottoRMIServer.java is on the server site.
// LottoRMIServer.java
import java.rmi.*;
import java.rmi.server.*;
The class LottoRMIImpl provides the implemetations of the methods which can
be remotely invoked by the client program. The method Naming.rebind(String)
associates a String with the implementation class. The String parameter is the
name part of the URL specified by the client program. This service is provided by
the rmiregistry program. The file LottoRMIImpl.java is on the server site.
// LottoRMIImpl.java
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
for(int i=0;i<numbers;i++)
{
array[i]=(int)(maximum*Math.random());
for(int j=0;j<i;j++)
{ if(array[i]==array[j]) { j=i; i--; } }
}
return array;
}
}
11.9. SOCKETCHANNEL AND SERVERSOCKETCHANNEL 301
SocketChannel ServerSocketChannel
classes in the java.nio package. In our example we send an array of 4 double and
the length of the array to the Server. The Server calculates the arithmetic, geometric
and harmonic mean of the 4 numbers. Then it returns these three numbers and the
length of the original array. Enough memory must be allocated for the ByteBuffer.
We recall that the size of int is 4 bytes and the size of double is 8 bytes.
The class Buffer is a container of a specific primitive data type (excluding boolean).
A buffer is a linear, finite sequence of elements it contains. The capacity of a buffer
is never negative and never changes. The method
Buffer flip()
flips this buffer. The limit is set to the current position and then the position is set
to zero. The method
in class DoubleBuffer writes the given double into this buffer at the given index.
The method
// MeanClient.java
import java.nio.channels.SocketChannel;
import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import java.nio.IntBuffer;
import java.io.IOException;
import java.net.InetSocketAddress;
ByteBuffer.allocate(48);
private DoubleBuffer doubleBuffer =
buffer.asDoubleBuffer();
private IntBuffer intBuffer = buffer.asIntBuffer();
intBuffer.put(0,nlength);
for(int i=1; i<=nlength; i++)
{
doubleBuffer.put(i,narray[i-1]);
}
channel.write(buffer);
}
// MeanServer.java
import java.nio.channels.SocketChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.DoubleBuffer;
import java.io.IOException;
import java.net.InetSocketAddress;
// harmonic mean
double harmmean = 0.0;
double temp = 0.0;
for(int i=0; i < nlength; i++)
{
temp += 1.0/doublearray[i];
}
harmmean = nlength/temp;
// geometric mean
double geommean = 1.0;
for(int i=0; i < nlength; i++)
{
geommean *= doublearray[i];
}
geommean = Math.exp(Math.log(geommean)/nlength);
buffer.flip();
buffer.clear();
intBuffer.put(0,nlength);
doubleBuffer.put(1,arithmean);
doubleBuffer.put(2,harmmean);
doubleBuffer.put(3,geommean);
sc.write(buffer);
}
12.1 Introduction
The Collections API is a set of classes and interfaces that provide an implementation-
independent framework for working with collections of objects. This API consists
of 13 new classes and 10 new interfaces that have been added to the java.util
package. These classes and interfaces provide support for generic collections, sets,
bags, maps, lists and linked lists. These classes and interfaces can be easily extended
to provide support for custom object collections. Some classes and interfaces from
Java version 1.0 have been replaced by improved interfaces and classes in version
1.2. For example, the interface Iterator replaces the interface Enumeration and
the class Map replaces the Dictionary class. The Vector class introduced in chapter
3 can be replaced by class ArrayList.
The new collections interfaces introduced with JDK 1.2 are as follows:
306
12.1. INTRODUCTION 307
The new collections classes introduced with JDK 1.2 are as follows:
is an ordered collection (also known as sequence). The user of this interface has
precise control over where in the List each element is inserted. The user can access
elements in the list by their integer index (position) and search for elements in the
list. Unlike sets, lists can have duplicate elements. The
ArrayList()
boolean add(Object o)
in class ArrayList appends the specified element to the end of this ArrayList. The
method
inserts the specified element at the specified position. To find out whether an element
is the ArrayList we apply method
It returns true if this ArrayList contains the specified element. The method
returns the element at the specified position at this ArrayList. To remove all
elements in ArrayList we use the method void clear().
310 CHAPTER 12. JAVA 2 COLLECTION FRAME WORK
The class
sorts the specified List into ascending order, according to the natural ordering of
its elements. The method
searches the specified List for the specified Object using the binarySearch algo-
rithm. The method
copies all the elements from one List into another. The method
replaces all the elements of the specified List with the specified elements.
Iterator takes the place of Enumeration in the Java Collections framework. It-
erators differ from Enumerations in two ways. Iterators allow the caller to remove
elements from the underlying collection during the iteration with well-defined se-
mantics. Method names have been improved. The method
boolean hasNext()
in class Iterator returns true if the iteration has more elements. In other words it
returns true if next() would return an element rather than throwing an exception.
The method
Object next()
void remove()
removes from the underlying Collection the last element returned by the Iterator
(optional operation). This method can be called only once per call to next().
12.3. EXAMPLES 311
12.3 Examples
The following two examples show how Collection, ArrayList, and Iterator is
applied.
// MyColl1.java
import java.util.*;
Iterator it = coll.iterator();
while(it.hasNext())
{
System.out.print(it.next()); // => ABC...YZ
}
System.out.println(" ");
} // end main
}
312 CHAPTER 12. JAVA 2 COLLECTION FRAME WORK
// MyColl2.java
import java.util.*;
Collections.sort((List) coll);
while(itnew.hasNext())
{
System.out.println(itnew.next()); // sorted list
}
contains various methods for manipulating arrays such as sorting and searching.
The methods work for basic data types and abstract data types. We apply the
methods
to arrays of basic data types and arrays of abstract data types. Before we call the
method binarySearch() we have to sort the array using the sort() method. We
also show how the method clone() is used.
// MyArray.java
import java.util.*;
import java.math.*;
Arrays.sort(a);
for(i=0; i < a.length; i++)
System.out.println("a[" + i + "] = " + a[i]);
int r1 = Arrays.binarySearch(a,-1);
System.out.println("r1 = " + r1); // => 1
boolean b1 = Arrays.equals(a,b);
System.out.println("b1 = " + b1); // => false
Arrays.fill(b2,2,4,true);
Arrays.sort(big);
BigInteger f = new BigInteger("6712345678");
int pos = Arrays.binarySearch(big,f);
System.out.println("pos = " + pos); // => 2
Arrays.sort(bigdec);
// use of clone()
int[] vec = new int[3];
vec[0] = 1; vec[1] = 4; vec[2] = 5;
int[] vecClone = (int[]) vec.clone();
for(i=0; i < vecClone.length; i++)
System.out.println(vecClone[i]);
}
}
12.4. ARRAYS CLASS 315
// Sort.java
import java.util.*;
Arrays.sort(strings);
List list = Arrays.asList(strings);
displayList(list);
} // end main
ListIterator i = list.listIterator(0);
while(i.hasNext())
{
Object o = i.next();
if(o == null) System.out.println("null");
else
System.out.println(o.toString());
} // end while
} // end method display
}
// Sorting.java
import java.util.*;
import java.math.*;
Collections.shuffle(listO);
System.out.println(listO);
Collections.reverse(listO);
System.out.println(listO);
Collections.swap(listO,2,0);
System.out.println(listO);
Collections.fill(listI,5);
System.out.println(listI);
int f = Collections.frequency(listI,5);
System.out.println(f);
implements the TreeSet interface backed by TreeMap. The set will be in ascending
order sorted according to the natural order of the elements.
The following program shows an application of the class TreeSet. The default
constructor
TreeSet()
constructs a new empty TreeSet sorted according to the elements natural order.
The method
boolean add(Object o)
The method
void clear()
The method
boolean contains(Object o)
The method
Object first()
The method
Object last()
// MySet.java
import java.util.*;
Iterator it = tset.iterator();
while(it.hasNext())
{
Object o = it.next();
if(o == null) System.out.println("null");
else
System.out.println(o.toString());
}
tset.add(s3);
tset.add(s4);
} // end main
}
12.5. CLASS TREESET 319
In Java the interface Set is a Collection that cannot contain duplicates elements.
The interface Set models the mathematical set abstraction. The Set interface
extends Collection and contains no methods other than those inherited from
Collection. It adds the restriction that duplicate elements are prohibited. The
JDK contains two general-purpose Set implementations. The class HashSet stores
its elements in a hash table. The class TreeSet stores its elements in a red-black
tree. This guarantees the order of iteration.
// SetOper.java
import java.util.*;
// union
TreeSet S3 = new TreeSet(S1);
boolean b1 = S3.addAll(S2);
System.out.println("S3 = " + S3);
System.out.println("S1 = " + S1);
// intersection
TreeSet S4 = new TreeSet(S1);
boolean b2 = S4.retainAll(S2);
System.out.println("S4 = " + S4);
System.out.println("S2 = " + S2);
The output is
The next program shows an application of the class TreeMap. The default construc-
tor TreeMap() constructs a new, empty TreeMap sorted according to the keys in
natural order. The constructor TreeMap(Map m) constructs a new TreeMap contain-
ing the same mappings as the given Map, sorted according to the key’s natural order.
The method
associates the specified value with the specified key in this TreeMap. The method
in class TreeMap returns a Set view of the mapping contained in this map. The
Set’s Iterator will return the mappings in ascending Key order. Each element in
the returned set is a Map.Entry. The method
returns true if this TreeMap contains a mapping for the specified key. The method
returns true if this Map maps one or more keys to the specified value. The method
returns the value to which this TreeMap maps the specified key. The method
removes the mapping for this key from this TreeMap if present.
322 CHAPTER 12. JAVA 2 COLLECTION FRAME WORK
// MyMap.java
import java.util.*;
int i;
for(i=0; i < sc.length; i++)
{
map.put(sc[i],sn[i]);
}
displayMap(map);
} // end main
while(it.hasNext())
{
Object o = it.next();
if(o == null)
System.out.println("null");
else
System.out.println(o.toString());
}
} // end method displayMap
}
Chapter 13
13.1 Introduction
The Swing components form a sophisticated library of GUI components including
borders, buttons, checkboxes, combo boxes, icons, labels, lists, list boxes, menus,
menubars, menu items, popup menus, radio buttons, progress bars, scrool panes
and viewports, scrollbars, tabbed panes, tables, text areas, text components, text
fields, trees and HTML viewers. All the components are Java Beans written in
pure Java and all components can be navigated with the mouse as well with the
keyboard. The Swing components extend the AWT (Abstract Windowing Toolkit)
components. Swing components are used to create graphical user interfaces for Java
programs. It includes not only the equivalent of AWT components, but also new
ones such as table and treewidgets. Swing is a standard part of Java 2 and higher.
Swing offers a number of advantages over the AWT components. Just as AWT
provides a Window class hierarchy, so does Swing. Swing’s window classes are
extensions of the AWT Window class hierarchy. The JWindow class extends the
AWT Window class. The JFrame class extends the AWT Frame class and JDialog
class extends the AWT Dialog class. The JWindow, JFrame, and JDialog classes
differ from their AWT counterparts in that they use a separate content pane for
adding and laying out GUI components. This content pane is a Container object
that is accessed using the getContentPane(). The method
Container getContentPane()
is in class JFrame and returns the content pane object for this frame. The content
pane is part of a JRootPane object that contains other panes for overlaying compo-
nents and intercepting mouse and keyboard events. Thus the JFrame class is slightly
incompatible with java.awt.Frame. The class JFrame contains a JRootPane as its
only child. The contentPane should be the parent of any child of the JFrame. This
is different from java.awt.Frame, e.g. to add a child to an AWT Frame we have
frame.add(child);
323
324 CHAPTER 13. THE SWING COMPONENTS
Using the class JFrame we have to add the child to the JFrames contentPane instead
frame.getContentPane().add(child);
The same is true for setting LayoutManagers, removing components, listing children,
etc. All these methods should normally be sent to the contentPane() instead of
the JFrame itself. Thus in Swing, top-level windows (such as JFrame or JDialog)
do not have components added directly to the window. Instead we add them to the
content pane like this
myWindow.getContentPane().add(component)
Swing menus, like Swing windows, are analogous to their AWT counterparts. The
classes
but with one difference. The Swing menu classes are all subclasses of the JComponent
class, and therefore, of the Component class. This means that Swing menus, unlike
their AWT counterparts, are first-class components and can be used with any Con-
tainer classes. The JPopupMenu class is analogous to the AWT PopupMenu class.
The class JPopupMenu is an implementation of a Popup Menu – a small window
which pops up and displays a series of choices.
The JTextComponent, JTextField, and JTextArea classes are the Swing analogs
of the AWT TextComponent, TextField, and TextArea classes. In addition, Swing
provides the JTextPane class for working with text documents that can be marked
up with different text styles. The class JTextPane extends JEditorPane provides a
text component that can be marked with attributes that are represented graphically.
Components and images may be embedded in the flow of text.
setLayout(new FlowLayout());
is replaced by
getContentPane().setLayout(new FlowLayout());
in swing.
13.1. INTRODUCTION 325
The following three programs show an application of the classes JButton, JTextField,
JFrame. We also show how the UIManager is used.
The method
String getText()
is in class AbstractButton and the class JButton inherts this method. The method
void setText(String)
If we want to change the look and feel of our application from the default, we can
use the UIManager class which allows us to find out the current look and feel of the
application, and to change it. The class UIManager keeps track of the current look
and feel and its defaults. We can select from a variety of looks and feels for our user
interface. The method
in class UIManager is passed the name of the class as a String which represents
the required look and feel. The most common way of using these methods is when
we want to change from the cross-platform (metal) look and feel to the system look
and feel.
326 CHAPTER 13. THE SWING COMPONENTS
13.2 Examples
In the next program we have rewritten the program GUI.java from chapter 5 now
using Java 1.2. The class WindowAdapter is an abstract adapter class for receiving
window events. The methods in this class are empty. This class exists as convenience
for creating listener objects. We extend this class to create a WindowEvent Listener
and override the methods for the events of interest. We create two buttons and
add them to the container. We also add two checkboxes and three labels to the
container. Finally a textfield is added.
// JGUI1.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public MyJList()
{
setTitle("Simple ListBox Application");
setSize(300,100 );
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent event)
{ System.exit(0); }});
setBackground(Color.gray);
topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
getContentPane().add(topPanel);
// create some items to add to the list
String listData[] = { "Item 1","Item 2","Item 3","Item 4" };
In the next two programs we include the interface ActionListener and the class
ActionEvent. The method
Object getSource()
String getText()
returns the button’s text. The class JTextField inherits the method
void setText(String t)
// Swing1.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
13.3. ADDING ACTIONS TO CONTAINERS 329
b1.addActionListener(al);
add(b1);
b2.addActionListener(al);
add(b2);
add(t);
} // end init()
frame.getContentPane().add(applet,BorderLayout.CENTER);
frame.setSize(300,100);
applet.init();
applet.start();
frame.setVisible(true);
} // end main
}
The validate() method is used to cause a container to lay out its subcomponents
again. It should be invoked when this container’s subcompoents are modified (added
or removed from the container, or layout-related information changed) after the
container has been displayed. An example is given below.
330 CHAPTER 13. THE SWING COMPONENTS
// Swing2.java
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
b1.addActionListener(al);
add(b1);
b2.addActionListener(al);
add(b2);
add(t);
} // end init()
frame.getContentPane().add(applet,BorderLayout.CENTER);
13.3. ADDING ACTIONS TO CONTAINERS 331
frame.setSize(300,100);
applet.init();
applet.start();
frame.setVisible(true);
} // end main
}
In the following program we open a window with a button which includes the text
"Press me". After clicking the button it is replaced by a button with the text
"1: I like this: Press me again". Clicking again overides the text in the but-
ton with the text 2: I like this: Press me again" etc up to 10. Every time
the colour of the text changes in a random fashion.
// ButtonPress.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent event)
{ System.exit(0); } } );
getContentPane().setBackground(Color.white);
getContentPane().setLayout(new FlowLayout());
getContentPane().add(button);
button.addActionListener(buttonHandler);
button.addActionListener(this);
setSize(400,150);
setVisible(true);
} // end constructor ButtonPress
red = randomNumberGenerator.nextInt(256);
green = randomNumberGenerator.nextInt(256);
blue = randomNumberGenerator.nextInt(256);
button.setForeground(new Color(red,green,blue));
} // end method actionPerformed
// JButtonGame.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public JButtonGame()
{
setSize(200,200);
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent event)
{ System.exit(0);}});
panel.setLayout(new GridLayout(nRows,nCols));
buttons = new JButton[nRows][nCols];
for(int nRow=0;nRow<nRows;nRow++)
{
for(int nCol=0;nCol<nCols;nCol++)
{
buttons[nRow][nCol] = new JButton ("");
buttons[nRow][nCol].addActionListener(this);
panel.add(buttons[nRow][nCol]);
}
}
getContentPane().add("Center",panel);
textField = new JTextField("",80);
334 CHAPTER 13. THE SWING COMPONENTS
textField.setEditable(false);
getContentPane().add("South",textField);
labelsUsed[i] = label;
int nRow = i/nCols;
int nCol = i - nRow*nCols;
buttons[nRow][nCol].setText((new Integer (label)).toString());
}
getButtonPosition((new Integer (nButtons)).toString());
blankRow = clickedRow;
blankCol = clickedCol;
JButton blank = buttons[clickedRow][clickedCol];
blank.setText("");
blank.setBackground(Color.green);
} // end constructor JButtonGame()
}
}
}
} // end method getButtonPosition(String)
oldBlank.setText(label);
oldBlank.setBackground(Color.lightGray);
blankRow = newRow;
blankCol = newCol;
} // end method moveBlank
// TextFields.java
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
import java.text.DecimalFormat;
public TextFields()
{
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent event)
{ System.exit(0); }
});
setTitle("Text Fields");
getContentPane().setLayout(new GridLayout(3,2));
getContentPane().add(new JLabel("Numerator: "));
getContentPane().add(numField);
getContentPane().add(new JLabel("Denominator: "));
getContentPane().add(denField);
getContentPane().add(new JLabel("Result of Division: "));
getContentPane().add(resultField);
numField.addActionListener(this);
numField.addFocusListener(this);
numField.setToolTipText("The Numerator Textfield");
13.5. EDITABLE TEXTFIELDS 337
denField.addActionListener(this);
denField.addFocusListener(this);
denField.setToolTipText("The Denominator Textfield");
resultField.setEditable(false);
resultField.setToolTipText("The result of the divison.");
pack();
setVisible(true);
} // end constructor TextFields()
container for text supports editing and provides notification of changes. The class
JEditorPane is sort of a fancy text area that can display text derived from different
file formats. The built-in version supports HTML and RTF (Rich Text Format) only,
but we can build editor kits to handle special purpose applications. JEditorPane
is most often use to display HTML. We choose the type of document we want to
display by calling the method setContentType and specify a custom editor kit via
the method setEditorKit. The class
is a text component that can be marked up with attributes that are represented
graphically. The class JTextPane inherits the method getCaret() from the class
JTextComponent. The method Caret getCaret() fetches the caret that allows
text-oriented navigation over the view. The
is a place within a document view that represents where things can be inserted into
the document model. The method Document getDocument() in class JTextPane
fetches the model associated with the editor. The
class Position
represents a location within a document. The method int getDot() in class Caret
fetches the current position of the caret.
// PosDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
13.6. DOCUMENT AND JTEXTPANE CLASSES 339
setbutton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{ // try block
int dot = pane.getCaret().getDot();
Document doc = pane.getDocument();
lastpos = doc.createPosition(dot);
pane.requestFocus();
} // end try block
catch(BadLocationException exc)
{ System.err.println(exc); }
}
}); // end argument setbutton.addActionListener
gobutton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(lastpos == null)
{
Toolkit.getDefaultToolkit().beep();
}
else
{
340 CHAPTER 13. THE SWING COMPONENTS
buttonpanel.add(setbutton);
buttonpanel.add(gobutton);
panel.setLayout(new BorderLayout());
panel.add("North", buttonpanel);
panel.add("Center", pane);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
} // end main
}
13.7. MODEL-VIEW-CONTROLLER 341
13.7 Model-View-Controller
Swing’s Model-UI architecture is a variation of the Model-View-Controller (MVC)
pattern. MVC addresses the problem of how to build software for user interfaces.
The MVC pattern, first introduced in Smalltalk-80, was designed to reduce the pro-
gramming effort required to build systems that made use of multiple, synchronized
presentations of the same data. The MVC consists of three distinct parts:
2) The View renders the data of the model. The view observes changes in the model
and then renders the updated model data. Since there is only a single central model,
all views will remain coherent.
3) The Controller listens to user events and controls the view on the data. The
View and Controller know about the Model, but the model is almost unaware of
their existence: it merely knows that if it changes, it has to send a message to any
registered listener warning it that there have been changes.
The MVC pattern prompts the following software qualities, which make it such a
novel idea:
2) Loose coupling: The model publishes only an interface for notification. Each
view implements this interface, but the model does not know, nor, care about the
view beyond this interface.
3) Pluggabilty: We can add new views easily, without changing the model.
The MVC design pattern is typically used for constructing interfaces that may
present multiple views of the same data. The design pattern is important, because
it completely de-couples data display from data representation. This means that
the user interface of an application can be completely changed - even dynamically,
under direction of the user - without need for any change to the underlying data
subsystem of the application. All Swing data-representation components are imple-
mented with this design pattern in mind, so all Swing applications will inherently
benefit from this immense design flexibility.
The easiest place to see this approch is the class JTable. We can define a TableModel
object (the model) and tell a JTable (combined View-Controller) to observe that
model. When the data changes, the JTable is notified, and it updates its display.
Several Views could monitor a single table. The model notifies them of changes,
342 CHAPTER 13. THE SWING COMPONENTS
and lets the View figure out how to update the display. A common mistake is to
write code to update the TableModel but not send any notifications.
// MyTable.java
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.JScrollPane;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.JOptionPane;
import java.awt.*;
import java.awt.event.*;
public MyTable()
{
super("MyTable");
MyTableModel myModel = new MyTableModel();
JTable table = new JTable(myModel);
table.setPreferredScrollableViewportSize(new Dimension(400,70));
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
} // end MyTable
if(DEBUG)
{
System.out.println("New value of data:");
printDebugData();
}
}
for(int i=0;i<numRows;i++)
{
System.out.print(" row " + i + ".");
for(int j=0;j<numCols;j++)
{
System.out.print(" " + data[i][j]);
}
System.out.println();
}
System.out.println("--------------------------------");
}
}
DefaultMutableTreeNode
is a general purpose node in a tree data structure. A tree node may have at most
one parent and 0 or more children. DefaultMutableTreeNode provides operations
for examining and modifying node’s parent and children and also operations for
examining the tree that the node is part of. The constructor
DefaultMutableTreeNode(Object userObject)
creates a tree node with no parent, no children, but which allows children and
initializes it with the specified user object. The method
removes newChild from its parent and makes it a child of this node by adding it to
the end of this node’s child array.
int getPathCount()
// JTreeClass.java
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
Container frameContainer;
DefaultMutableTreeNode son1_willi =
new DefaultMutableTreeNode("Lars");
DefaultMutableTreeNode son2_willi =
new DefaultMutableTreeNode("Gunnar");
DefaultMutableTreeNode son3_willi =
new DefaultMutableTreeNode("Jan");
DefaultMutableTreeNode son4_willi =
new DefaultMutableTreeNode("Olli");
DefaultMutableTreeNode son1_Lars =
new DefaultMutableTreeNode("Friederich");
DefaultMutableTreeNode son1_Gunnar =
new DefaultMutableTreeNode("Eugen");
DefaultMutableTreeNode son2_Gunnar =
new DefaultMutableTreeNode("Karl");
DefaultMutableTreeNode son1_Jan =
new DefaultMutableTreeNode("Albert");
DefaultMutableTreeNode son1_Olli =
new DefaultMutableTreeNode("Ollix");
DefaultMutableTreeNode son1_Eugen =
13.8. JTREE CLASS 347
new DefaultMutableTreeNode("Otto");
public JTreeClass()
{
super(TITLE);
buildGUI();
setupEventHandlers();
setSize(WIDTH,HEIGHT);
show();
}
void buildGUI()
{
setupMenuBar();
setupTree();
layoutComponents();
}
void setupMenuBar()
{
fileMenu.add(fileExit);
menuBar.add(fileMenu);
setJMenuBar(menuBar);
}
void setupTree()
{
root.add(son1_willi);
root.add(son2_willi);
root.add(son3_willi);
root.add(son4_willi);
son1_willi.add(son1_Lars);
son2_willi.add(son1_Gunnar);
son2_willi.add(son2_Gunnar);
son3_willi.add(son1_Jan);
son4_willi.add(son1_Olli);
son1_Gunnar.add(son1_Eugen);
void setupEventHandlers()
{
addWindowListener(new WindowHandler());
fileExit.addActionListener(new MenuItemHandler());
}
textField.setText(text);
13.8. JTREE CLASS 349
}
}
// Browser.java
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
topPanel.add(urlField);
getContentPane().add(topPanel,BorderLayout.NORTH);
try
{
htmlPane = new JEditorPane(initialURL);
htmlPane.setEditable(false);
htmlPane.addHyperlinkListener(this);
JScrollPane scrollPane = new JScrollPane(htmlPane);
getContentPane().add(scrollPane,BorderLayout.CENTER);
}
catch(IOException ioe)
{
warnUser("Cannot build HTML pane for " + initialURL
+ ": " + ioe);
}
{
try
{
htmlPane.setPage(event.getURL());
urlField.setText(event.getURL().toExternalForm());
}
catch(IOException ioe)
{
warnUser("Cannot follow link to "
+ event.getURL().toExternalForm() + ": " + ioe);
}
}
} //end hyperlinkUpdate
The class PrinterJob is the principal class that controls printing. An application
calls methods in this class to set up a job, optionally to invoke a print dialog with
the user, and then print the pages of the job. The following methods are in this class.
The method
is used when the pages in the document to be printed by this PrinterJob are drawn
by the Printable object painter. The method
presents the user a dialog for changing properties of the print job interactivly. The
method
// PrintTest.java
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.awt.print.*;
import java.awt.print.PrinterJob;
{
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent event)
{ System.exit(0); }
});
setTitle("Print Test");
getContentPane().add(buttonPanel,BorderLayout.NORTH);
getContentPane().add(drawPanel);
setSize(400,400);
setVisible(true);
}
gc.setPaint(new GradientPaint(width/4.0F,height/2.0F,Color.black,
3.0F*width/4.0F,height/2.0F,Color.white));
Ellipse2D ellipse
= new Ellipse2D.Double(width/4.0,height/4.0,width/2.0,height/2.0);
gc.fill(ellipse);
}
Java Beans
14.1 Introduction
Java Beans is a component technology on top of the Java programming language
that tries to simplify programming by reducing it as far as possible to simple graph-
ical operations. It is used mainly to implement graphical user interfaces, but can be
applied to the non-graphical parts of a program as well. A Java Bean is a reusable
software component that works with Java. More specifically: a Java Bean is a reuse-
able software component that can be visually manipulated in builder tools. To work
with Java Beans one needs an appropriate tool like a Java Integrated Development
Environment and a set of components, the beans.
Individual Java Beans will vary in functionality, but share certain common defining
features.
1) Support for introspection allowing a builder tool to analyze how a bean works.
2) Support for customization allowing a user to alter the appearance and behaviour
of a bean.
3) Support for events allowing beans to fire events, and informing builder tools about
both the events they can fire and the events they can handle.
5) Support for persistence allowing beans that beans that have been customized in
an application builder to have their state saved and restored. Typically persistence
is used with an application builder’s save and load menu commands to restore any
work that has gone into constructing an application.
356
14.1. INTRODUCTION 357
The most common use of beans is for graphical user interface components, such as
components of the java.awt and javax.swing packages. Although all beans can
be manipulated visually, this does not mean every bean has it own visual represen-
tation. The simplest beans are typically basic graphical interface components, such
as a java.awt.Button object.
The Java Bean APIs contain a java.beans.Introspector class which can be used
to find out about the properties and methods of a class. It can find out about
properties of a bean by either an implicit or explicit method. The implicit method
uses design patterns. The Introspector creates a list of all of the public methods
in the bean and searches that list for signatures that matches a particular pattern.
The explicit introspection uses an array of package names to form a search path for
locating explicit information about a bean.
Sometimes when a bean property changes, another object may want to be notified
of the change and react to the change. Whenever a bound property changes, no-
tification of the change is sent to interested listeners. A bean containing a bound
property must maintain a list of property change listeners, and alert those listeners
when the bound property changes. The convenience class PropertyChangeSupport
implements methods that add and remove PropertyChangeListener objects from
a list, and fires PropertyChangeEvent objects at those listeners when the bound
property changes. Our beans can inherit from this class, or use it as an inner class.
An object that wants to listen for property changes must be able to add and remove
itself from the listener list on the bean containing the bound property, and respond
to the event notification method that signals a property change. By implement-
ing the PropertyChangeListener interface the listener can be added to the list
maintained by the bound property bean, and since it implements the
PropertyChangeEvent
class encapsulates property change information, and is sent from the property change
event source to each object in the property change listener list via the propertyChange
method.
358 CHAPTER 14. JAVA BEANS
14.2 Example
The following programs give an example for a bean. The class DateAlerter imple-
ments a date alerter and the class DateWatcher implements a date watcher. The
class DateAlerter uses the Date class and we implement the public methods
and
We also use object serialization. Object serialization supports the encoding of ob-
jects and the objects reachable from them into a stream of bytes. It supports the
complementary reconstruction of the object from the stream. Both String and
Date implement serializable.
// TimeBeans.java
// DateAlerter.java
import java.beans.*;
import java.text.*;
import java.util.*;
{
propertySupport.removePropertyChangeListener(lis);
}
}
// DateWatcher.java
import java.beans.*;
import javax.swing.*;
14.3 JavaBeans
JavaBeans are Java classes that follow conventions which allow for easy reuse of
components. This allows, for example, the creation of new GUI components which
can be used and manipulated from the NetBeans IDE GUI builder.
JavaBeans are not necessarily graphical in nature. The NetBeans IDE provides
straightforward access to the capabilities of JavaBeans.
A bean can be used from the palette for a JFrame form. Right clicking on a JFrame
form class node in a project and selecting “Tools” followed by “Add to Palette”
adds a bean to the palette of beans available to the form.
Select the “Add from JAR...” button. Select the JAR file and the beans to be
used in the palette.
SomeType getSomething(void)
void setSomething(SomeType)
import java.util.Timer;
import java.util.TimerTask;
public Alarm1()
{
alarm = -1;
rings = 0;
alarmTimer = new Timer("Alarm", true); // is a daemon
}
added manifest
adding: Alarm1.class(in = 1488) (out= 857)(deflated 42%)
14.3. JAVABEANS 363
Alarm1.manifest:
Manifest-Version: 1.0
Name: Alarm1.class
Java-Bean: true
14.3.7 Introspection
//ShowBean.java
import java.beans.BeanDescriptor;
import java.beans.BeanInfo;
import java.beans.IndexedPropertyDescriptor;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.ClassLoader;
int i;
for(i=0;i<pd.length;i++)
{
System.out.println("Property: " + pd[i].getName()
+ ((pd[i].isBound())?" (bound)":"")
+ ((pd[i].isConstrained())?" (constrained)":"")
+ ((pd[i] instanceof IndexedPropertyDescriptor)?
" (indexed)":""));
System.out.println("Property: " + pd[i].getName() + ", read: "
+ pd[i].getReadMethod());
System.out.println("Property: " + pd[i].getName() + ", write: "
364 CHAPTER 14. JAVA BEANS
+ pd[i].getWriteMethod());
}
}
catch(java.lang.ClassNotFoundException e)
{ System.out.println("Class not found: " + args[0]); }
catch(java.beans.IntrospectionException e)
{ System.out.println("Error during introspection: " + args[0]); }
}
}
void addPropertyChangeListener(PropertyChangeListener)
void removePropertyChangeListener(PropertyChangeListener)
//Alarm2.java
14.3. JAVABEANS 365
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Timer;
import java.util.TimerTask;
public Alarm2()
{
alarm = -1;
rings = 0;
alarmTimer = new Timer("Alarm",true); // is a daemon
pChange = new PropertyChangeSupport(this);
pChange.addPropertyChangeListener(this);
}
// TimerTask
public void run()
{
int oldrings = rings;
rings++;
pChange.firePropertyChange("rings",oldrings,rings);
}
// PropertyChangeListener
public void propertyChange(PropertyChangeEvent e)
{
System.out.println(e.getPropertyName() + " changed from "
+ e.getOldValue() + " to " + e.getNewValue());
}
// PropertyChangeSupport
public void addPropertyChangeListener(PropertyChangeListener p)
{ pChange.addPropertyChangeListener(p); }
java.beans.VetoableChangeSupport.
//Alarm3.java
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
import java.util.Timer;
import java.util.TimerTask;
public Alarm3()
{
alarm = -1;
rings = 0;
alarmTimer = new Timer("Alarm",true); // is a daemon
pChange = new PropertyChangeSupport(this);
pChange.addPropertyChangeListener(this);
vChange = new VetoableChangeSupport(this);
vChange.addVetoableChangeListener(this);
}
// TimerTask
368 CHAPTER 14. JAVA BEANS
// PropertyChangeListener
public void propertyChange(PropertyChangeEvent e)
{
System.out.println(e.getPropertyName() + " changed from "
+ e.getOldValue() + " to " + e.getNewValue());
}
// VetoableChangeListener
public void vetoableChange(PropertyChangeEvent e)
throws PropertyVetoException
{
// throw new PropertyVetoException("I won’t allow it.", e);
System.out.println(e.getPropertyName() + " changed from "
+ e.getOldValue() + " to " + e.getNewValue()
+ " (not vetoed)");
}
// PropertyChangeSupport
public void addPropertyChangeListener(PropertyChangeListener p)
{ pChange.addPropertyChangeListener(p); }
// VetoableChangeSupport
public void addVetoableChangeListener(VetoableChangeListener v)
{ vChange.addVetoableChangeListener(v); }
else
{
alarmTimer = new Timer("Alarm", true); // is a daemon
if(alarm >= 0) alarmTimer.scheduleAtFixedRate(this,alarm,alarm);
else alarmTimer.cancel();
}
}
The following classes implement a bean for a Sudoku puzzle. The Sudoku class
extends JTable and consequently inherits all the JavaBean properties of JTable.
370 CHAPTER 14. JAVA BEANS
Thus the starting Sudoku configuration can be set by editing the model property of
JTable.
//SudokuTableModel.java
import java.lang.*;
//Sudoku.java
import java.lang.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
// PropertyChangeSupport
14.3. JAVABEANS 371
try { v = Integer.parseInt((String)getValueAt(i,j)); }
catch(Exception e) { continue; }
if(usedblk[(i/3)*3+(j/3)][v-1]) return false;
if(usedcol[j][v-1]) return false;
if(usedrow[i][v-1]) return false;
usedblk[(i%3)*3+(j/3)][v-1] = true;
usedcol[j][v-1] = true;
usedrow[i][v-1] = true;
}
return true;
}
public Sudoku()
{
super(new SudokuTableModel());
super.setTableHeader(null);
}
}
Java 2 Platform, Standard Edition (J2SE) version 1.5 adds a number of new features
to the language. One of this addition is generic types. Generic types allow us to
abstract over types. The most common examples are container types, such as those
in the Collection hierarchy. The following program gives two examples. The two
container classes ArrayList and Hashtable are used.
// GenericTypes.java
import java.util.*;
374
375
class Pair<X,Y>
{
private X first;
private Y second;
class PairMain
{
public static void main(String[] args)
{
Pair<String,Long> l1 = new Pair<String,Long>("max",1024L);
Pair<?,?> l2 = new Pair<String,Long>("min",64L);
l1.printPair(l2);
}
}
Java 1.5 now also has an enhanced for loop. The new enhanced for loop can replace
the iterator when simply traversing through a Collection as follows.
376 CHAPTER 15. ADDITIONS TO JSE 1.5 AND 1.6
// EnhancedFor.java
import java.util.*;
Converting between basic data types such as int, double, boolean and their equiv-
alent object-based counterparts like Integer, Double, Boolean can require unneces-
sary amounts of extra coding. especially if the conversion is only needed for a method
call to the Collections API, for example. The autoboxing and auto-unboxing of Java
basic data types produces code that is more concise and easier to follow. The fol-
lowing program gives an example. It simplifies the program GenericTypes.java
given above.
// Autoboxing.java
import java.util.*;
import java.util.List;
import java.util.ArrayList;
class DoubleList
{
public static void main(String[] args)
{
List<Double> doubleList = new ArrayList<Double>();
for(double x=0.0;x<10.0;x++)
{
doubleList.add(x);
}
for(double y=0.0;y<10.0;y++)
{
sum += y;
}
System.out.println("sum = " + sum);
}
}
378 CHAPTER 15. ADDITIONS TO JSE 1.5 AND 1.6
// StaticImport.java
// Varargs.java
Another example for using variable arguments is given in the following summation
example
// Varargs1.java
The Scanner class provides us with a simple regular expression-oriented text scan-
ner, for scanning primitive types and strings from an input source. The following
program gives an example.
// ReadKeyboard.java
import java.util.Scanner;
class ReadKeyboard
{
public static void main(String[] args)
{
System.out.printf("enter four values: " +
380 CHAPTER 15. ADDITIONS TO JSE 1.5 AND 1.6
// ProcessBuilding.java
import java.lang.ProcessBuilder;
import java.lang.Process;
Starting from version 1.6 Java includes the ability to evaluate portions of code for
scripting languages. This allows a Java program to load a custom script and execute
it. The scripts can also interact with the Java program. The classes are available
from the javax.script package. The class ScriptEngine implements the support
for evaluating scripts from a certain language. The methods eval(String) and
eval(Reader) can be used to evaluate strings in the target language or load files to
be interpreted.
Not all scripting languages are supported on all platforms. To determine whether a
scripting language is supported we use ScriptEngineManager. The ScriptEngineManager
can find the engine for a specific language
ScriptEngine getEngineByName(String)
List<ScriptEngineFactory> getEngineFactories()
ScriptEngineFactory provides details about a ScriptEngine such as the name of
the language supported and the file extensions associated with the scripting lan-
guage.
The following Java program list the available scripting engines. It then attempts
to evaluate any JavaScript files which are named on the command line. If the
JavaScript engine is not available, then getEngineByName returns null. When
trying to evaluate a script, ScriptException may be thrown. This indicates a
problem when evaluating the script, either due to an error in the script or some
other error experienced by the ScriptEngine.
// Script.java
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.Iterator;
import java.util.List;
int j;
for(j=0;j<args.length;j++)
{
System.out.println("Running script " + args[j]);
e.eval(new java.io.FileReader(args[j]));
}
382 CHAPTER 15. ADDITIONS TO JSE 1.5 AND 1.6
}
}
function fact(n)
{
if(n <= 0) return 1;
return n*fact(n-1);
}
println(fact(10));
The output will differ from computer to computer and according to the Java im-
plementation on the computer. Note that, if your version of Java does not support
the JavaScript ScriptEngine, the program will terminate prematurely due to an
exception (NullPointerException).
Chapter 16
There are a large number of web sites which provide information, news and tutorials
of Java, HTML and JavaScript. Furthermore there are web sites to download new
versions of Java, HTML and JavaScript.
http://java.sun.com/
http://java.sun.com/jdc/
http://developer.java.sun.com/
Another useful web site for Java, HTML and JavaScript is “The Web Developer’s
Virtual Library”
http://wdvl.com/WDVL/About.html
The WDVL has more than 2000 pages and some 6000 links.
http://www.niu.edu/acad/english/htmlref.html
http://developer.netscape.com/docs/
provides links to technical manuals and articles for Java, JavaScript and HTML.
The offical word on the latest standard in HTML can be found on the web site
http://www.w3.org/pub/WWW/MarkUp/MarkUp.html
383
384 CHAPTER 16. RESOURCES AND WEB SITES
http://www.w3.org/XML/
http://www.w3schools.com/
Bibliography
[1] Horton Ivor, Beginning Java 2, WROX Press, Birmingham, UK, 1999
[2] Jaworski Jamie, Java 1.2 Unleashed, SAMS NET, Macmillan Computer Pub-
lishing, USA, 1998
[5] Willi-Hans Steeb, The Nonlinear Workbook: Chaos, Fractals, Cellular Au-
tomata, Neural Networks, Genetic Algorithms, Gene Expression Programming,
Support Vector Machine, Wavelets, Hidden Markov Models, Fuzzy Logic with
C++, Java and SymbolicC++ Programs, 4th edition World Scientific, Singa-
pore, 2008
[6] Willi-Hans Steeb, Yorick Hardy, Alexandre Hardy, Ruedi Stoop, Problems and
Solutions in Scientific Computing with C++ and Java Simulations, World Sci-
entific, Singapore 2006
[7] Tan Kiat Shi, Willi-Hans Steeb and Yorick Hardy, SymbolicC++: An Intro-
duction to Computer Algebra Using Object-Oriented Programming, 2nd edition
Springer-Verlag, London, 2000
385
Index
Arrays, 22 exit, 57
BufferedReader, 54 extends, 117
Character, 76 final, 16
Color, 162 finally, 177
DataInputStream, 179 float, 13
DataOutputStream, 179 for, 31
Graphics, 153 getGraphics, 153
Image, 166 goto, 51
Iterator, 310 if, 30
JTree, 345 length, 22
Math, 55, 80, 378 length(), 37
Number, 75 main(), 8
Object, 27, 85 new, 22
Panel, 141 notify(), 245
Scanner, 379 null, 188
Socket, 282 paint, 153
String, 64 readLine(), 54, 180
StringBuffer, 72 repaint, 231
StringTokenizer, 69 return, 51
TreeMap, 321 run, 228
TreeSet, 317 static, 8, 10
available(), 190 super, 120
break, 31, 35, 51 supper, 3
case, 35 switch, 35
catch, 173 synchronized, 240
char, 14 this, 88
class, 2 throw, 173
transient, 203, 207
clone(), 27
try, 173
continue, 51
wait(), 245
default, 35
while, 31
dispose, 153
do-while, 31 Abstract class, 114
double, 13 Applet, 9
drawArc, 153 Array, 22
drawLine, 153
drawOval, 153 Basic data types, 11
drawRect, 153 Binary notation, 40
386
Bitwise operations, 40 Polygon, 34
Broadcast address, 268 Polymorphism, 4
Port, 273
Character, 14 Postincrement operator, 20
Checksum, 192, 194 Precedence, 20
Constructor, 123 Preincrement operator, 20
Control statements, 29 Primitive data types, 11
Default constructor, 123 Priority, 237
deprecated, 4 Recursion, 48
Equality operator, 14 Regular expression, 98
Exception, 173 Relational operators, 29
Remainder operator, 16
Fibonacci numbers, 50
Fields, 4 Scope, 10
Serialization, 203
Garbage collection, 22 Shift operators, 42
Garbage collector, 97 Socket, 282
Generic Types, 374 String, 14
Synchronization problem, 245
Host, 267
Thread, 228
Infinity symbol, 18 Tool tips, 336
Information hiding, 3 Two Complement, 41
Inheritance, 3, 114, 117 Type conversion operator, 11
Inner classes, 129
Interfaces, 131 Unicast address, 268
Internationalization, 218 Unicode, 14, 18
Internet, 267
Varargs functionality, 378
Layout Managers, 133
Locale object, 218 Wrapper class, 75
Logical operators, 38
Methods, 4
Modulus operator, 16, 34
Multicast address, 268
Multitasking, 228
Multithreading, 228
MVC, 341
Network, 267
Node, 267
Objects, 8
Pass by reference, 43
Pass by value, 43
387