Você está na página 1de 383

JAVA Programming

Contents

Chapter 1. An Overview of Java


1.1. Introduction to Java
1.2.Java and Object-Oriented Programming
1.3.The Java Language
1.4.Java in Practice
Chapter 2. Java for C++ Developers
2.1.Java and C++
2.2.Overview of Classes
2.3.Simplifying C++
2.4.Javadoc
Chapter 3. Object-Oriented Principles and JAVA
3.1.Procedural Programming Vs OOP
3.2.Fundamentals of OOP
3.3.Classes, Methods, and Messages
Chapter 4. Introduction to the Java Language
4.1.Java Syntax
4.2.Operators and Flow Control
4.3.Java Object Orientation
Chapter 5. Anatomy of Java Classes
5.1.Overall Structure of a Class
5.2.Object Life Cycle
5.3.Interfaces, Casting, and Reflection
5.4.Exception Handling
Chapter 6. Java User Interface Programming
6.1.User Interface Architecture
6.2.Event Handling
6.3.Useful AWT Utilities
6.4.Java Applications
Chapter 7. Features of Java
7.1.Java Packages
7.2.Threads and Synchronization
7.3.Internationalization
Chapter 8. Java Security, Networking, and the Internet
8.1.Java Security
8.2.The Applet Execution Environment
8.3.Networking
8.4.Server Issues
Chapter 9. JavaBeans
9.1.Components
9.2.Working with Components
9.3.Creating and Using Beans
Chapter 10. Java Database Connectivity
10.1.Overview of JDBC
10.2.JDBC Configuration
10.3.Connections
10.4.Querying the Database
Contents

Chapter 11. Java and Distributed Objects


11.1.Overview of Distributed Objects
11.2.An Overview of Java RMI
11.3.Creating RMI Application
11.4.Java IDL
Chapter 12. Java Animation and Images
12.1.Working with Images
12.2.Animation
12.3.Image Manipulation
12.4.Working with Sound
Chapter 13. Java Tips and Techniques
13.1.Features of the Language
13.2.Advanced GUI Features
13.4.Using the Java Packages
1
An Overview of Java
1.1. Introduction to Java

• What is Java:
Java is a powerful and versatile object-oriented programming language. It has
many of the best features of languages such as C and C++. However it also adds many
new features of its own, which make it uniquely suited to today's computing requirements.
The Java programming language was developed by a team at Sun Microsystems in
the early 1990s. The original aim of Java's development team was to produce a language
that could be used to control a wide variety of consumer electronic devices. To achieve
this, the language had to be portable - in other words, capable of running on a variety of
processors. It also had to be small, efficient, and easy to program in.
For a number of reasons, the use of Java to control consumer devices never
became a commercial reality. However by 1994 the World Wide Web had established
itself as the most significant and rapidly growing part of the Internet. It soon became
apparent that the very real benefits that Java could deliver were ideally suited to the Web's
requirements.
Programs that are small and efficient can be downloaded quickly from the Internet.
And because the programs are portable, they can execute on the many different types of
computers connected to the Internet.
Java is a powerful language, but it is simpler to learn and to program in than other
high-level languages. Its syntax is very similar to C, and programmers who use C and C++
will find it easy to convert to Java. The designers of Java deliberately left out a number of
features that are significant in C++.
The reasons that they omitted these features include the following:
The features had not proved as useful as originally intended
They make programming in C++ more difficult and error-prone
They make it less secure
C++ is an object-oriented derivative of the C programming language. However,
Java was designed from the ground up to be an object-oriented language. Virtually
everything in Java - apart from simple data types - is an object. Java's object model is
simple to understand and easy to extend. It does not support some of the object-oriented
features of other languages. For example, it doesn't have multiple inheritance, a feature
which can be confusing and difficult to use. Instead, it uses interfaces, which are simpler
to use and achieve the same effect.
Java has a rich object environment. It has an extensive collection of classes, which
are grouped together in packages. These packages deal with areas such as I/O and
networking, and simplify the programming required to develop an application.

Page 1 Go To INDEX
Java programs are architecture-neutral - they can run on any computer platform
that supports Java. You can also describe Java programs as platform-independent. When
a Java program is written, the source code is compiled to bytecodes. These bytecodes are
similar to machine instructions, but they are not specific to any particular processor. The
bytecodes are then interpreted by a Java runtime environment, which is often embedded
in a Web browser.
So it is possible to write a Java program once, and execute it on a number of
different platforms, without having to recompile the source code.
Security is one of the most important features of the Java language. When a Java
runtime environment, such as a browser, loads a Java program, it verifies the bytecodes
as safe before it allows the program to execute. In addition, the program can't call external
functions or access system resources such as the hard disk.
These features make Java a safer and more secure language than any others
currently available.
In addition to being a secure language, Java is also extremely robust. This means
that it is easy to write reliable, bug-free programs using Java. One of the reasons for
Java's robustness is that the code is checked both at compile time and at run-time.
Another reason is that Java automatically allocates and deallocates memory as needed,
thus freeing the programmer from this responsibility. The process of automatic memory
deallocation in Java is called garbage collection. In other programming languages,
inefficient memory management is a major source of errors. Java's robustness is also
enhanced by its simple object-oriented exception handling.

• JAVA and the Web:


The Internet is a worldwide system of linked computer networks. It is a
heterogeneous network, meaning that many different types of computers are connected to
it. Among the computers connected to the Internet are:
Different types of mainframes
UNIX workstations and servers
IBM-compatible PCs
Apple Macintoshes
The common factor linking all computers on the Internet is that they use the TCP/IP
protocol to communicate. TCP/IP stands for Transmission Control Protocol/Internet
Protocol. Since the mid-1990s the World Wide Web has been the fastest-growing part of
the Internet. The Web uses an Internet standard called Hypertext Transfer Protocol
(HTTP) to locate and download resources on remote computers. These resources are
usually HTML files - often called Web pages - or multimedia elements such as graphics
and sound files. HTML stands for Hypertext Markup Language.
Web pages are viewed using a browser, which displays text and - usually -
graphics. The browser also provides easy-to-use navigation, both within the document,
and to other Web pages connected by hypertext links.
Several factors have been crucial to the phenomenal growth of the Web, among
them:

Page 2 Go To INDEX
Simple, transparent navigation between documents
Rich multimedia content
Ease of creation of Web pages that can then be read by many people
Despite their advantages, however, Web pages are essentially static documents.
To incorporate any kind of interactivity into a simple HTML Web page, it is necessary to
write a CGI script, which executes on the server computer. CGI stands for Common
Gateway Interface. CGI scripts suffer from two main disadvantages:
They impose an extra workload on the Web server
They consume bandwidth
Up to now, their use has mainly been restricted to accepting input from users
through on-screen forms. This data can then be used to query remote databases.
Java was originally designed to control consumer electronic devices. To do this,
Java had to be platform-independent, secure, and reliable. However these requirements
also made Java an ideal language for developing Internet applications. In 1994 the Java
design team used the Java language to implement a Web browser. This browser is called
HotJava, and it is capable of displaying Web pages and graphics. However HotJava has
an ability that no other browser then had - it could download and execute Java programs.
Once the HotJava browser had demonstrated the feasibility of executing Java
programs, other Java-enabled browsers were quickly developed. Netscape Navigator first
implemented Java in its Version 2.0. More recently, Microsoft Internet Explorer 3.0 and
Spyglass can also run Java programs. These programs execute on the web client, thus
conserving processing power and bandwidth on the remote Web server.
The development of Java has changed the face of the Web. It is now possible to
create dynamic, interactive Web pages that incorporate Java programs. Java programs
can perform many useful functions in a Web page by:
Enhancing the user interface
Validating user input
Performing calculations
Guiding the user through remote Web sites
The key to Java's power on the Web is its ability to distribute executable content.
The reason it can do this is because of its cross-platform capabilities. Once a Java
program has been written it is compiled into platform-independent bytecodes. It can then
run on any platform that supports the Java Virtual Machine.
The Java Virtual Machine (JVM) is a theoretical computer that interprets bytecodes.
The JVM is usually implemented in software, in which case it sits between the Java
program and the computer being used. On the Web, this means any computer that can
run a Java-enabled browser. Downloading any program from the Internet poses important
security issues. For example, programs downloaded from untrusted web sites might
contain hostile code that would wipe data from hard disks. However, several of Java's
design features were explicitly included to stop such an event occurring.
For example, in Java, the standard security model is to deny the downloaded applet
access to the local hard disk.

Page 3 Go To INDEX
• The Java Environment:
The Java environment contains both compile-time and runtime elements. After Java
source code is written it is compiled into bytecodes. Bytecodes are instructions for a Java
Virtual Machine, which is a virtual computer that runs in memory. In the Java Virtual
Machine, bytecodes are executed by the Interpreter, which operates in conjunction with
the runtime system.
Alternatively the bytecodes can be converted into native machine code instructions
by a just-in-time (JIT) compiler. JIT compilers often give execution times nearly as fast -
90% - as native C or C++ programs.
You can create and run Java programs with the set of tools included in the Java
Development Kit (JDK). The latest release of the JDK can be downloaded from Sun's Web
site at http://java.sun.com. The tools in the latest release of the JDK - currently at 1.1 - include
the following:
Javac - the Java compiler
Java - the Java runtime interpreter
Jdb - a Java debugger
Javadoc - generates documentation
Appletviewer - this runs Java programs outside a Web browser
A Java source file can be created with any text editor. It must contain one or more
class definitions and nothing else, as Java doesn't permit global variables or functions. In
object-oriented programming, a class describes the general attributes and behavior of an
object. The source file will have a java filename extension. Suppose you have written a
simple Java program - the source code is in a file called FirstApp.java. To compile this,
you run the Java compiler javac and pass the name of the source file on the command line
C:\> javac FirstApp.java
The compiler now creates a file called FirstApp.class and stores it in the same
directory as the source file. The FirstApp.class file is a platform-independent bytecode
version of your program. To run the program, you use the runtime interpreter java as
follows:
C:\> java FirstApp
In this case, you pass the class name FirstApp as an argument on the command
line, not the filename FirstApp.class. The runtime interpreter now executes the FirstApp
program and prints the message to the screen.
The debugger for the Java environment is called jdb. It is a command-line tool that
can be used to debug files on the local system or remote systems.
The javadoc tool is used to create documentation from Java source code files. It
does this by searching for special comment tags embedded in the files. It then creates an
HTML file, which can be viewed with any Web browser.
The two most important types of program you can create with Java are applications
and applets. Java applications are standalone programs that execute in conjunction with a
runtime interpreter. Java applets, on the other hand, are typically smaller programs that

Page 4 Go To INDEX
are embedded in an HTML document. They execute within a Java-enabled browser such
as HotJava or Netscape Navigator.
The Appletviewer included in the JDK enables you to run Java applets you are
developing without having to launch a browser. The syntax to use the Appletviewer is as
follows:
Appletviewer URL
The URL points to an HTML file that contains a tag for the relevant applet. URL
stands for Uniform Resource Locator, an address that uniquely identifies a resource on
the Internet.

• Java Applications and Applets:


Because Java is a general-purpose programming language, it can be used to
produce many types of programs. You can use Java to create stand-alone applications,
just like those produced with C and C++. However you can also use it to produce applets,
which are small programs that execute within a Java-enabled Web browser.
Applications are stand-alone programs that are generally launched from the
command line. With Java, you can create applications that have a graphical user interface
(GUI). Most end-user applications now available have a GUI interface. But you can also
use Java to create command line applications that do not use GUI features.
Java makes it easy to create portable GUI applications that run on any supported
platform. For example the same Java bytecodes that will run on a Windows 95 computer
will also work on computers running Solaris and OS/2. So one set of source code
produces one set of bytecodes that run identically anywhere. You don't need to write any
custom code to give your program the native look and feel of each operating system it will
use, as you will get this automatically.
A Java application is a class that has a main method. In object-oriented
programming, a method is a function associated with a particular object. A Java applet, on
the other hand, does not have a main method.
Applets are small Java programs that are usually downloaded from the Internet or
some other network. They can only execute within a Java-enabled browser such as
HotJava or Netscape Navigator. They can also execute within Appletviewer, which is part
of the Java Development Kit (JDK). Applets usually fulfill certain specific functions.
Calculators, data entry forms, and navigational image maps have been implemented as
applets. Because they are usually small, they can be downloaded quite quickly. Despite
their size, applets can perform many useful roles with a minimum of code. This is because
they can take advantage of the features that are already built into Web browsers.
For instance, to display a graphic format such as a GIF file, the applet uses
functionality already built in to the browser. A Java applet is normally invoked from a Web
page. The relevant HTML file contains an <APPLET> tag and at least three attributes:
Code - the name of the file that contains the main class of the applet
Width - initial width in pixels
Height - initial height in pixels

Page 5 Go To INDEX
If the applet is located at a different URL from the source HTML file, you specify its
location with the codebase attribute. Other attributes can be used to specify the applet's
position and appearance on the Web page. Applets can be used in many ways to enhance
Web pages. For example applets are now being used to perform the following functions:
Create animations
Play sound effects
Enhance user interaction
Perform computations
Because applets are often downloaded from the Internet, it is not safe to assume
that they are free from hostile code. Therefore, some important restrictions have been
placed on applets' functionality. These security policies can vary, depending on the
browser and its settings. Applets are not normally given access to the local machine's file
system. In this they differ from Java applications, which can read and write files on the
hard disk. This is a major limitation for applets, but it is a necessary one from a security
standpoint. If an applet could read and write files, it would be easy to create one that could
corrupt or destroy data on the disk.
Another restriction that is placed on applets is network connectivity. The only
network connection an applet can normally make is with the host computer from which it
was downloaded. Again, allowing an applet unrestricted network access would pose too
great a security risk. In line with Java's object-oriented nature, an applet is itself an object.
More precisely, an applet is an extension of the java.applet.Applet class. Because an
applet is a class, it can be used as part of another applet or an application.

• The Java Language:


One of the design aims of Java's developers was to keep the language as simple
as possible. They looked at the features and design of existing programming languages.
They incorporated many of the best of these features in Java. But they also discarded
many features that had not proved worthwhile in practice. C and its object-oriented
descendant C++ are two of the most powerful and widely used programming languages
today.
So it's not surprising that Java's syntax is very similar to the syntax of these
languages. Programmers who use C and C++ will find it easy to move to Java
programming. And, because of its relative simplicity, programmers with different
backgrounds will not find Java as difficult to learn as C or C++.
Java is highly object-oriented - everything in the language is an object, apart from
the simple data types. These data types can be divided into the following categories:
Numeric data types
Character data type
Boolean data type
In Java, even the primitive data types can be encapsulated as objects if required.
Java's integer numeric data types are always signed. The integer data types are as
follows, regardless of platform:
Byte - 8-bit

Page 6 Go To INDEX
Short - 16-bit
Int - 32-bit
Long - 64-bit
Java implements floating-point numbers according to the IEEE-754 standard. The
float type is a 32-bit value, while double is 64 bits long. Java's implementation of its
numeric data types helps its cross-platform capabilities. For example, different C or C++
compilers can interpret an int value as 16-bit, 32-bit, or even 64-bit, depending on the
computer platform. In contrast, Java always handles an int as a 32-bit signed quantity,
regardless of the platform. Java's character data type char defines an unsigned 16-bit
Unicode value. The 16-bit Unicode character set contains thousands of characters from
many different world languages. This is unlike most other programming languages, which
use an 8-bit value to store a character.
Using the Unicode character set standard makes it much easier to internationalize
and localize Java programs. Java has a boolean data type, which corresponds to the
logical values of true or false. It is not possible to convert a Java boolean value into any of
the other simple data types.
Java's operators are similar to all the C and C++ operators. A useful addition to
Java is that the + operator can be used to concatenate strings. In Java, as in other
languages, arrays are groups of same-type variables. You can declare an array of any
type, and you can also use arrays of arrays. Unlike C and C++, Java arrays are actually
real objects. Java also treats strings as objects, and provides two classes to handle them.
The String class is used for constant strings, while the StringBuffer class is for strings you
may wish to modify. As in most programming languages, a string is written as text
enclosed between double quotes.
Memory management is one of the biggest challenges for programmers using
traditional languages. Inefficient and incorrect memory management is often a cause of
crashes and poor performance. In Java, the task of explicitly managing memory is
removed from the programmer - the Java run-time environment does it instead.
Java does not have pointers, or any explicit command to free memory. You can,
however, invoke the garbage collector if required. The Java run-time system manages
memory by keeping track of objects and their references. When there are no more
references to an object, it becomes a candidate for automatic garbage collection. Java's
garbage collector is a process that runs in the background, collecting and compacting
unused memory. It runs in a low-priority thread, waiting for higher-priority threads to
relinquish the CPU.
A Thread is a portion of a program that can execute concurrently with other
threads. Typically this happens when a user pauses while interacting with an application.
The garbage collector is just one example of Java's use of threads. In fact, Java was
designed from the beginning to support multithreading. It does this both at the level of the
language itself and through support from the run-time environment and thread objects.
This means that Java makes it easy to create applications that have several concurrent
processes running.
The Java multithreading model thus makes more efficient use of the computer's
resources.

Page 7 Go To INDEX
• Java's object environment:
In recent years object-oriented programming (OOP) has come to dominate the
programming world. In OOP, an object can be thought of as a software model or
representation of a real-world object. Although this seems a simple idea, it can be a very
powerful and productive approach when properly applied. Many programming languages
now claim to be object-oriented. However they often don't deliver the benefits promised by
object orientation. This may be because an object model has not proved as successful in
practice as expected. Or it may be because of compatibility requirements with older
languages.
Java was designed from the ground up to be an object-oriented language. Apart
from simple data types, virtually everything in Java is an object. But in addition to the
language itself, the Java environment contains a number of key classes that enable the
rapid development of sophisticated programs. In object-oriented programming, a class is a
template that defines the properties of a particular object.
Java's classes are kept in a number of libraries or packages, which contain related
classes. The most important of these are the core classes, which are a required part of all
Java environments on any platform. The following are the core classes:
The language package, java.lang
The utilities package, java.util
The Input/Output (I/O) package, java.io
The networking package, java.net
The language package is central to the Java language. It contains many classes
that support the built-in aspects of Java. For example, it contains the Object class, which
is a superclass of all Java classes. This means that any object you create in Java will
inherit the variables and methods of the Object class. The language package contains two
string classes for manipulating text. These are String (for constant text) and StringBuffer.
There are many ways to create string objects and, once created, the string classes
provide many powerful methods for working on them. The language package contains
classes for wrapping the simple data types as objects. It also contains a powerful Math
class, which provides many mathematical functions and constants.
The utilities package java.util provides a number of classes that implement complex
data structures. These structures represent such things as hash tables, stacks, and
vectors. These are particularly useful for more advanced applets and applications.
The I/O package java.io uses a stream model to represent all forms of I/O. For
example, there are a number of classes for handling input such as:
InputStream
BufferedInputStream
DataInputStream
FileInputStream
The input stream classes are mirrored by the output classes such as OutputStream,
FileOutputStream, and PrintStream. Java's I/O classes are very comprehensive. They
make it easy to handle normal I/O activity, but provide a large variety of tools to deal with

Page 8 Go To INDEX
special circumstances. The abstract window toolkit (AWT) is a very important package of
Java classes. It simplifies the development of graphical user interfaces (GUIs) for both
applets and applications. The AWT classes provide most of the functionality and
components that are found in modern windowing systems.
Because of Java's cross-platform capabilities, programs developed with the AWT
can run on systems as diverse as X/Motif, Mac OS, OS/2, and Windows 95 and NT. In
each case, the program will have the look and feel of the platform it is running on, without
requiring any special coding for that platform.
The java.net package contains classes that support network programming. Several
of these classes deal with the TCP/IP protocols used on the Internet. You can implement
programs that use FTP (File Transfer Protocol), HTTP (HyperText Transfer Protocol), and
SMTP (Simple Mail Transfer Protocol). Java's classes make it easier to use these
protocols than ever before, because they hide much of the low-level detail. Web
programming is simplified by the URL and URLConnection classes. URL represents a
uniform resource locator object. URLConnection accesses the content addressed by a
URL object. Other java.net classes provide access to the bare network interface. These
include the following:
Socket - TCP socket
ServerSocket - server TCP socket
InetAddress - host IP address
DatagramSocket - UDP (userdatagram protocol) socket

• Java Security:
Java's cross-platform capabilities make it ideal for creating programs that can be
distributed over the Internet. Many such programs are already available. Most of them are
applets that can be downloaded from the Web and executed in a suitable browser. The
wide availability of applets and the ease with which they can be executed poses special
security problems. For example, the source of the applet is often unknown.
This is in contrast to conventional software, where the manufacturer is known and
the safety of the product can be assumed. An applet that has been developed maliciously
can work in several ways. The most obvious of these is to disable or degrade the
performance of the computer on which it runs. A more insidious form of attack is where the
integrity of data on the computer is compromised.
The most sophisticated type of malicious program can access data and send it to a
remote computer, possibly that of a business rival. The designers of Java were very
conscious of the types of security risk that could be posed. For this reason they built in
several layers of security in the Java environment. The result is that it is very difficult to
create a Java program that can act in a malicious way. The Java compiler provides the
first line of defense in Java's security.
While converting Java source code to bytecodes, it ensures that the language's
safety rules are obeyed. The Java compiler ensures that accesses are not allowed beyond
the end of an array. In Java, arrays remain the same size from their creation to their
destruction. The compiler also performs strict type checking. This ensures that the
compile-time type and the runtime type of variables are compatible. The Java compiler

Page 9 Go To INDEX
does not perform any memory layout functions - this only happens at runtime. Memory
layout will depend on the hardware and software characteristics of the platform on which
the program executes.
Another difference is that Java doesn't have pointers like C and C++. Java
compiled code uses symbolic handles instead. These handles are resolved to real
memory addresses at run time by the Java interpreter. Java's lack of pointers or explicit
memory management provides a major security benefit. It means that a Java programmer
does not have the explicit control of memory that is sometimes used to create malicious
programs.
As you have seen, the Java compiler provides several features that ensure secure
bytecodes. However there is no guarantee that an applet downloaded from the Web has
been produced by an official compiler. Therefore another line of defense is provided by the
Java runtime environment.
When bytecodes are loaded into the runtime environment, they are subjected to a
thorough examination by the bytecode verifier. It performs a number of checks on the
code and will only pass it for execution if they are all completely satisfied. The bytecode
verifier checks that the code conforms to the Java specification. It ensures that the code
does not contain forged pointers, and doesn't access memory directly. It also checks for
system access violations. When the code has been passed by the verifier, users can be
confident that it meets a number of conditions:
Parameter types of all bytecode instructions are correct
There are no stack overflows or underflows
Object member accesses are legal
The bytecode verifier is very thorough and obviously takes a certain amount of time
to carry out its checks. However when the bytecodes are passed, the interpreter can then
run much faster, as it doesn't have to repeat any checks.
A Java program that is running may request that other classes be loaded. Naturally
these classes are checked by the bytecode verifier. They are then placed in separate
name spaces according to the origin of the class. Bytecodes that originated on the local
system are placed in the local name space. These bytecodes can be given more
privileges if they are known to be safe. Bytecodes that were downloaded from the network
are placed in a different name space devoted to that network source.
When a class references another class, it first looks for it in the local name space
that holds the built-in classes. If it doesn't find it there it searches the name space of the
referencing class. This compartmentalization of classes adds a further layer of security to
the Java environment. For example, imported classes can't emulate built-in classes, which
may have higher security privileges. A number of security features are implemented in
Java-enabled browsers. Compared to other programs, an applet's access to system
resources is severely restricted. This ensures that applets downloaded from the Internet
can't destroy or corrupt data on the local computer.
Applets have only limited access to the host operating system. They can only
access a limited number of system properties to help them perform their task. These
include the vendor name and version number, and the filename separator character. An
applet is only permitted to make a network connection to the host computer from which it

Page 10 Go To INDEX
was downloaded. These restrictions ensure that it would be almost impossible for an
applet to transmit sensitive data to a remote computer.

1.2. Java and Object-Oriented Programming:

• Object-oriented programming:
Object-oriented programming (OOP) is a powerful methodology for designing and
creating reliable software systems. In OOP, an object is a software representation that
models the characteristics of a real-world object. These characteristics may describe the
state of an object.

For example, a car object might have properties that describe its color, engine size,
and top speed.
A software object can also describe the behavior of a real-world object. For
example, a car object could have the following functions:
Starting
Accelerating
Braking
Turning
The process of combining state and behavior information in a software object is
called encapsulation. It is one of the fundamental principles of object-oriented
programming.

An object's state information is stored in its instance variables. These are generally
not accessible from outside the object. The behavior of an object is defined by its
methods. A method is essentially a function associated with a particular object. Methods
can be used to change the state of an object's instance variables.
They can also be used to create new objects. Java uses the concept of a class to
define objects. A class is an abstraction that represents a set of objects with similar

Page 11 Go To INDEX
characteristics. An object is a particular example, or instance, of a class. So we can regard
a class as a template for creating objects. An object is created by instantiating a previously
defined class. Its methods and the types of its variables are defined by the class. Because
the object is now a real instance of the original class, its variables contain real values. This
is why they are called instance variables.

A Java class's methods and variables may be marked public or private. Public
methods and variables may be manipulated by code outside the object. In contrast, private
methods and variables can't be accessed in this fashion.
An object's instance variables are usually declared private. If it is necessary to
change or access them, this is done through the object's methods. In this way the exact
details of the object are hidden from the rest of the system. Instead, a clearly defined
public interface is presented to the outside world. The ability to hide data behind a public
interface is a key strength of encapsulation. For example, the implementation details of a
class could be changed to more accurately model a real-world object.
As long as the public interface remains the same, any programs using the class will
be unaffected by the changes. So modifying an object-oriented program should be less
problematic than modifying one written in a procedural language. Another benefit of
encapsulation is that it encourages code reuse. Classes can be treated as black boxes
with known inputs and outputs. A programmer need not be concerned by the inner
workings of a class as long as the public interface is understood. A class defines the
attributes and behavior of a potential object. It is possible to derive a new class from an
existing class - a process called inheritance.
Deriving a new class from an existing class is also called subclassing. The new
class will inherit all the attributes and methods of the existing class. But it can also
incorporate new attributes and methods to define a more specific type of the object being
modeled. And it can also override the methods of the parent class, thereby changing its
behavior. Using an automotive example, we could start with a class called Vehicles.
This class would have a basic set of attributes and behavior common to all
vehicles.
We could then derive two subclasses - Car and Truck - from the Vehicles
superclass. These will have specific attributes in addition to those of the Vehicle class.

Page 12 Go To INDEX
We could further subclass Car into SportsCar and FamilyCar.

The process can be repeated as often as necessary, building up a class hierarchy.


Some object-oriented programming languages allow classes that inherit
characteristics from more than one parent class. This feature is called multiple inheritance.
Java doesn't allow multiple inheritance - it only allows single inheritance. This is because
Java's designer's believed that multiple inheritance causes too many problems in practice.
Although Java does not allow multiple inheritance, you can achieve many of its effects by
using interfaces. An interface definition is a declaration of a set of methods. It does not
explicitly specify how the methods should be implemented. Java permits classes to have
multiple interfaces.
In an object-oriented system, an object causes another object to perform an action
by sending a message to it.
The second object then invokes the appropriate method to perform the action. The
parameters passed to the method are input values to the function it performs. In java, the
objects passed to a method must match those expected. Alternatively they may inherit
from, or interface with, the required types. This makes Java what is known as a strongly
typed language.
In a procedural language, you normally need two functions with different names to
carry out two different tasks.

Page 13 Go To INDEX
In an object-oriented system a single message can invoke different methods,
depending on the kind of object receiving the message. This is an example of
polymorphism, which is a fundamental feature of an object-oriented language.
Polymorphism means "one object, many shapes".

• The origins of java


The origins of Java go back to work carried out at Sun Microsystems in 1990. A
small team of software developers got together to develop a new programming language.
The original purpose of the language was to control consumer electronic devices. Existing
programming languages such as C and C++ were not considered suitable for this
purpose.
Consumer electronic devices such as TV set-top boxes and PDAs use a wide
variety of processor chips. A program written in C or C++ has to be compiled to run on a
particular processor. Therefore a program written in one of those languages has to be
recompiled each time a new processor is introduced. Another disadvantage facing users
of other languages is the small amount of program space available in consumer devices.
The Java design team decided that a new approach was necessary. The new
language would have to be small, fast, and robust. It would also have to be able to support
widely differing types of hardware. The designers began by looking at the best features of
C++ and similar programming languages.
They developed an object-oriented language incorporating many of these features.
The first application of the language was to control a small hand-held computer they built
called the *7 (pronounced "star seven"). The user interface of *7 was a touch-sensitive
color screen, which could be used to remotely control household appliances. The next
application of the new language was to control TV set-top boxes. These devices were to
be used to deliver interactive video-on-demand. The *7 and interactive video controllers
did not evolve into commercial products. However they helped Java to develop and
mature as a reliable and effective language. The next stage in Java's evolution is related
to the development of the World Wide Web. The Web started as an Internet-based
hypertext medium in 1990. By 1993, it was moving from a text-based interface to a
graphical one, spurred by the development of the NCSA Mosaic browser.
This development resulted in a huge increase in the use of the Web, which has
since become the most popular part of the Internet. The development team soon realized
that Java would be an ideal language for developing Internet applications. This was
because many of the design aims they started out with coincided with the nature of the
Internet. For example, the Internet is a heterogeneous collection of different computers,
with many types of processors. These include IBM-compatible PCs, UNIX servers and
workstations, and Macintoshes. Many of the PCs connected to the Internet have limited
memory and processing power.
Therefore a small, efficient, and platform-independent language like Java is ideal
for programming Web applications. The first Web program developed by the Java team
was a graphical browser. Originally this was called WebRunner, but it was later renamed
HotJava. It was written entirely in Java, and functionally it was similar to other graphical
browsers then available. However, it was unique in that it could load and run Java applets.
HotJava was important in showing what the Java programming language was capable of.

Page 14 Go To INDEX
Its availability on the Internet generated a lot of interest among the developer
community. Java technology was made public in early 1995 at the SunWorld conference.
At the same time, Netscape announced that its Navigator browser would support Java
applets. This support was delivered with Netscape Navigator 2.0, which arrived in late
1995. Netscape Navigator is the world's most popular Web browser. The fact that it now
supports Java means that millions of people can run Java applets. This has been a
powerful stimulus to the development of Java programs that perform many roles. It has
also led to the continued enhancement of the Java programming language and its
environment.

• Java and C++


To understand the relationship between Java and C++, it is necessary to look at the
history of C++ and its predecessor C. C is a structured programming language that has
been around for over 25 years. Initially its success was linked to that of the UNIX
operating system. UNIX and its associated shell tools were written in C. But C's many
strengths helped it to become a very widely used programming language. The fast,
compact, and portable code it produces can extract maximum performance from most
processors. C has been used to write some of the most complex applications ever
developed. However, large programs written in C very often have inadequate structure.
This makes the programs difficult to write, debug, and maintain. To overcome these
difficulties, the principles of object-oriented programming were applied to C.
C++ is an object-oriented development of the C programming language. C++ uses
the object-oriented principle of encapsulation to bind code and data into classes. C++ was
originally called "C with Classes". C++ is also backward compatible with C. A program
written in C is also a valid C++ program, and it will be compiled by any C++ compiler. The
backward-compatibility of C++ enabled many C programmers to quickly move to it.
However it also means that C++ is not as object-oriented as it could otherwise be.
The designers of Java investigated C++ very thoroughly. When they were
developing Java they used many of the best features of C++. They used the compact,
elegant syntax of C++, and many of its object-oriented features. They also used features
from other languages such as Eiffel, SmallTalk, and Objective C.
For a number of reasons, Java's designers deliberately did not use some of the
features of C++. Some features had been included to ensure compatibility with C. Other
features that seemed fine in theory had never proved very beneficial in practice. Java is a
new programming language - it is not a development of C++. However it draws on the best
features of that powerful programming language. And its similarity in syntax means that
C++ programmers find it easy to move to Java.
One of the main differences between Java and C++ concerns the use of pointers.
Pointers are sometimes considered one of C++'s strong points, but in practice they can
cause many problems. Even a tiny error in pointer arithmetic can cause a memory location
to be inadvertently overwritten. This error may not become apparent until millions of
instructions later, when that memory address is used. This makes such errors very difficult
to debug. The use of pointers also has security implications. Most computer viruses use
pointers to modify memory locations with malicious intent. Instead of using pointers, Java
uses handles, which are symbolic references to objects in memory.

Page 15 Go To INDEX
Handles are similar to pointers, but you can't increment or change a handle in the
way you can change a pointer. Java does not use pointer arithmetic and doesn't allow
data to be converted to a pointer type. This makes it easier to write reliable and robust
code in Java. It also makes it difficult to write a malicious program such as a virus. Another
area in which Java differs from C++ is memory management.
C and C++ use the malloc() function to allocate memory and the free() function to
deallocate it. C++ introduced the new and delete functions, which are used in a similar
fashion to malloc and free. These functions often cause problems in programs written in
these languages. For example, when free() is used on a pointer that has already been
freed, the program usually crashes. And if a programmer forgets to free a memory location
no longer in use, a memory leak occurs.
Java uses the new operator to allocate space for an object on the memory heap.
Instead of returning a physical address, new returns a handle for the object. The
programmer does not have to worry about the actual memory location of an object - Java's
memory management looks after this task. Java keeps track of the objects that are in
memory and all references to them. When there are no longer any references to an object,
the memory space it occupies is released for reuse.
This is known as garbage collection, and it runs as a background process. Freeing
the programmer from this type of housekeeping makes Java code more robust and
reliable.
Some of the differences between Java and C++ relate to the fact that Java is a
more truly object-oriented language. Apart from simple data types, everything in Java is an
object. For example Java does not have functions. Instead of creating a function, you
define a class and create a method for that class.
C and C++ permit you to use global variables. The use of global variables can
cause many problems, especially in complex programs. When one part of a program
modifies a global variable, it can have a completely unforeseen effect on a different part of
the program. Java's object orientation is evident in the area of global variables. In Java, it
is impossible to create a global variable that is outside the class hierarchy. Although Java
allows you to have public static variables in a class, their use is not encouraged.
C++ uses structures to create complex data types. Java does not have structures. If
you want to create a complex data type in Java, you declare a class with the appropriate
instance variables. One of the fundamental features of any object-oriented language is
inheritance. C++ allows a class to inherit the characteristics of more than one class - a
feature known as multiple inheritance. Java only allows inheritance from a single class.
However, in Java you can achieve the equivalent of multiple inheritance by using
interfaces. In this context, an interface is a declaration of a set of methods and constants -
no variables may be defined.
One of the most misused features of many programming languages is the goto
statement. It is often used simply to break out of nested loops, and its use encourages
badly structured code. Java does not have a goto statement. Instead it uses the break and
continue statements in conjunction with labeled blocks.
One of the design aims of Java was to be a much simpler language than C++. To
this end, Java does not have the following features of C++:
Preprocessor #include <iostream>

Page 16 Go To INDEX
#defines #define pi 3.14159
Typedefs typedef double (*(fp3)())[10]();
Header files
Some of these C++ features can make it very difficult for one programmer to
understand another programmer's code. To understand how a C++ program works, you
have to read all the associated header files, #defines, and typedefs. In Java, instead of
using a typedef you simply declare a new class. Similarly, instead of using a #define you
just use constants. Java doesn't need header files because the type information is
compiled into a class file by the compiler.
These differences between Java and C++ make Java code easier to write,
understand, and reuse. C++ allows automatic coercion of a data element from one type to
another, in such a way that precision can be lost. For example, the value of a floating-point
variable can be assigned to an integer variable, thus losing precision. In Java you have to
explicitly cast the floating-point variable to an integer before making such an assignment.
Java's data types are similar to those in C++.
However a problem with C++ data types is that their implementation depends on
the compiler and the computer platform. For example, an integer data type may occupy
16, 32, or 64 bits, depending on the platform.
In Java, each data type has a fixed size, which does not vary. This helps to ensure
that Java programs will run consistently on all supported platforms.

1.3. The Java Language:

• A Java applet - a step by step


Applets are small Java applications that can be downloaded over a network from a
server and executed on a client machine.

The applet's name and location are inserted into an HTML document, using the
<APPLET> tag. They are downloaded and executed automatically as part of the Web
page. Applets are normally animated sequences of graphics or enhanced interfaces, but
can be used for any purpose that Java's wide functionality will allow. Let's look at a sample
applet now.

Page 17 Go To INDEX
The applet we will look at here is among the simplest possible. It displays a small
message reading "Click Here" inside a rectangle on screen, and responds to a mouse
click with a "Thank You" message. Additionally, some output is directed to the Java
console and the status line of the browser.

The first two lines tell the browser to import two relevant packages. The first
package is the AWT, or Abstract Windowing Toolkit, which contains classes and methods
responsible for building the user interface and handling events.
The second package, Applet, is responsible for defining the classes and methods
associated with applets. Here we define a public class, called ClickHere that is an
extension of the standard Applet class. The standard Applet class contains many methods
that define the behavior of an applet on screen. We will see here just a small subset of
those methods. "implements MouseListener" specifies that this class will handle mouse
events. There are five mouse events that need to be implemented:
MouseClicked
MouseEntered
MouseExited
MousePressed
MouseReleased
We are only interested in mouseClicked events in this applet. DisplayString is a
string variable that contains the text message we will display to the user. The initial value,

Page 18 Go To INDEX
when the applet starts, will be "Click Here". A String is the standard class used for string
handling in Java. A series of methods is inherited from the Applet class. These methods
are called in a predefined sequence:
Init
Start
Update
Paint
Stop
Destroy
For the purposes of this example, we will override the init and paint methods and
will let the default methods control everything else. The init method is the first method
called in the sequence and is only called once - when the applet is first loaded. The init
method is normally used to initialize variables.
Here we tell the system to start sending any mouse events to the applet for
handling. The keyword "this" refers to the current object - in this case the class ClickHere.
The standard output is to the Java console, and here we have chosen to display a
welcome message.
If you have a browser, it will probably have an option to view the Java console. The
Java console is useful for debugging applets. This is the paint method. It is called
whenever the visual appearance of your applet is modified in any way. It is also called
automatically when the applet starts. The paint method receives a Graphics object, which
we have called g in this example. The setColor method sets the default color value. A set
of predefined color values is available: black, white, red, green, blue, cyan, yellow,
magenta, orange, pink, gray, darkGray, and lightGray.
In this example, we have chosen to display the rectangle's border and the text
messages in blue. This method call draws a blank rectangle at the uppermost left location,
with a width of 150 pixels and a height of 80 pixels. The 0,0 coordinate is the uppermost
left point in the applet's display area. Then we use the drawString method to place the
contents of DisplayString on the screen, beginning at a point 50 pixels to the right and 20
pixels down from the origin (0,0).
The mouseClicked method is called by the event handler when the user clicks the
mouse button.
The showStatus method sends output to the browser's status line, usually at the
bottom of the browser screen.
Here it presents the message "Welcome to ClickHere!".
Here, we change the value of DisplayString to reflect that the mouse click event has
occurred. However, the user will not see this new value until we rerun the paint method.
Here we force the paint method to run again - with the repaint method call. In this
example, we are not interested in handling any type of mouse event other than
mouseClicked.
However, the JDK 1.1 delegation event model specifies that when implementing
MouseListener we must provide methods for all the possible types of mouse event. These

Page 19 Go To INDEX
four empty methods are included only to ensure compliance with JDK 1.1 when we
implement MouseListener.
Once you finish writing a Java applet, you need to compile it.
C:\>javac ClickHere.java
You do this by entering javac on your command line, followed by the applet file
name. The applet file name must be identical to the class name, including the case of the
letters used to type it. It must end with a java extension. So, in this example the file name
is ClickHere.java. If the file compiles without errors, the compiler creates the class file.
It is the same as the class name, but with a class extension.
C:\>ClickHere.class
To run an applet you need to call appletviewer, or embed the applet into a Web
page and run your browser.
To run an application, you simply type java on the command line, followed by the
name of the java class. You use the java class name, rather than the java class file name
as you might have expected.

• Embedding an applet into an HTML document


The sample HTML document labeled FIGURE 1.3.1 illustrates how to insert an
applet into a Web page. The applet is inserted into the body of the HTML document,
between the <BODY> and </BODY> tags, at the place where the document's author
wants it to appear. The <APPLET> and </APPLET> tags enclose all the information
required for the browser to download and run the applet. This example uses just a few of
the many attributes that can be associated with the <APPLET> tag.
We will first look through this simple example and then go on to look in detail at the
syntax of the <APPLET> tag. The first attribute to notice is CODEBASE.
This tells the browser the location of the compiled class file of the applet. The
CODEBASE can specify the location relative to the HTML source file or else as an
absolute URL and directory.
The CODE parameter specifies the name of the applet class file. This will be the
compiled file of the applet. Finally, the WIDTH and HEIGHT parameters specify the size of
the display rectangle containing the applet.
All such size values are specified in pixels, not in inches, millimeters, or other
absolute units of measurement. These sample HTML lines are enough to display simple
applets.
Now let's look at the full syntax of the APPLET tag, to see what other features are
available. We will then see a fuller example of the APPLET tag in action.

Page 20 Go To INDEX
Words in uppercase, like CODEBASE, are the reserved attribute names. Attributes
may be of mixed case in the final HTML document and they are illustrated here in
uppercase for the purpose of clarity only. Attributes in square brackets [], are optional,
while the others are mandatory. Let's go through each of the attributes in turn.
The CODEBASE parameter specifies the base URL and directory of the file
containing the applet code. Normally it is defined relative to the HTML source directory.
Alternatively, it can be an absolute URL, pointing to a server and directory where the class
resides. If the attribute is not specified then the default location is taken as the HTML
document's base directory.
The CODE attribute specifies the name of the compiled applet, and is mandatory.
This value must be relative to the base URL of the applet as specified with the
CODEBASE parameter, and cannot be absolute. Some browsers do not understand the
<APPLET> tag at all. In that case, any HTML text between the <APPLET> and
</APPLET> tags will be displayed in the normal way. Java-aware browsers will, however,
ignore this untagged text and will try to execute the applet. Some browsers may not be
able to run the applet, either because they are not fully Java-enabled, or because they
refuse to run the applet, perhaps on security grounds.
In these cases, the ALT parameter specifies alternate text, which can be displayed
instead of running the applet. HTML authors are advised to use these parameters to
provide alternatives for users who do not have Java-enabled browsers.
The NAME parameter gives the applet a unique name within the HTML document.
This allows for interaction between named applets on the page. The same applet can
even be used more than once, but at different locations, in the document. The browser will
only load the applet class file once.
The WIDTH and HEIGHT parameters, in pixels, give the initial applet display area
size. The optional ALIGN attribute specifies the alignment of the applet within the
displayed page. If you are familiar with the <IMG> tag, then these values will be familiar. In
fact, they are the same values and operate in the same way. The possible values of the
ALIGN attribute are self-explanatory:

Page 21 Go To INDEX
Left
Right
Top
Texttop
Middle
Absmiddle
Baseline
Bottom
Absbottom
The VSPACE (vertical space) and HSPACE (horizontal space) attributes specify, in
pixels, the free space around the applet. This gives the HTML author greater cosmetic
control of the applet.
The <PARAM> tag allows the HTML author to pass parameters to the applet at run
time. Parameters allow applet users - the HTML authors - to customize general-purpose
applets for particular purposes. Applet authors can give their applets greater flexibility
through the judicious use of parameters.
The applet itself reads these values by using the getParameter() method and by
specifying the name of the parameter they wish to retrieve. The two PARAM attributes are
NAME and VALUE.
The NAME attribute value is a string that is the name of the parameter.
The VALUE attribute is the string representation of the parameter value.
All values are passed to the applet as strings, so applets must convert the string to
the data type they require.

Now let's see a larger example of an <APPLET> tag in an HTML document.

Page 22 Go To INDEX
Here we have specified that the middle of the applet should be aligned with the
middle of the baseline of the preceding text, with 10 pixels of space surrounding it on all
sides. We have also specified the text that should appear if the browser does not execute
the applet for any reason. This applet takes three parameters:
Speed
Warning
Exitmessage
Their values, in turn, are:
"23"
"Do not click this button!"
"Goodbye"
Remember that the speed value, "23", is a string value, even though we may want
to pass an integer. The applet developer must convert this string into its relevant value - in
this case, an integer with a value of 23.

• Applet example - address book


Let's look at a larger applet now. It shows how Java developers can implement a
user interface and data storage across the Internet. We will look at how the applet appears
to an end-user, and see how it was implemented in Java code. This applet allows you to
view, add, and delete address book entries. Address book entries consist of a name, an
address, and a phone number. The applet uses two buttons, Add and Delete, as well as
three text fields for name, address, and phone number, and a scrollable box for listing the
currently stored names.

Page 23 Go To INDEX
Here we have a full set of entries with the first name highlighted in the list. Tom's
details then appear in the three fields to the right. Pressing the Add button creates a new
entry at the bottom of the list. The values are initialized as "undefined". To add a name,
you type it into the text box and press Enter. You can add a series of names, addresses,
and phone numbers in this way. You delete entries by first selecting them in the scroll box.
Then you press the Delete button, and the entry disappears. The Java code that
implements the address book applet is included as a footnote.
You can scroll through the footnote to see how real Java code looks. Further
courses in SmartForce's Java curriculum will cover the Java language syntax and object-
oriented techniques necessary for a full understanding of the address book applet code.
Five classes are used in the address book applet:
ValueChange
Person
PersonPanel
PersonList
PersonApplet
The classes send each other messages in response to user events.

A Person object is made up of three strings, one each for name, address, and
phone. It responds to messages by broadcasting changes to "Observers" (a Java core
class).
The ValueChange class holds a Person object, a description of the changed item,
the new string, and the old string. PersonPanel displays the Person details and broadcasts
changes to Person details by the user.

Page 24 Go To INDEX
PersonApplet displays two buttons (Add and Delete), a PersonList, and a
PersonPanel.
PersonList displays the list of Persons in the left hand side display box. It is a
subclass of List, an AWT component. A List is a scrollable list of text items that a user can
choose from.
This code, for example, defines the ValueChange class as public and as an
extension to the Object class.

It has four private variables:


oDescription - a String type
oObject - an Object type
oValueNew - an Object type
oValueOld - an Object type
These private variables cannot be accessed by other classes.
This code appears at the top of the PersonList file.

Notice how the first two lines import from the AWT and UTIL core class packages.
Notice how the PersonList class is an extension to the List class.
oStringChangedName is defined as a static String type, meaning that it is shared
by all instances of the class. It is declared to be final, meaning that it cannot be changed
by any inheriting subclass. Variables with the modifiers static and final before them are
constants in Java.
oVector is defined as a private Vector type. Vectors are Java's name for
dynamically allocated lists of objects.
This code appears in the PersonApplet class file.

Page 25 Go To INDEX
These lines, for example, instantiate two Button classes, called oButtonAdd and
oButtonDelete. These lines add those buttons to the panel display area. These lines of
code instantiate and then add a PersonList to the applet display area.
This code, in the PersonApplet class, handles user events, such as clicking the Add
and Delete buttons.

These lines test the event argument, aoEvent, to see if the user clicked inside the
list box. If so, the code then tests to see if the Event was a LIST_SELECT event or not.

1.4. Java in Practice:

• JavaBeans:

Page 26 Go To INDEX
An important advantage of object-oriented languages, such as Java, is their ability
to reuse software components. Software reuse reduces development time and cost, while
increasing flexibility. Also, software from third-party vendors, in forms such as tool kits, can
be purchased by developers and integrated with their own software.
The ability to integrate software components from different, independent sources is
provided for in Java by the JavaBeans API specification. Java beans are reusable
software components that are designed to be:
Simple to use
Compact
Portable across multiple platforms
They enable the reuse of existing software and the dynamic integration of
independently developed software elements. In keeping with the Java philosophy,
JavaBeans is a platform-neutral component architecture model. The JavaBean API is
compatible with existing component architectures, like:
IBM and Apple's OpenDoc
Microsoft's ActiveX/COM/DCOM
Netscape's LiveConnect
OMG's (Object ManagementGroup's) CORBA
Java beans link to these platform-specific component architectures through bridges
developed and supported by JavaSoft's industry partners. Java beans can be GUI
widgets, non-visual functions or services, or larger applications. The emphasis during the
design of JavaBeans was on the smaller software components likely to be distributed over
networks. But JavaBeans also support much larger software applications.
A component model architecture typically provides five types of service:
Component interface publishing and discovery
Event handling
Persistence
Layout control
Application builder support
Components register their interfaces so that they can receive and process event
notifications from other components. This means that the two interacting components can
be linked dynamically at run time, rather than at build time. The component can export
properties that can be modified or accessed by external components. These properties
are accessed or modified through the component's public methods. Events are the means
by which two components interact at run time.
Events are raised by one component and are then delivered to the appropriate
component for event handling. The persistence mechanism enables the storage of
component-state information in a non-volatile medium for later retrieval. This means that
the two interacting components can be linked dynamically at run time, rather than when
they are built.

Page 27 Go To INDEX
An automatic Java serialization method is available for simple persistence. A layout
mechanism defines how components are visually presented. This mechanism defines a
component's layout, both within its own space and in relation to the other visual
components of a container. A container holds an assembly of related components. Builder
tools enable you to assemble an application using user-friendly GUI tools. But builder tools
must have access to the internal properties of components and be able to modify them at
design time.
Builder tools use application builder support interfaces to determine a component's
properties and available methods. A component developer can define design-time
property editors within the component. Property editors allow greater flexibility in the use
of components. A bean must be able to run in the design environment of the builder tool.
This allows users to customize the action and appearance of the bean.
JavaBeans is designed to work well for distributed applications.
The JavaBeans API is optimized for local, virtual machine operation rather than
network access. Three primary network access mechanisms are available to JavaBeans:
Java Remote Method Invocation(RMI)
CORBA IDL
JDBC - Java Database Connectivity
These are either established industry standards or adaptations of them. JavaBeans
will extend Java's strengths in key areas, while still retaining its platform independence

• What's new in JDK 1.1?


The latest Java Development Kit, JDK 1.1, includes new versions of the Java
Virtual Machine, Java class libraries, and development tools. JDK 1.1 has major quality,
performance, and feature enhancements, but is still fully backward compatible with JDK
1.0.2. The major new features include
Internationalization
Security, AWT, and networking enhancements
JAR files
Remote method invocation
Object serialization
They also include
Reflection
JDBC - Java database connectivity
Inner classes
New Java native method interface
Performance enhancements
Let's look at each of these new features.

Page 28 Go To INDEX
Internationalization allows the development of localizable applets. Developers can
create applications that can readily be adapted to different languages and country-specific
standards, like time and dates. This extends the "Write Once, Run Everywhere" Java
design goal. The internationalization features include:
Use of the UNICODE 2.0 character set standard
A locale mechanism
Localized message support
Locale-sensitive date, time, time zone, and number handling
They also include
Collation services
Character set converters
Parameter formatting
Support for finding character/word/sentence boundaries
The previous version of the Abstract Windows Toolkit (AWT) was inadequate in
many respects. JDK 1.1 features a greatly enhanced AWT, with a number of strong
performance improvements, particularly for Windows environments. These changes
enable Java applications to assume the look and feel of the user interface of the platform
on which they are running.
The AWT 1.1 lays the groundwork for the upcoming JavaBeans component model
architecture. It contributes to a richer infrastructure for larger-scale GUI development. The
new AWT is compatible with the earlier AWT, so existing Java applications and applets
will continue to run. AWT 1.1's enhancements include:
Printing
Easier and faster scrolling
Pop-up menus
Mouseless operation
Clipboard support
They also include
Desktop colors
Separate cursors for each component
Delegation-based event model
Imaging and graphics extras
More flexible font support for internationalization
JDK 1.1 allows developers to create distributed Java-to-Java applications. The
methods of Java applications on other Java virtual machines can be accessed through
Remote Method Invocations (RMIs). RMIs will even connect applications on different host
computers. References to remote objects must be obtained by the client, or calling,
application. A reference can be obtained in one of two ways:

Page 29 Go To INDEX
By using the bootstrap-naming service provided by RMI
Through receiving the reference as an argument or return value
RMI relies on Object Serialization to pass parameters and method calls.
Object Serialization, an extension of the core Java I/O classes, enables the
encoding of Java objects into streams of bytes and their subsequent decoding. This
means that RMI does not need to truncate types, thus supporting true object-oriented
polymorphism. A standard SQL database access interface is provided through Java
Database Connectivity (JDBC). It provides uniform access to a wide range of relational
databases. JDBC is implemented in terms of the ODBC standard C API, the de facto
standard for creating platform-independent interfaces to enterprise databases. The Java
security API allows developers to incorporate low and high-level security features into their
applications.
Eventually, Java security will feature cryptography, key management, and access
control. JDK 1.1 includes a subset of this functionality, comprising:
Digital signatures, including the ability to sign classes, images, sounds, and
other data
Message digests to give unique identifiers to digital data
Key management
Access control lists
JAR (Java ARchive) is a platform-independent file format based on the widely-
available ZIP format. It is useful for archiving groups of data files into a single compressed
file format. Additionally, it is ideal for making HTTP transfers of applets more efficient.
Using this format developers can aggregate and compress multiple files associated with
an applet, including images, sounds, and the class file itself.
A single HTTP request will then suffice to download all of an applet's associated
files, which is much more efficient than downloading them separately. JAR files are
compressed using the ZIP format, further improving efficiency. Additionally, individual
entries in a JAR file can be digitally signed to authenticate their origin. JAR is written in
Java, so is fully extensible. JAR files are fully backward compatible with earlier applet
code. The Java reflection API provides the ability to obtain information about Java objects,
within certain security constraints.
Certain types of applications need to use reflection to discover underlying
information about classes in the Java Virtual Machine at run time. For example, Java
beans might require run time access to the public variables, methods, and constructors of
a component. Debuggers, interpreters, inspectors, and class browsers require run time
access to the implementation of a class in the class file.
JDK 1.1 allows Java developers to apply the concepts of lexical scoping and block
structure to their Java code, using inner classes. Lexical scope refers to the range of code
within which an object remains active or available.
Block structured languages promote the hierarchical structure of code, in which
some procedures are implemented within higher-level procedures and their scope,
extends only to its enclosing procedures. Lexical scoping and block structuring greatly
simplify many types of development problems.

Page 30 Go To INDEX
Inner classes are defined as members of other classes, either locally within a block
of statements, or anonymously within an expression. Previously, all classes were
members of packages and were top-level classes only. Inner classes can use both class
and instance members of enclosing classes, and local variables of enclosing blocks. Inner
classes are implemented at compile time; so do not require any changes to the Java VM.
Inner classes can be used to implement adapter classes. An adapter class is an
object's interface to the outside world. For example, an adapter might receive events from
AWT and JavaBean components for passing to its enclosing object.
In Java 1.1, an adapter class is most easily defined as an inner class placed inside
the class, which requires the adapter. Code written in another programming language -
called native methods - may often need to be accessed by a Java programmer. The
reasons for using native methods may include the wish to use:
Existing libraries written in another language
Time-critical code written in assembler
Platform-dependent features accessible only through anon-Java language
Use of native methods is not encouraged as it breaks the portability and security
models of Java. Native methods should only be used as a last resort.
JDK 1.1 introduces a new Java Native Interface (JNI), with the primary goal of
having binary compatibility of native method libraries across all Java VM implementations
on a given platform. Java developers should be able to write a single native application
that will work, without change, with all Java VMs supporting the JNI. By programming
through the JNI, you can use native methods to:
Create, inspect, and update Java objects, including arrays and strings
Call Java methods
Catch and throw exceptions
Load classes and obtain class information
Perform run-time type checking
Finally, JDK 1.1 also introduces some platform-specific performance
enhancements:
Interpreter loop in assembly code on Win32and Solaris/Sparc
Non-contiguous heap support on Mac
Monitor speed-ups
AWT peer class re-write for Win32
Garbage collection of classes
Optional use of native threads on Solaris

• The potential of Java:


Java is still an evolving language and development platform. Demands from the
development community mean that Java will continue to see new core APIs, industry

Page 31 Go To INDEX
initiatives, tools, applications, and other additions. Some of these additions, which will
greatly increase Java's potential, include:
The 100% Pure Java initiative
Proposed expansions to the Abstract WindowsToolkit (AWT)
Network computers and HotJava Views
Let's see what some of these initiatives will entail.
100% Pure Java is a marketing and technology initiative, which aims to ensure
cross-platform compatibility of all Java network applications. All applications seeking the
designation "100% Pure Java" must pass a test suite designed to ensure strict compliance
with the Java specifications.
All such applications will be officially certified and allowed to carry the 100% Pure
Java logo. There will be assistance for Java developers trying to pass their applications
through the test suite. A marketing drive for certified products is also anticipated in the
near future. Products may also receive Web-site exposure through a "100% Pure Java
Hall of Fame".
JavaSoft see their Abstract Windows Toolkit (AWT) as a critical component of Java.
The extensions to the AWT in JDK 1.1 are the first phase of a planned expansion to Java's
GUI capabilities. The next phase, due in 1997, will include many proposed new features.
The planned features include:
A lightweight component framework
Peerless components
Pluggable look-and-feel
Drag-and-drop capability
Java 2D for complex rendering
Let's look more closely at these planned features.
In AWT 1.0.2 there is a one-to-one mapping between components and windows,
resulting in three main problems. Firstly, windows are inefficient, so having too many of
them is a bad way to implement multiple components.
Secondly, windows are opaque - they do not allow transparent regions.
Thirdly, consistent handling of windows across different platforms is difficult.
The solution to the windowing problem is to make components that can share the
windows of their containers. So, new windows do not have to be opened to display these
components. These new lightweight components will ensure much lighter weight
interfaces. And they are all implemented in Java code, ensuring their platform-
independence. Some application developers require a common look-and-feel for their
Java applications, even across different platforms. Currently, the Java AWT delegates
look-and-feel responsibilities to sets of platform-dependent peer classes. Unfortunately,
this sometimes makes component appearance hard to alter.
The AWT must account for cross-platform inconsistencies, and there is no option
for a common look-and-feel. Peerless components and pluggable look-and-feel will allow
developers the option of creating cross-platform common look-and-feel. The peer option

Page 32 Go To INDEX
will be retained for those who want the applications to have the look-and-feel of native
programs.
Pluggable look-and-feel will allow customization of look-and-feel at several different
levels. A new general data transfer architecture and an API for clipboards is included with
JDK 1.1. This will be extended to include a drag-and-drop API in a future release of the
AWT. Only basic rendering capabilities are included in JDK 1.1. A new Java 2D API will
have many complex rendering facilities, including
Arbitrary transformations, such as rotation and scaling
Image composting
Sophisticated text handling
Java's distributed cross-platform nature qualifies it as the language of choice for
distributing software to network computers (NCs). PCs and their applications were
designed to cater for the broadest possible set of users. Because of this, applications are
generally large, monolithic, and function-rich. These applications require large amounts of
disk space. In addition, software updates are delivered as upgrades to existing
applications, an expensive and often time-consuming operation. Java will change this
software distribution model.
It is hoped that much smaller and easier-to-maintain network computers (NCs) will
replace many PCs. Network computers do not require local disk storage. Instead, they rely
on retrieving application software from a central server over a network. Software is
downloaded to the NC when, and if, a user requests it. Users will only use the software
and functionality they absolutely require. Regular manual upgrading of application
software is eliminated. Users can switch hardware while still retaining their own individual
environments, which would be stored centrally.
Unlike the old model of centralized mainframes serving a network of dumb-
terminals, network computers do their own computing. By using Java, administrators can
provide users with many types of hardware, from NCs to PCs, knowing that the central
application software will run across all those platforms. Thus, networks of NCs are
scalable.
HotJava Views is a specially written user environment for some NCs. It is drastically
slimmed-down compared to a typical PC environment, with its main functionality consisting
of e-mail, calendar and scheduling, a name directory, and internet browser. System
administrators will benefit from HotJava Views because of:
Zero client administration costs
Minimal software distribution costs
Easy network computer replacements
Users will benefit from
Ease of use
Powerfully integrated, yet simple, applications
A virtual user environment regardless of location

• Java development environments:

Page 33 Go To INDEX
Java is still in its infancy as a language, but some important development tools
have already been created for it. These tools make the full power of Java available to
applications developers through sophisticated visual development aids.
Most of them also include ready-made Java components for reuse by
programmers. Let's have a quick look at the main features of some of these development
environments now. The tools we will discuss are
Sun's Java Workshop
IBM's Visual Age
Symantec's Visual Café
Borland's Open JBuilder/Latte
Microsoft's Visual J++
Sun's Java WorkShop tool is written almost entirely in Java and HTML. The tool is
embedded in a browser-like environment, and its screens look like traditional web pages.
Its screens are navigated using standard browser controls. This allows running and
debugging of applets in the development environment, without having to launch another
program. You use a Visual Java design tool to define the visual aspects of the application,
and then generate code around it. Help is in HTML format and an on-line tutorial is also
provided.
The debugger is fully integrated with the tool's environment, providing a smooth
development and debugging cycle. Because of its design features, Sun's Java WorkShop
is highly portable. The Java WorkShop environment is easy to adapt to, since it relies on
familiar browser interfaces. It illustrates well the Web-friendly aspects of Java.
IBM's VisualAge for Java tool emphasizes support for applications that need to
access centralized databases. This tool adheres to Java's JDBC standards for database
access. IBM is also developing JDBC drivers for its own database architectures.
Also, JavaBean components can be built from database schemas obtained through
VisualAge's Data Access Builder. These beans can then be combined visually with other
beans to form the finished application.
Application developers using VisualAge for Java can make use of a variety of
protocols, including CICS, to communicate with databases. Also, code can be altered
during execution, a very useful feature when large applications are involved.
Symantec's Visual Café builds on their earlier Café product. It combines a visual,
component-based programming model with an advanced Just-in-Time (JIT) compiler and
virtual machine. In fact, Netscape are to integrate the JIT compiler into their Web
browsers, for extra efficiency and performance.
The source code editor supports the highlighting of keywords for both Java and
HTML. Classes are managed using two tools:
The class browser
The hierarchy editor
Visual Café provides full support for both the new AWT and JavaBeans. Its visual
interface allows you to place controls such as buttons or labels onto a screen and
generate the code automatically. There is even a SlideShow component for combining

Page 34 Go To INDEX
.PNG and .JPEG files into applets. Visual Café allows the two-way control of visual
objects.
Changes to the visual object automatically results in changes to the underlying
code - and vice versa. This is an important advantage when adjusting visual interfaces.
Visual Café's advanced features include a very fast Just-in-Time (JIT) compiler, an
Interaction Wizard, and a debugger. The Interaction Wizard, for example, allows you to
generate code handlers. You place an object over another on screen.
The wizard then presents you with a list of options to choose from. The option
defines the interaction that you want for the two objects and the code is then generated
automatically for you.
Borland's Open JBuilder/Latte tool follows closely their earlier Delphi product. It
aims to be a high-productivity rapid applications development (RAD) environment. The
basic components Open JBuilder/Latte uses will all be Java beans. All Open
JBuilder/Latte's tools are two-way - meaning that modifications to code are reflected
immediately in the appearance of components, and vice versa. Borland have designed
Open JBuilder/Latte to be freely extensible. Third-party tools can be added at will to the
basic configuration.
Over time, a suite of such tools is expected to enter the marketplace. Open
JBuilder/Latte's database access facilities include JDBC drivers for ODBC and Borland's
own BDE. Microsoft's Visual J++ builds on their Visual C++ tool. It emphasizes a
traditional 3GL development paradigm and has:
Enhanced source file editing
Excellent debugging features
Support for ActiveX components.
You edit source files using a FileView tool, which features customizable syntax
highlighting of Java and HTML, and keystroke recording. You can generate application
and applet versions of your code by setting a simple flag. Passing parameters from HTML
<APPLET> tags is also made easy, and default HTML pages can be generated for your
applet.
When debugging, you have full control over watchpoints and breakpoints. You can
inspect a variable's values by placing the cursor over it, or by dragging it to a watch
window. Visual J++ also includes Microsoft Internet Explorer 3.0, allowing you to debug
multiple applets on the same HTML page.
Visual J++ supports ActiveX components, and Microsoft are planning for
ActiveX/JavaBeans interoperability.

• Internet case studies:


The Web was not specifically designed for client/server computing. You can try to
develop client/server applications using the HTML/CGI protocols. However, there are
many disadvantages to this approach.
Firstly, there is no client-side validation of CGI forms. Every form, once filled-in, has
to be sent to the server for validation, resulting in needless network traffic and long delays.
And transaction-oriented applications do not work because HTML/CGI interactions are

Page 35 Go To INDEX
"stateless". That is, once information is passed, the connection between the client and
server is broken. You must explicitly manage the state of the transactions between the
client and the server - a time-consuming and difficult task. You can only access database
records one at a time, which means users will often have to waste time waiting for extra
records to be downloaded from the server.
You will not be able to scroll through lists of related records, except in the most
limited of ways. Now, Java extends the Web's capabilities to include complete client/server
applications. Java applets overcome the limitations of HTML pages alone, or HTML
combined with CGI.
Because Java is a complete language, all business-logic validation can take place
on the client side, reducing network traffic and speeding up interactions considerably.
Datasets can be cached locally and navigated by the Java applet within its own memory
space.
And state management logic can be built into the Java applets and applications.
Unify Corporation has used Java in this way to create a client/server development tool that
overcomes traditional HTML/CGI weaknesses.
VISION/Web, an extension to Unify's mature VISION product, is a high-end 4GL
development tool that generates Java code. Unify's VISION is a mature product, offering
automated GUI programming and data access capabilities. The VISION run-time
environment has been completely rewritten in Java to produce VISION/Web.
VISION's message-based architecture means that state management is built-in and
transparent to the developer. VISION/Web uses native database drivers on the server side
to greatly speed up database access. Entire applets can be written without recourse to
HTML, CGI, Java, or JavaScript programming.
There are some minor limitations to VISION/Web when compared with the VISION
tool. The VISION/Web development environment restricts screen widgets to those
provided for in the Java AWT.
Some 4GL statements are not translatable into Java code, such as attempts to
invoke system calls or access the hard disk. VISION/Web provides
A secure virtual machine environment
Platform and browser independence
Client-side business logic
Traditional network applications suffer from several constraints such as:
Limited bandwidth across the internet reduces the practical size of
applications.
Applications written in most languages are platform-dependent.
They are constrained by the HTML/browser framework within which they run.
Marimba Inc. is using the power of Java to help eliminate these problems. Their
Castanet system offers a new software distribution paradigm, which will overcome
bandwidth limits, platform dependence, and security concerns.
Marimba Inc. was founded by members of the original Java development team and
is supported by JavaFund. Kleiner, Perkins, Caufield, and Byers (KPCB), a leading

Page 36 Go To INDEX
venture capital firm focused on technology companies, announced the $100m JavaFund
in August 1996. JavaFund is designed to promote Java-related ventures. Java's built-in
platform independence and high security have made Castanet possible. Castanet is
comprised of
Channels
Tuners
Transmitters
Channels are applications and content delivered over the internet like applets, but
which operate like applications and are stored locally on the user's hard disk. Channels
are ideal for applications requiring real-time regular updates to content or functionality.
Tuners are client-resident programs that download, install, and request updates for
channels. Transmitters deliver the channels to tuners. They use differential updating
techniques. This means that only those files that change need to be redelivered to the
user. You use channels much like any other locally resident application.
But you will also obtain regular updates to the channel, completely transparently.
You might get access to sports results, interactive games, news updates, or financial
reports.

Page 37 Go To INDEX
2
Java for C++ Developers
2.1. Java and C++:

• Overview of principal similarities:


If you have used C or C++ for some time, then Java syntax will appear familiar to
you. Java shares its look and feel with C and C++. These similarities will ease your
introduction to Java. In fact, you should be able to guess what these sample lines of Java
code do, even if you have never seen a Java program before.

This is a comment, followed by a while loop with two statements in its body. Notice
that this form of comment is the same in Java as in C and C++. There are two other types
of comment in Java. We will cover them later. And Java also has while loops, as in C and
C++. And notice the use of the “!” operator too. Incrementing a variable with the shortened
C syntax - using the ++ operator - is also possible. And assignment with an operator is
also possible.
Braces delimit statement blocks, just as in C and C++.

Page 38 Go To INDEX
Despite these similarities at the syntactic level, there are quite significant
differences between Java and C++. Java has no:
Pointers
Struct, union, or enum

Typedef or #define

Sizeof
#include

But don't worry - these features and keywords, and the concepts they represent,
have been implemented in a simpler and safer way in Java. C++ was designed specifically
as an object-oriented extension to C. It is a superset of C, and C programs will compile as
C++ code. Another way to put it is to say that C++ is backwardly compatible with C. Java
is wholly new, and was not designed to be backwardly compatible with any other
language, including C++. However, the designers did base much of the syntax on C/C++.
Statement separators, flow control statements, operators, and array access are all
largely the same. You will recognize Java keywords like:
While

If, else

Switch,
case

For

Int,

Page 39 Go To INDEX
float,
double

Java and C++ have many common primitive types. However, Java is much stricter
when defining implementation details and default values for these types. Numeric types
have strictly defined bit sizes, for example.

And all numeric variables are set to zero in the absence of explicit initialization. The
if/else, do/while, while, switch/case, and for flow control statements are all nearly identical
to those in C/C++.
The main difference is that Java conditions return boolean false or boolean true, not
0 or 1 as in C/C++.

Of course, you will quickly notice several key differences between Java and C++.
As we have already seen, pointers are missing in Java. As a result, memory handling,
linked lists, and parameter passing are all implemented differently in Java. And there is no
need for the sizeof keyword either, since memory allocation for objects is handled
transparently by Java.
The preprocessor, header files, typedefs, and #defines have all been removed or
replaced. Arrays are declared and allocated differently, but are otherwise quite similar to
C/C++ arrays.
Strings also bear many resemblances to C++ strings, but the + operator for string
concatenation is built-in to the language. Structs, unions, and enums have all been
removed. But they can all be implemented in other ways in Java.
In general, Java and C++ share enough features to make it easy for you to learn
Java. But you should be wary of assuming that superficially similar code is, in fact, the
same.

Page 40 Go To INDEX
• Common Syntax:
Most of the basic syntax in Java is identical to C/C++.

The semicolon still separates statements in Java. Braces enclose statement blocks.
Parameters still appear between parentheses (). Array elements are accessed using valid
integer expressions within square brackets []. Java code is free-format. You are allowed to
indent your code in whatever way you like. And you can put as many spaces or lines
between statements as you think appropriate.
Assignment, and assignment with operators have been retained in Java. You can
use three types of comment in Java. The first begins with a /* and continues until the first
*/ sequence is found. You are not allowed to nest /* */ comments. As in C++, you can
insert a comment on a line starting with two slashes // and continuing until the end of the
line is reached.
A good tip is to use // comments within your code blocks, so that if you want to
comment out a section of code later, you don't have to worry about inadvertently nesting /*
... */ type comments.
There is a special "doc" comment beginning with /** and continuing till a */ is
reached. Doc comments are usually placed before declarations. This type of comment is
used in conjunction with the javadoc tool to produce online documentation.
Identifiers are composed of letters and, optionally, digits. But they must begin with a
letter.

Underscores (_) and dollar signs ($) count as letters too.

Identifiers are case-sensitive. So, "theLargestInteger" is not equivalent to


"thelargestinteger".

Page 41 Go To INDEX
Identifiers can be of unlimited length. This allows you great flexibility in choosing
meaningful names for your classes, variables, and methods.

• Types and arrays in Java


Java emphasizes simplicity, platform-independence, stability, and ease of use.
These characteristics are especially apparent, in comparison to C/C++, in the primitive
data types. The full list of primitive types in Java is:
boolean

char
byte

short
Int
Long
Float

Double

You will notice that Java has the same primitive types as C, but adds the two new
types of boolean and byte.

The boolean type has only two possible values - "true" or "false". It replaces the
conditional expressions of C/C++, where 1 or 0 is returned. This makes programs more
readable and less open to confusion. Having a boolean primitive type means that certain
"tricks" in C/C++ are no longer valid in Java. For example, testing for a decrementing
counter to reach 0 is not valid. So the line "while (i--)" must be replaced with an explicit test
that returns a boolean value, like "while (i-->0)".

Page 42 Go To INDEX
Booleans may not be cast to or from any other types, including integers.

The new type, byte, is an integer of length eight bits. It is a useful primitive type
when dealing with I/O and lower-level data manipulation. Java's implementation rules for
numeric types are much stricter than those for C or C++. All integers are signed and each
type occupies a strictly defined number of bits. You can be guaranteed that when you use,
for example, a short integer, it will be implemented in 16 bits. This is important for ensuring
platform-independence.

In C or C++, you cannot assume anything about the value of uninitialized variables.
In Java, there are standard default values for each type.

If you do not explicitly initialize variables, they will be set to this default value by the
interpreter.
All integers (byte, short, long, and int) are signed. Variables of type byte, for
example, range from -128 to 127, and short integers from -32768 to 32767. This means
that you cannot use the keyword "unsigned", as in C/C++. Integer literals in Java are
equivalent to those in C and C++. Here are some valid bytes as they could be initialized.

Hexadecimals and octals are defined by preceding the literals with "0x" (zero x) or
"0" (zero) respectively.

Page 43 Go To INDEX
You place the letter "L", in upper or lower case, after an integer literal to specify that
it is a long integer.

Floating-point literals can have an "F", or "f", appended to indicate that they are of
type float. "D", or "d", indicates that they are of type double.

These are examples of valid float and double literals.

The letter "e", or "E", denotes an exponential value. For example, 7e3 evaluates to
a float value of 7000.00.
Variables of type char are 2-byte, 16-bit Unicode characters. In most cases this
makes no difference to the way you use characters or strings. The first 128 Unicode
characters are identical to the ASCII set used in C. Using Unicode makes
internationalization easier.

Some Unicode character literals may not be displayable on certain platforms, so


Java offers a way to refer to them using the "\u" escape sequence. These are valid
Unicode characters.

Notice too, the use of standard C/C++ escape sequences.


String literals are defined between double quotes, as in C.

Page 44 Go To INDEX
You are also able to use the + string concatenation operator.
Arrays in Java closely resemble arrays in C and C++. Arrays are non-primitive
types, and share features of the Java Object class. Both objects and arrays are passed by
reference, whereas primitive types are passed by value. For this reason, objects and
arrays are called the reference data types. You declare and instantiate arrays in much the
same way as other objects, using the "new" keyword.
Square brackets in declarations, either after the type or object identifier, or after the
array identifier, indicate that an array is being defined.

Arrays can also be statically initialized. The compiler automatically calculates the
array size.

Multi-dimensional arrays are defined, as in C, as arrays-of-arrays.

Just like C, multi-dimensional arrays can be non-rectangular, or "triangular".


Triangular arrays have to be allocated dynamically in C, while they may be allocated
statically in Java. This example shows how a two-dimensional array of arrays of varying
sizes is allocated statically in Java.

You access array elements exactly as in C - by putting a valid integer expression


between square brackets after the array name.

Page 45 Go To INDEX
The Java interpreter checks array bounds, and if they are too low or too high it
throws an exception. Exception handling in Java will be covered in a further unit.
Strings are implemented as instances of a class called String, in the java.lang
package. Packages and classes will be fully explained in Unit 2, Overview of classes.
They are not null-terminated arrays of characters, as they are in C/C++

Having a class for strings means that you can use a full range of methods to
manipulate them. You can convert booleans, integers, and floating-point numbers to
strings using the valueOf method. For example, this code initializes two String types to
represent an integer and a double respectively.

Strings (that is, String objects), once initialized, are immutable - there is no way for
you to change their contents. You must use the StringBuffer class instead. Bounds
checking takes place at run time, as with arrays, and exceptions are thrown if invalid
accesses are attempted. Strings can be initialized with double quotes ( " ) and, optionally,
the + operator. The + operator concatenates two strings.

• Flow controls and operators:


The if/else, while, do/while, switch/case, break/continue, and for flow control
statements are almost identical in Java to their C/C++ equivalents. There is a
try/catch/finally statement for use in exception handling. This will be covered in Unit 3,
Simplifying C++. You are, however, forced to use proper boolean expressions, that

Page 46 Go To INDEX
evaluate to either true or false, in test conditions. That means, for example, that testing for
an integer to decrement to zero is not valid in Java.

Additionally, the test expression must be placed between parentheses, as in C and


C++. The switch statement is the same in Java as in C/C++. Here we show a simple
switch statement.

Values of type short, int, byte, or char can be used as values for the case labels.
You may not use long integer types as values for case labels.
The goto statement is banned in Java, and is replaced by a combination of the
break and continue statements and labeled loops.

You may notice that "goto" is a reserved keyword in Java, but is not implemented. A
compiler error will result if you try to use "goto" as an identifier in your code. A break
statement inside a while, do, or for loop stops the execution of that loop, as in C/C++.
This code, for example, shows two break statements - one inside a for loop and
another inside a while loop. The key difference in Java is that you can label loops with
identifiers, followed by a colon, as in this example.

Page 47 Go To INDEX
Notice the top_loop label before the while keyword. An optional label can follow the
break keyword. If there is a label following the break, then control transfers out of the
enclosing statement that the label refers to. You use "continue" in much the same way. It
stops the execution of the current loop cycle, but restarts at the beginning of the loop
again.
Java supports nearly exactly the same set of operators, as does standard C.

Generally, you can assume that all operators you have used in C or C++ are usable
in Java. But Java does not support one or two C/C++ operators, and has some extra ones
of its own. We will consider these here.
You cannot combine two or more expressions into one using the comma operator.

But you may use the comma operator to declare and initialize variables. And the
"for" statement allows the comma operator, but only in its initialization and increment
sections. Java has no pointers, so there is no need for the reference and de-reference
operators, "*" and "&" respectively. And the sizeof operator is redundant for the same
reason.
Java does not treat array access and field access ("[]" and "." respectively) as
operators. The + operator for Strings is a new operator. Although it looks like operator
overloading, it isn't, because Java does not encourage operator overloading.

Page 48 Go To INDEX
Integer numbers are all signed.

Therefore, the right shift operator, >>, maintains sign. The >>> operator is added to
allow for unsigned shifting.
The “&” and “|” operators, when applied to Boolean types, evaluate both their
operands, even if the result is determined after evaluating the first operand. The “&” and “|”
operators applied to integral types do bitwise evaluations as in C and C++. However, “&”
and “|” applied to Boolean types in Java perform Logical "AND" and Logical "OR"
respectively. You use “&&” and “||” operators to perform boolean evaluations without side
effects.
Here, you can clearly see that (i++>100) evaluates to false, and that the whole
expression then evaluates to false.

But using the “&” operator, the int j is incremented – a side effect of evaluating the
second operand. The "&&" operator would not increment j, since it would cease evaluating
the boolean expression after finding the first operand false.

2.2. Overview of classes:

• Introduction to classes and objects:


Classes are the fundamental units in Java. A class is a collection of data and
related methods that operate on that data. In fact, all data and functionality in a Java
program are organized into classes. Java's insistence on organizing data and methods
into classes is much stricter than C++'s object orientation. Java uses classes to implement
the key object-oriented concepts of:
Encapsulation
Inheritance
Polymorphism
Encapsulation involves hiding data within a class and only allowing access to it
through methods you define. Inheritance involves creating subclasses that inherit the data
and methods of their ancestor classes. Polymorphism involves using the same method
name to operate on multiple classes. Classes are the mechanism through which objects
are defined in Java. Objects are instances of classes. Classes define a 'template' for
objects, while objects are dynamically created to represent instances of those classes. So
a running Java program consists of interacting objects, which are all instances of classes.

Page 49 Go To INDEX
Many instances of a single class can exist side-by-side in a Java program. Methods
operate on the data in the class. Data may include primitive types or other classes. The
uppermost class in the Java class hierarchy is the Object class. Another way to put it is to
say that it is the root class.
All other classes inherit from this Object class, either directly or indirectly. That is,
they are all subclasses of Object. This means that all classes in your Java programs can
use the methods defined for the Object class. For example, one useful method is called
equals.

It returns boolean true if object1 and object2 refer to the same object. A class that
inherits from another class is called a subclass of that superclass. Subclasses inherit, or
"acquire", the data and methods of their superclasses. But they can also override those
inherited methods.
Overriding a class means redefining its functionality. Classes are split into three
basic components:
Class declaration
Data
Methods
A class declaration is composed of
Optional class modifiers - public, final, abstract
The keyword "class"
The class name - any valid identifier
Optional clauses - extends, implements

Let's look at a simple example of a class declaration. Here is the keyword, class.

The class name is Fractions. The Java convention is for classes to begin with an
uppercase letter. We have specified an access modifier of "public", meaning that Fractions
is visible everywhere. And we explicitly state that Fractions is an extension, or subclass, of
the class Object.
It is not strictly necessary to specify that we are subclassing, or extending, Object. If
you do not explicitly specify which class you are extending, the default is "extends Object".
Here, the class name is "Employee".

Page 50 Go To INDEX
The class access modifier used in this example is "public". Then the data for the
class is defined. The Employee class has two Strings for names, an employee number,
and a salary amount.
Finally, the methods that operate on the data in the class are defined. Objects need
to be declared and then instantiated. Let's define a new Employee object and call that
Employee "johnny".

Strictly speaking, "johnny" is a variable that references an object of type Employee.


Precede the object identifier, johnny, with the class name, Employee. We have only
declared that johnny refers to an Employee object, and have not instantiated that object
yet.
Objects are instantiated using the new operator. Notice how we initialized johnny's
first name, surname, employee number, and salary. We are using a special method
defined for this purpose in the class - a constructor method.
Constructors are methods, which have the same identifier as the class name and
are used to initialize new objects. Java allows us to declare and allocate objects in a single
statement. You just combine the declaration and instantiation into a single line, as here.
Object data is accessed using the dot operator, ".".

Page 51 Go To INDEX
So, to access the social security number of an Employee in our example, we would
use this syntax. The variable currentEmployee is an int (an integer type) variable that
takes on the value of johnny's employeeNumber. To invoke a method on the Employee
class is also quite simple. Just use the object name, a dot, and the method name with any
relevant arguments.
This line increases johnny's salary by 7%, for example.

Or we can access his salary by calling the access method getSalary.

• Inheritance in Java:
You can extend a class in Java to create subclasses.

In this example, we have declared a new class called PartTimeEmployee to be an


extension of Employee. The class you extend is called the superclass of the subclass.
In this case, the superclass is Employee and the subclass is PartTimeEmployee.
You may, in turn, extend those subclasses indefinitely. For example, we can extend
PartTimeEmployee to create a new class StudentEmployee.

This means that one subclass may be the superclass of another class. As you can
see, the terms subclass and superclass are relative.
Class declarations are of this form.

The usual convention is to place the first letter of class names in uppercase. There
are only three class modifiers:
Public
Final
Abstract

Page 52 Go To INDEX
The public class modifier means that the class is visible everywhere. The class can
be subclassed and objects can be instantiated from it anywhere in a program. The final
modifier means that the class cannot be subclassed. In turn, all methods of a final class
are final too. Clearly, final methods cannot be overridden, since the class cannot be
subclassed. Final classes and methods allow the compiler to perform certain optimizations
to the code. And the interpreter does not need to dynamically look up the class and its
methods. The keyword abstract indicates classes that are not fully implemented, or which
contain methods that are not fully implemented.
The implementation must be provided by a subclass. They must be subclassed and
their abstract methods implemented before they can be used.
Abstract classes cannot be instantiated, since they are missing vital implementation
details. And they cannot be declared final since they must be subclassed to be of any use.
There are two optional clauses in the class declaration:
Extends
Implements
The "extends" keyword, followed by an identifier, indicates the superclass. But
remember, you cannot extend a final class. A class inherits the data and functionality of its
superclass, and the superclasses of its superclass. If you do not explicitly specify a
superclass, as in this example, then the default superclass is Object.

Even if you extend from a class other than Object, that class or one of its ancestors
will be a direct extension of the Object class. So, all classes have Object as an ancestor.
Object is the only Java class that does not have a superclass. All Java classes
inherit the methods of Object. All Java classes belong to a single class hierarchy
beginning at Object - the root class - and continuing to the lowest-level classes. There is
no multiple inheritance in Java, although it can be simulated using interfaces. For more
information on interfaces, see the CBT Systems course Anatomy of Java classes. Each
subclass inherits the data and methods of all its ancestors.
Inheritance is subject to the access modifiers used, and is discussed later. That's
why all classes inherit the methods of the Object class. Object has no data to inherit, only
methods.

Page 53 Go To INDEX
The diagram illustrates a sample class hierarchy for the Employee class and its
subclasses. There are three subclasses of Employee - PartTimeEmployee,
ContractEmployee and FullTimeEmployee. And there is a single subclass of
PartTimeEmployee - StudentEmployee. Let's imagine a simple scenario.
PartTimeEmployees do not work a full week. Their salary will be specified as an
hourly rate. And their weekly salary will be the rate multiplied by a new variable - called
hoursWorked.

Here we have defined a class, called PartTimeEmployee, and added an extra


variable - hoursWorked. This is the body of the PartTimeEmployee constructor method.
There are two important keywords to mention here - "super" and "this".
The super keyword refers to the immediate superclass of this class. It is used here
to invoke the constructor of the Employee class. If you decide to explicitly invoke a
superclass constructor, it must be the first statement in a subclass constructor.
Alternatively, it can be used to call overridden superclass methods.
The variable "this" refers to the currently instantiated object. It is used here to
differentiate the object's hoursWorked variable from the parameter hoursWorked.
Although a subclass inherits all the data and methods of its superclass it can still
override the methods of its superclass.
This is the salaryIncrease method, as defined in the Employee class.

Let's see how to override this class in the ContractEmployee class. Imagine a
situation where it was a company policy not to give contract workers salary increases of
more than 5%. Thus, we must change the salaryIncrease method to reflect this fact.
This method overrides the Employee salaryIncrease method.

Page 54 Go To INDEX
Notice that their names are identical. And the types and number of their arguments
must be identical too, although the argument names can be different. And notice how you
can still call an overridden method, using the super keyword. Here we see the data
declared for the Employee class.

Notice how these variables are either defined as public or protected. Just like
classes, data and methods within a class can have access levels, or visibility levels, set for
them.

• Class methods and class variables:


Let's examine the data declared for the class Employee. These are what are
termed instance variables. There is a separate copy of these for each instantiation of the
Employee class. But there may be cases where we want a single variable to be available
to all instances of the class Employee. We call these variables class variables or static
variables. They are declared using the "static" modifier. Let's define a new variable called
latestEmployee under the statement:
protected float salary;
static int latestEmployee = 0;
LatestEmployee contains the employee number of the most recently instantiated
Employee. Class variables are initialized when the class is loaded. Instance variables, on
the other hand, are initialized when an object is instantiated.

Page 55 Go To INDEX
So, latestEmployee will be set to 0 before any instances of Employee are created.
We access class variables by preceding the variable name with the class name.

Within the class, of course, the class name is unnecessary.


Here we have a method in a different class that accesses the latestEmployee class
variable. Constants are special cases of class variables. They are defined as "static final".
Being static, the same copy of the variable is accessible to all instances of the class.
Being final means that it cannot be modified after it is defined. Let's look at an
example of a constant in Java. Let's say it was company policy to limit pay increases for
contract workers to a maximum of 5%.

This line of code declares an increaselimit constant of 5 (percent). The methods we


have seen so far have been instance methods. They are invoked through calls on objects.
Class methods, on the other hand, are methods, which are called through the class.
You have seen this line of code before.

It is the default method invoked when you try to execute a Java class. The static
modifier keyword declares the method, main, to be a class method. Class methods have
some interesting properties.
They are invoked using the class name, rather than an object name. They may not
invoke instance methods or refer to any instance variables in the class. And they cannot
use the "this" keyword, since they are not invoked on an instance of the class. Class
methods are useful when you want to define a method that will be used independently of
any object in that class.
If you do not refer to instance variables or instance methods in your method, then
consider using a class method. Static initializers are used to initialize class variables, and
are executed only once, when the class is loaded. This allows more complex initializing
than allowed when declaring them. But these static initializers have some peculiar
features.
First, they do not need a name - since it is obvious that a class can only have a
single static initializer. And they have no arguments, since the system calls them
automatically. And for the same reason, there are no return values. A static initializer is
declared with just the static keyword and curly braces. The code operates under the same
rules as class methods:
No access to "this" variable

Page 56 Go To INDEX
No access to instance variables
No calls can be made to any instance methods

• Packages and the import statement:


Java classes are organized into packages. Packages usually contain groups of
related classes. Every class is a member of a package. The package statement appears
as the first statement in a Java file. The package's fully qualified name follows the package
keyword.

In this case, the package is called company.people.


Package names mirror the directory structure of the class files. Thus, all classes in
the company.people package must appear in the path company\people (or
company/people).
Access to classes from within a package is different from access from external
packages. For example, a protected variable is accessible to another class within a
package, but inaccessible to packages from outside. Protected variables can be inherited
by subclasses in other packages, but cannot be accessed by them.
In other words, how you structure your packages can determine class, variable, and
method access. If you do not specify a package name in your files, then your classes
become part of an unnamed default package. The import statement is not to be confused
with the C language directive, #include. It does not read in, or load, the referred-to
packages or classes.
It simply allows the programmer to refer to classes directly, without having to
precede them with the package name. The java.lang package is imported by default into
every Java program. So when you refer to Object, which is in the java.lang package, you
do not have to refer to it as java.lang.Object: just Object will do. The import statements
appear after the package statement and before anything else. There can be an unlimited
number of them. There are only two forms of the import statement. Here's the syntax for
the first form of import statement.
Import package_name.class_name;
Here we can directly refer to the class name in the import statement, without
preceding it with any package name. So:
import java.awt.peer.ContainerPeer;
Means we can refer to ContainerPeer throughout our code; Here's the syntax for
the second form of the import statement:
import package_name.*;
It allows us to directly refer to all classes in the relevant package. Thus,
import java.util.peer.*;
Allows us to access such classes as ContainerPeer and ListPeer without preceding
them with the package name.

Page 57 Go To INDEX
Regardless of the package that a class belongs to, it is stored in a separate file.
The name of the file is the class name, followed by a ".class" extension. A single source
file can have multiple class definitions but only one public class. The name of the source
file must be the name of its only public class followed by the extension “.java”. We could,
for example, store all the Employee-related classes in a common file, called
Employee.java.

• Advanced classes:
A key concept in object-oriented programming is that of data hiding, or
encapsulation. Data inside a class should only be accessed by trusted methods. This
prevents illegal, unwanted, or arbitrary access to data in a class. Similarly, variables within
methods should be protected from access by other methods.
Local variables exist in Java, just as in C and C++. Local variables can only be
accessed within the relevant method (or statement block).

In the salaryIncrease method we have defined a local variable called increase. It is


allocated upon every invocation of the salaryIncrease method and does not require any
access modifiers.
You use access modifiers to control the level of access to your classes, methods,
and variables. Access modifiers are sometimes referred to as visibility modifiers. Data and
methods within a class are sometimes referred to as class members. Let's consider
visibility modifiers for class members. These access levels determine which classes or
subclasses can access a variable or method, and also whether a subclass can inherit that
member. There are, in fact, four levels of access, or visibility modifiers, for class members:
Default
Public
Private
Protected
The default visibility, indicated by the absence of a keyword, allows for access and
inheritance within a package only.

Page 58 Go To INDEX
Classes outside the package cannot access or inherit the class member. When you
define your class members so as to have public access, you make them completely visible
to all classes, both inside and outside the package that the class belongs to.

You use public access for methods or variables that need to be accessible from
anywhere. Private variables or methods are not visible anywhere outside the class in
which they are defined.

They cannot be inherited by subclasses either. You should only use private visibility
for members that are only used within a class and nowhere else.
Protected class members are visible only within the same package.

Page 59 Go To INDEX
They are not visible to subclasses from external packages. However, they can be
inherited freely by subclasses in any package. The salary variable was declared as
protected in our Employee class.

This means that classes in other packages can only access salary directly if they
are a subclass of the Employee class.
Alternatively, other classes could use the access method specified for salary -
getSalary. Early versions of Java included the "private protected" access modifier. The
private protected access modifier is not supported in versions after 1.0 and you should not
use it in your code. Good practice dictates that you should use the strictest data hiding
possible. If classes or class members do not need to be visible outside of a class, you
should make them private.
Every Java class has at least one constructor method. Constructor methods have
the same name as the class they are defined in. There can be several constructor
methods for a class, and they are differentiated by their argument lists.
All object creation, using the new keyword, involves invoking one of a class's
constructors. Any initialization for a new object takes place in the constructor. If you do not
define a constructor, then Java provides you with a default. This default constructor takes
no arguments and performs no special initialization.
It merely makes a call to the superclass constructor, which has no arguments.
Constructors return "this" implicitly. Returning "this" implicitly means:
No return type is specified in the method declaration
The "void" keyword is not needed in the declaration
No return statement is required
It is possible to define multiple constructors for a single class, all with the same
name. They are differentiated through their argument lists, which must be different.
Constructors within the same class can invoke one another. This saves having to

Page 60 Go To INDEX
duplicate very similar code between two constructors. You use the "this" keyword to refer
to the constructor that corresponds to the argument list you use.

This example shows how to call another constructor in the same class using "this".
The constructor is identified through its argument list - a single integer in this case.

You call a superclass constructor by inserting the super keyword followed by an


argument list between parentheses. This must appear as the first statement in the
constructor body.
Here, the PartTimeEmployee constructor calls an Employee constructor. If you do
not explicitly call a superclass constructor, then Java inserts a call to super() anyway. That
is, it enforces at least one call to the constructor of the immediate superclass. If the first
line of a constructor block is a call to another constructor within the class then Java
postpones a call to super(). Instead, it invokes the explicit constructor in the normal way.
That constructor will either explicitly invoke a superclass constructor, or else Java
will enforce an implicit call to super() from that constructor. A constructor for
StudentEmployee invokes, either explicitly or implicitly, the PartTimeEmployee
constructor. It, in turn, invokes the Employee constructor. And that constructor invokes the
Object constructor.
Thus, all constructors, in a chain from the bottom of the class hierarchy to the top,
are called either explicitly or implicitly. This is termed constructor chaining. When Java
garbage-collects an unreferenced object, it frees up any memory allocated to the object.
However, there may be resources held by the object, which you need to explicitly
free. You do this through finalizers. Finalizers are a bit like constructors, but are invoked at
object destruction instead of object instantiation.
However, they have no arguments and return no values. Finalizers are all called
"finalize". A typical example of a finalize method declaration is shown here.

Page 61 Go To INDEX
Finalizers are only ever called once in the lifetime of an object, just before garbage
collection. Some finalizers may store the "this" reference somewhere, thus keeping the
object alive and preventing it's garbage collection. In this case the garbage collection is
cancelled.
But the finalizer is not re-called when it is garbage-collected again. The compiler
makes no guarantees about when, or even if, a finalizer is called. If the program finishes
before all objects are dereferenced then they are not garbage collected at all.
In this case, the operating system is usually responsible for freeing held resources.
Garbage collection takes place transparently to the user, and cannot be controlled by the
programmer. Be careful never to assume that finalizers will always be called, or called in
any particular order. Unlike constructors, finalizers are not implicitly chained.

You may make an explicit call to a superclass finalizer with super.finalize() instead.
super.finalize() method always works because finalizers are all called finalize, have no
arguments, and return nothing.

2.3. Simplifying C++:

• Pointers and casting:


Several important features of C++ are not present in Java. Some of these features
are omitted with the intention of making Java a safer and more robust language than C++.
The most important example of this type of feature is pointer arithmetic. In C++, a pointer
is a special type of variable that contains a memory address. It can be used to select and
manipulate the addresses of functions and data. Pointers can be used in C++ for several
purposes. For example, you can access an array element with a pointer instead of using
the bracket operator [].
You can also pass the address in memory of an argument to a function, rather than
its value. Using pointers enables a programmer to directly access memory. It also enables
dynamic memory allocation, which is useful when the size of objects is not known until run
time. Despite the power of pointers, it is undeniable that they are the cause of many bugs
in C++ programs.
A small error in pointer arithmetic can cause a memory location to be inadvertently
overwritten. This type of bug often takes a long time to find and correct. Java does not
have pointer arithmetic like C++ has, and it doesn't allow data to be converted to a pointer
type. However it achieves much of the functionality of pointers by making extensive use of
references.
A reference acts like a pointer, although it is actually a handle. A handle is a
symbolic reference to an object in memory. In Java you use the object itself, rather than a
pointer to it, as you would in C++. This is not a major restriction, as nearly everything in
Java is an object. For example, strings and arrays are Java objects. Simple data types
such as int and float are not objects.
But you can treat them as objects by using the appropriate data type wrapper class.
These wrapper classes can be found in the java.lang package.

Page 62 Go To INDEX
Generally speaking, only experienced programmers are able to make effective use
of pointers. It is much easier to write error-free code by using references to objects than by
accessing them with pointers.
And extra security is provided by the Java runtime system, which performs
boundary checking on array operations. Both C and C++ have a feature called automatic
coercion.

This happens when one data type is implicitly converted to another type. This
process can lead to a loss of precision.
In this example, a floating-point value is assigned to an integer variable, thus losing
the fractional part. Another case in which precision can be lost is when a data type of a
certain length is converted to a type of shorter length. This happens, for example, when a
64-bit long is cast to a 32-bit int. In this case the compiler will remove the upper 32 bits of
the long value, possibly causing a loss of accuracy. Unlike C and C++, Java does not
permit automatic coercion of data types. If you make an assignment that could possibly
cause a loss of precision, the compiler will generate an error. You must explicitly cast the
variable to the required type. This is done by putting the desired type in parentheses to the
left of the variable to be cast.

Certain rules should be followed when casting to avoid losing precision.

An integer can be cast to another integer type or to a floating-point type. However,


a floating-point type cannot be cast to an integer type. The char type, which is a 16-bit
Unicode value, can be safely cast to int, long, float, or double.
Finally, it is important that the size of the destination type is never smaller than the
source type.

• Defining types in Java:


Two of the design aims of Java's developers were to make that language:
Simpler than C++

Page 63 Go To INDEX
More object-oriented than C++
It is evident that these objectives have been achieved when you examine how the
languages allow you to define data types. Java's built-in data types are very similar to
those of C++. The few small differences between the languages were included to ensure
that Java's data types are platform-independent. But Java's approach to user-defined
types is quite different from, and much simpler than, that of C++.
In Java everything apart from simple data types is an object. Therefore if you want
to define your own data type, you have to write a class to define it. A Java class is very
similar to a C++ class. Both Java and C++ classes consist of
Data members
Methods
Access specifiers
In both Java and C++, access specifiers can be public, private, or protected. There
is a slight difference between the two languages in what protected means. In Java, all
classes within the same package have access to protected variables. In C++, only
subclasses have access to such variables. In a Java class you must define the access
specifier individually for each variable.

Another difference is that Java does not have the C++ scope resolution operator
(::).

Page 64 Go To INDEX
C++ has several constructs that enable a programmer to create user-defined data
types. One of these constructs is the "struct". The "struct" was originally developed for C,
where it allows you to group together several pieces of data and treat them as a unit. C++
expanded the idea of a "struct" to include member functions. For backward-compatibility a
"struct" that is valid in C is also a valid C++ "struct". Java does not have any "struct"s - you
simply use a class instead. You can make the instance variables and methods in your
class private or public, as required. The absence of "struct"s makes the language simpler,
without losing any functionality.
Another feature in C++ for creating user-defined data types is the union. A union
acts like a single variable, but it can store different data types at different times. The
purpose of the union is to conserve memory. This is because it only occupies the space
needed by the largest data type defined, not the total space needed to store all the data
types it can represent. Java again simplifies matters by dispensing with unions - you can
use a class instead. Java's memory management model makes the use of unions
redundant.
C and C++ programs use enums to associate numbers with a list of words. An
enum variable is actually an int. Java does not use enums - you can achieve the same
effect by defining constants.

• The C++ preprocessor:


One of the most important aims of Java's designers was to make the language
simple to read and understand. They based many of Java's features on C++. However
they omitted features, which, they believed, made C++ difficult to read and understand.
One of these features was the C++ preprocessor. The preprocessor is also used in C
programs. Before C++ source code is compiled, it first runs through the preprocessor. This
is a program that searches for preprocessor directives, which are commands preceded
with the number sign (#).
It modifies parts of the source code as directed by the preprocessor directives.
Finally it writes the output to an intermediate file, prior to compilation. Three of the most
widely used preprocessor commands are as follows:
#include - include a library header file

Page 65 Go To INDEX
#define - define a macro
#ifdef - this is for conditional compilation
The preprocessor is a feature that C++ inherited from C. Java's designers
dispensed with the preprocessor because it makes programs harder to understand and
maintain. However Java does not forfeit any functionality by not having a preprocessor. In
C++ the header files contain the external declarations for the libraries being used by the
program.
They are distributed along with the compiled binary code - not included inside it.
This arrangement can cause many problems in practice. With large class libraries, it can
be very difficult to ensure that the correct versions of the header files are being distributed
with the compiled code.
In addition to this compatibility problem, using header files makes the code difficult
to maintain. To fully understand C++ source code, it is necessary to read all the
associated header files. This can make it very difficult for one programmer to maintain
another programmer's code.
Java avoids these problems by dispensing with header files completely. It uses the
import statement to include classes in other packages.

In Java, the import statement is similar to the C++ #include statement. However,
the Java import statement simply allows a program to more easily reference other pre-
compiled classes whereas the C++ #include statement includes the external definition of
the referenced classes.
The imported classes can then be referenced in the source code of the Java class
file without having to specify the full package name. In C and C++, #define is often used to
define a constant value with an associated name.
In Java, you use the final keyword to specify a variable whose value remains
constant.

The value of myHeight is now fixed at 71, and it will remain at 71 even in a
subclass.
The #ifdef is used in C++ programs to implement conditional compilation.

If the #ifdef yields a true result, the code between #ifdef and #endif is included in
the compilation. This type of compilation is often used to enable programs to run on
multiple platforms. Java doesn't have a #ifdef directive because it doesn't need it. Since
Java is platform-independent you don't need to compile separate versions of your program
for different platforms.

Page 66 Go To INDEX
• Flow control extensions
Java's flow-control syntax is very similar to that of C and C++. This means that
programmers familiar with those languages find it easy to start writing programs in Java.
However there are some important areas in which Java's flow-control model extends those
of C and C++.
To write effective Java programs, it is necessary to understand how to use threads
and exceptions. Java's use of threads enables a program to run multiple parts of itself
concurrently. The ability to run threads is extremely useful in practice.
It means, for example, that a program can have a process running in the
background while simultaneously handling user input. A thread is similar to a process but
it does not have the overhead that a process has. A thread is sometimes known as a
lightweight process. C++ does not inherently support multithreading, but you can, for
example, make a UNIX fork system call from a C++ program.
This creates a process that is an exact copy of another process - code and
variables. Java's threads, in contrast, duplicate only the code needed to run in parallel.
This makes threads more efficient than running multiple processes. There are two ways in
which you can make your application run in separate threads. You can extend the class
Thread, which is part of the java.lang package.

You now have a new class - MyFirstThread - that has all of a thread's methods and
properties.
To make MyFirstThread do something useful, you implement the logic of the thread
in its run() method.

A thread's run() method is the equivalent of an application's main() method. You


may want to implement a thread in a class that already exists. In this case the class will
not have been derived from the Thread class. To support threading in such cases Java
provides the Runnable interface. Runnable is a public interface that has only one method.

To use the Runnable interface with an existing class you use the following syntax.

However you still need to use a Thread object, because that is the only class that
can launch a concurrent thread. You first create an instance of the ExistingClassRunnable
class.

Page 67 Go To INDEX
Then you create a new thread, passing it the Runnable object as a parameter.

This can be done in the constructor of ExistingClassRunnable.


Exceptions are a means of handling potentially recoverable runtime errors. Both
Java and C++ have exception-handling mechanisms. In fact, the syntax for exception
handling is similar in both languages. However Java's exception-handling is easier to
implement and more robust than that of C++. In Java, an exception is actually an object.
By treating exceptions as standard objects, Java can handle different types of
errors using a standard interface. Code for handling errors is included in the java.lang
package. This package is automatically imported into all Java programs. Exceptions can
be handled in several different ways in Java.
If an exception is not explicitly handled in the code, it is passed on to the Java
runtime system. The runtime system may be able to deal with the exception without
causing the application or applet to crash. However it is better to write code that can
handle foreseeable exceptions. Java has several different types of exceptions:
Runtime exceptions
Checked exceptions
Custom exceptions
Runtime exceptions occur within the Java runtime system, for example:
Arithmetic exceptions - the classic example here is divide-by-zero
Indexing exceptions - accessing an array element with an incorrect index
These are also known as unchecked exceptions, because the compiler does not
check to see if your program handles them. Checked exceptions are exceptions that you
must explicitly handle in your code. These exceptions are associated with particular
methods. The compiler checks that these exceptions are being handled - if they are not, a
compilation error is flagged.
Java's online documentation describes the exceptions associated with each
package. All exceptions are members of the java.lang.Exception class. You can customize
an existing exception by overriding methods and changing variables. Or you can create
new exceptions by extending the java.lang.Exception class. A simple example of Java's
exception handling can be created by using the keywords try, catch, and finally.
The try keyword indicates that the Java program is going to execute a block of
code that might generate an exception.
The catch statement identifies the exception that has occurred and specifies the
code to execute to handle that exception.
The try statement can be followed by a number of catch statements, each
specifying what action to take for a different exception.
The finally statement is always executed, whether or not an exception was
generated within the try statement.

Page 68 Go To INDEX
The throw keyword generates an exception. It takes as a parameter an object of
the desired exception type. This can be used to generate customized error messages,
while still throwing the error on to the default exception handler.

• C++ Libraries:
C++ is an object-oriented derivative of the C programming language. When C++
was first developed, it included the C standard library for backward-compatibility. In
procedural languages a library is a collection of related functions. It also introduced a new
Stream I/O library. Since it was introduced, C++ has evolved and increased in size. In
particular, its standard library has grown hugely.
The C++ draft standard specification now lists over 800 items such as functions,
types, and structures. These items are grouped in header files, of which there are 32 C++
headers and 18 C headers.
The functionality provided by the large C++ standard library enables programmers
to more easily develop complex applications. Java also has a standard library, composed
of packages, which are collections of classes. In many cases the functionality provided by
Java's standard library matches that of the C++ library.
There are still some areas where support for particular features is stronger in C++.
However Java is a young language and it is certain that these areas will be improved very
soon.
The C++ standard library can be divided into 10 separate sublibraries. Each of
these sublibraries contains both C++ headers and C headers. C++ has a general utilities
sublibrary that contains three C++ headers.
<utility.h> and <functional.h> define many templates for various operations. Java
does not use templates so it does not have an equivalent.
<memory.h> provides templates to support memory management. Java uses a
garbage collector to free up memory, so again it does not need an equivalent to this C++
feature.
In the strings sublibrary C++ has a <string.h> header to help manipulate strings.
The C headers <cstring.h> and <cwchar.h> also contain functions useful for text
manipulation. Java provides similar capabilities in the String and StringBuffer classes. For

Page 69 Go To INDEX
diagnostic purposes C++ programmers use the <stdexcept.h> header file, which declares
the standard exceptions such as length_error and runtime_error.
They can also use the C headers <cerrno.h> and <cassert.h>. Java has many
standard exceptions in each of its packages, which offer similar functionality. The most
important set of Java exception classes is found in the java.lang package. This package is
imported into every Java program by default.
This makes it easier to incorporate robust error-handling into Java programs. C++
has a well-developed sublibrary for handling mathematical operations. The three C++
header files in this sublibrary are <numeric.h>,<complex.h>, and <valarray.h>.
In addition the C header file <cmath.h> defines many standard mathematical
functions. Java's mathematical methods are defined in the Math class, which is part of the
java.lang package.
This class handles most standard mathematical tasks such as exponents,
trigonometric functions, and absolute values. However it does not yet offer some of the
more advanced functionality provided by the C++ classes. For example it does not match
the C++ <complex.h> header, which provides functions for dealing with complex numbers.
C++ has several header files, which help to implement its streams approach to
input/output. These include <iostream.h>, <streambuf.h>, <sstream.h>, <fstream.h>,
<iomanip.h>, and several others. Java uses a similar stream approach to input/output.
Much of its I/O functionality is incorporated in the InputStream and OutputStream
classes of the java.io package. The containers sublibrary contains an important selection
of C++ header files. These headers can be divided into the following three categories:
Sequences - <vector.h>,<stack.h>, <queue.h>,<dequeue.h>, <list.h>
Associative containers -<map.h>, <set.h>
Bitwise operations - <bitset.h>
Containers are objects that contain other objects - they play a vital role in object-
oriented programming. So it's not surprising that Java matches the features offered by the
C++ containers sublibrary very closely.
The relevant classes are part of the java.util package. Sequence-type containers
are provided by Java's Vector and Stack classes. Associative functionality is provided by
the Dictionary and Hashtable classes. And bitwise operations are supported by Java's
BitSet class. C++ has an important sublibrary devoted to algorithms.
It consists of a C++ header <algorithms.h> and the C header <cstdlib.h>. The
algorithms defined by these headers are of many types - sorting, comparing, merging, and
so on. Java's algorithms can be found in its standard library. At present, they don't offer
the functionality provided by the algorithms in the C++ sublibrary.
C++ has a localization sublibrary that consists of a C++ header <locale.h> and a C
header <clocale.h>. These headers define functions that support international formatting
for dates, text, numbers, and monetary units.
Java 1.1 supports different date and time formats based on locale. The java.text
package provides many useful methods and constants for localizing programs. And Java's
use of the Unicode character set provides another important advantage in this area.

Page 70 Go To INDEX
2.4. Javadoc

• The Javadoc utilities and its parameters:


Ideally an application should be thoroughly documented as it is being developed.
Many developers, however, document their code after the application is completed. This
leads to documentation that is sometimes incomplete, or even misleading. Java provides a
tool called javadoc that helps developers to document their code as it is written. Javadoc
is sometimes referred to as the Java API Documentation Generator. The javadoc utility,
which comes with the JDK, creates documentation straight from the source code. It
generates information directly from the class, method, and variable declarations. But it
also includes comments written using the doc comment syntax.
/** This is a javadoc comment */
The javadoc utility produces documentation in the form of HTML files, which can be
viewed by a Web browser. These files are hyperlinked to each other, and also to the Java
API documentation. This type of linked output makes it easier to understand how the code
works. You run javadoc from the command line and pass it the full name of the Java
source file. If you are documenting a class, you must include the ".java" extension.
javadoc classname.java
You can pass multiple class names to javadoc if required.
javadoc classname1.java classname2.java…
You can also use javadoc to document an entire package by passing the package
name as an argument.
javadoc packagename
When javadoc executes it generates a series of HTML files:
classname.html
AllNames.html
Tree.html
Packages.html
Package-packagename.html
Classname stands for the actual name of the class; packagename stands for the
name of the package. The classname.html file contains detailed information on the
relevant class. AllNames.html contains an alphabetical list of the attributes and methods of
the class. The tree.html file shows the class hierarchy as an inheritance tree. The
packages.html file gives a list of all packages in the application. It is usually empty when
you are producing documentation for a class.
The Package-packagename.html file lists all the classes in the relevant package. It
is only produced when you are documenting a package. A number of options are available
for customizing the output of javadoc. The syntax is now displayed.
javadoc [-options] classname.java

Page 71 Go To INDEX
Two of the options limit the number of default files produced. The -notree option
omits the class hierarchy file tree.html. And the -noindex option omits the AllNames.html
index file.
The syntax to direct the output to a destination directory is now displayed.
javadoc –d directory classname.java
You can tell javadoc where to look for the ".java" source files with the -classpath
option. A path containing more than one directory can be specified by using semi-colons.
javadoc –classpath c:\javasrc1;c:\javasrc2
Some of javadoc's options tell it to include certain tagged information that is omitted
by default. The -author option tells javadoc to include any @author tag information. And
the -version option will include the @version tag information. The -verbose option causes
additional information to be printed describing javadoc's progress.

• The doc comment syntax


The javadoc utility automatically documents all class, interface, method, and
variable declarations. However to fully document an application you need to include your
own comments. The javadoc utility lets you include your comments with the doc comment
syntax. The text in a Java doc comment can span several lines.

/** This is a javadoc comment


That spans more than one line */
Java doc comments are only recognized in specific places in the source code. They
can only be placed immediately before the declarations of
Classes
Constructors
Methods
Data member variables
You can use special tags in doc comments to improve the formatting of the output.
These tags are preceded by the "at" sign (@), and consist of the following:
@see
@version
@author
@param
@return
@exception
The @see tag inserts "See Also:" before the succeeding reference.
@see java.lang.Object

Page 72 Go To INDEX
More importantly, it turns the reference into a hyperlink, which can be clicked for
more information.
The @version tag identifies the version number of the class. You may have only
one @version tag within a doc comment.
@version 2.5 06/02/97
The @author tag creates an author entry - you may have multiple @author tags in
a single doc comment.
@author Soledad Mendez
@author Johnny Leary
The @version and @author tags are only used for class and interface
documentation sections.
Three tags are reserved for use with method and constructor documentation. These
are @param, @return, and @exception.
The @param tag has the following syntax:
@param parameterName description
This tag adds a parameter name and description to the "Parameters:" section.
The @return tag adds a description of the return value to the "Returns:" section.
@returns description
The syntax of the @exception tag is displayed here.
@exception fully-qualified-className description
This adds the exception name and description to a section called "Throws:". The
exception name is hyperlinked to its entry in the API documentation. You can also use the
@see tag when documenting methods and constructors.
The @see tag is the only tag that can be included in a comment for a variable. To
enhance the documentation you can embed most standard HTML tags in your doc
comments. For example, you can include hypertext links and graphic images. You should
not use the following HTML tags in a doc comment:
The horizontal rule tag <HR>
Heading tags <H1> through <H6>
This restriction applies because javadoc itself uses these tags in a certain way to
format the output.

• Generating class documentation with Javadoc


To see javadoc in action, let's use it to document a class called Employee.

Page 73 Go To INDEX
This class contains basic employee data, and methods needed to operate on them.
The source file contains several doc comments. The first of these precedes the class
declaration, and briefly describes the Employee class.
The doc comment is defined between /** and */.
The extra asterisks shown are included merely to make the source code look
neater. The doc comment for the class spans several lines. It includes two tags that can
only be included in a class doc comment:
@version
@author
The next doc comment is for the salary variable. Then there is a comment for the
constructor of the Employee class. The doc comment for the salaryIncrease method
contains two tags that only appear in method and constructor comments:
@param, describing the parameter passed to the method
@return, describing the method's return value

Page 74 Go To INDEX
You run javadoc from the command line and pass it the full name of the source file.
C:\javafile\>javadoc employee.java
You must use the .java extension, or javadoc will treat the file as a package. If you
want to document a number of classes simultaneously, you simply pass javadoc all the file
names. Javadoc omits the @version and @author tags by default. If you want to include
this information in the output, you must use the following options:
C:\javafile\>javadoc –version –author employee.java
The javadoc utility now creates an HTML file named after the source file. If you are
documenting several classes simultaneously, javadoc produces one HTML file for each
class, and names them accordingly. In this example, javadoc produces a file called
Employee.html, and three additional files:
Packages.html - this will be empty as no packages were used
AllNames.html - alphabetical index of methods and fields
Tree.html - class hierarchy
Let's look at the Employee.html file in a browser:

Page 75 Go To INDEX
Under the class name you can see a diagram showing where the Employee class
fits in the class hierarchy. Because Employee was created without extending any other
class, it is implicitly descended from java.lang.Object. Then you can see the access
modifier for the class. The next section shows the information included in the doc
comment for the Employee class. You can see that the @version and @author tags neatly
format the output. The variable index section shows a list of the declared variables.

Each entry is hyperlinked to another part of the HTML document that gives more
detail on that variable.

Page 76 Go To INDEX
In this example, only the salary variable has been commented. The constructor
index section provides a link to the constructor's declaration, along with the relevant
comment.

The method index section provides similar links to the class methods' details.

The next section is called fields, and it contains details of the class's variables.

Page 77 Go To INDEX
These variables are color coded as follows:
Instance variables are denoted by a purple ball
Static variables are denoted by a blue ball
There are no static variables in this example. The constructor section gives details
of the constructor of the Employee class.

As this example does not use method overloading, there is only a single entry.
Constructors are denoted by a yellow ball. The final section of the documentation
generated by javadoc gives details of the class methods.

Page 78 Go To INDEX
Instance methods are denoted by a red ball, and static methods are denoted by a
green ball. You can see that the salaryIncrease method includes the doc comment and the
@param and @return tag entries.
The AllNames.html file is an alphabetically ordered index of all the fields and
methods in the class.

You can use the underlined letters to jump to entries beginning with that letter. For
example, clicking on S brings you to the section with the salary variable and the
salaryIncrease method. These entries are, in turn, linked to their declarations in the
Employee.html file.

Page 79 Go To INDEX
At the top of the AllNames.html file there are two hypertext links. All Packages is
linked to the packages.html file, which in this case, is an empty file.
Class Hierarchy is linked to tree.html, which shows that Employee is a subclass of
java.lang.Object.

The Index link at the top of tree.html is linked back to AllNames.html. Employee is
linked to Employee.html, while Object is linked to Java's API documentation.
Employee.java is a simple class that does not generate a lot of documentation.
The real benefits of using javadoc become apparent when you are documenting:
A large class

Page 80 Go To INDEX
A number of classes simultaneously
A package
When you are documenting a large class it will generally have many calls to the
Java API. Javadoc automatically creates links to the existing API documentation. This
makes it easier to read and understand the code. When documenting a number of classes
simultaneously, javadoc creates a class file for each, named after the respective classes.
However it only generates a single AllNames.html file and a single tree.html file, each
containing details for all the classes. So these files will be larger and more informative
than those in the Employee.java example.

• Javadoc in practice
For javadoc files to work correctly, certain conditions have to be met. The Java API
documentation must be present - in HTML format - in the same directory as the javadoc-
generated files. This directory must also contain the images subdirectory, which contains
graphic files that enhance javadoc's output.
There is, however, a problem with having javadoc-generated files in the same
directory as the API documentation files. When javadoc executes, among the files it
creates are an AllNames.html file, a tree.html file, and a packages.html file.
The problem is that the standard API documentation already contains an
AllNames.html file, a tree.html file, and a packages.html file. If you move the javadoc-
generated files into the API documentation directory, you will overwrite the existing files.
One way to overcome this problem is to rename the javadoc-generated files. Suppose you
want to document a Java class called Customer.
First you create a new temporary directory - let's call it javatemp. You then copy the
Java source file Customer.java to this directory. Now run javadoc on the source file with
the following command:
javadoc Customer.java
The javadoc executable file normally resides in the \java\bin directory. Your PATH
variable must point to this directory. After running javadoc you will have four new files in
javatemp:
Customer.html
Allnames.html
Tree.html
Packages.html
Because the Customer class does not use any packages, packages.html does not
contain any information, so you can delete it. You can now rename the AllNames.html and
tree.html files. A good convention to use is to prefix their names with the name of the
relevant class:
AllNames.html becomesCustomerAllNames.html
Tree.html becomesCustomertree.html

Page 81 Go To INDEX
The Class Hierarchy link at the top of the CustomerAllNames.html document still
points to a file called tree.html. Therefore you have to change it to refer to the renamed
file. You open the file with a text editor and change the code to the following:
<A HREF="Customertree.html">
The Index link at the top of the Customertree.html file points to AllNames.html. So
again you must change the code to:
<A HREF="CustomerAllNames.html">

The Index link at the top of the Customertree.html file points to AllNames.html. So,
again you must change the code to:
<A HREF="CustomerAllNames.html">
In this simple example, these are the only changes you have to make to maintain
the integrity of the links. If other files are being used, such as packages.html, then the
corresponding hyperlinks would have to be changed.
Now you can create a directory to hold the javadoc documentation - let's call it
javadocs. You then copy the existing API documentation into this directory. It must also
contain the subdirectory "images", which holds the graphic files. You can now copy the
Customer HTML files into the javadocs directory.
You can create and add as many javadoc files to javadocs as long as you
remember the following:
Use a unique name for each new class
Rename the AllNames.html file, the tree.html file and, if necessary, the
packages.html
File
Change the links to reflect the filenames

Page 82 Go To INDEX
3
Object-Oriented Principles & Java
3.1. Procedural programming Vs OOP:

• Limitations of procedural programming


Traditionally, the standard approach to programming was procedural or functional.
Widely used procedural languages include:
PASCAL
COBOL
Modula-2
FORTRAN
C
The procedural programming approach breaks a problem into a series of small
subroutines or procedures. Procedural languages are also known as function-oriented or
structured languages. Problems with the procedural method have led software developers
to look for a more efficient approach to the development process. Object-oriented methods
are becoming more popular at the expense of the procedural approach. There are several
commercial reasons for the loss of popularity of procedural languages.
First - the cost of software development in a procedural environment is relatively
high. High expectations regarding quality have added to this expense. Increased demand
for products requires greater development resources. Faster development methods are
needed to deal with increased demand for products.
Many of these commercial problems can be addressed by applying the principles of
good programming. There are a number of principles of good programming that are
supported in traditional environments. For instance:
Modularity
Reusability
Extensibility
Other principles include
Ease of maintenance
Preservation of data integrity
Efficient debugging
However, although procedural programming supports these principles, they have
proved to be difficult to attain and maintain efficiently. Procedural programming techniques
are not always successful because they do not enforce the principles of good
programming and make it easy for you to disobey these principles. For instance, a

Page 83 Go To INDEX
difficulty arises from the way that modules interact with each other in a procedural
program.
Another problem is that procedural languages are not as effective at modeling real-
world things as their object-oriented counterparts. Object-oriented programming can
implement such practices with greater ease than traditional languages.
The principles of good programming are generally considered to produce high-
quality, low-cost software in an efficient manner. Of these principles, modularity has had
the most important influence on procedural programming.
Dividing a program into separately named and addressable components called
modules makes a large program structure easier to understand. However, the way in
which procedural programming allows modules to interact with each other gives rise to
problems. Perhaps the most serious difficulty a programmer encounters is the inherent
complexity of modeling a real-world problem.
Traditionally the focus has been heavily oriented toward the procedural side of the
activities being modeled. The problem with a procedural approach is that it does not
always translate well to software that is compact, easy to maintain, and reusable. In order
for modularity to be effective the modules must display "module independence". Module
independence is achieved by developing modules that:
Perform a single task
Do not interact excessively with other modules
Often, software developed using procedural methods does not achieve effective
module independence. A failure to achieve effective module independence means that
modules are more difficult to maintain and test because:
Secondary effects caused by design and code modification are more likely
Errors are spread to other parts of the program
Reusable modules are more difficult to develop and implement
Software complexity can be measured using two criteria - coupling and cohesion.
These criteria present problems for programs developed using the procedural approach to
programming. Coupling refers to the complexity of interfaces between modules. Cohesion
is a measure of the strength of functional relatedness of elements within a module.
Coupling is a measure of the relative interdependence of modules.
In software design, programmers strive for the lowest possible level of coupling.
This is because simple connectivity between modules results in programs that are easier
to understand. Low levels of coupling make programs less prone to errors that occur at
one location and then recur through a program.
The degree of coupling depends on the interface complexity between modules. It
also depends on what data passes across the interface. The highest level of coupling is
known as content coupling.
It occurs when one module makes direct use of data that is within the boundary of
another module.

Page 84 Go To INDEX
In function-oriented systems, a function in one module can access and modify data
structures in another module. The use of pointers, in C for example, increases the
possibilities of this happening inadvertently.
Programmers using procedural languages have been much constrained by having
to write functions so that they do not modify data outside their boundary or scope. If
functions change data outside of their scope, testing becomes very difficult. One of the
most difficult problems with using the procedural approach is to write all functions in such
a way that they do not modify data outside their boundary. It is almost impossible to
completely eliminate coupling.
It is an inherent problem with the procedural approach, and a certain amount of
coupling is inevitable. However, a programmer can achieve low coupling by:
Minimizing the number of interfaces between modules
Minimizing the amount of information that moves across an interface
Cohesion is a measure of the relative functional strength of a function. It is also a
measure of the modular strength of a module. A simple function is one, which performs a
single task and is therefore highly cohesive. Cohesion is a natural extension of a concept
called information hiding. Information hiding allows modules to be designed so that each
module hides from other modules the way that it performs its task.
The advantages of information hiding depend on there being high cohesion
between modules. High cohesion is seen in a module that performs a single distinct
procedural task. In practice, high levels of cohesion are not always easy to achieve under
the procedural paradigm. Let's see how information hiding affects the level of cohesion.
For each task in a program there is a corresponding module or function. Each
function is supposed to perform a task that uses inputs to generate output results. Tasks
are connected by function calls that pass data through a list of attached parameters.
These functions are meant to be like a "black box" in the sense that you should not be
able to see what is going on inside them. To use an existing function from a library a
programmer should only need to know:
What task the function performs
What parameters need to be passed to it to make it perform its task
What values are returned by the function
With some procedural languages this information is stored in a definition module.
All implementation detail - that is, the code that performs the function - is contained in an
implementation module.

Page 85 Go To INDEX
The implementation detail does not need to be visible to the programmer using the
function.
Information hiding ensures effective modularity is achieved. The independent
modules communicate to each other only that information which is necessary for the
modules to perform their function. If you were writing a program and you needed a
function to perform a particular task, you might simply use an existing function written by
another programmer. As more functions are written they can be added to a library of
functions and made available for other programmers to use.
The advantage of information hiding and functional strength is that code is more
reusable. Ideally, a new application should reuse a number of components (routines),
which have already been tested and used in previous applications. So, while the first
software applications may be expensive to develop subsequent ones will gradually
become cheaper. This re-use makes sense. Otherwise it would be like a car manufacturer
having to reinvent the wheel every time a new car was to be built.
A cohesive module should stand-alone and require little interaction with procedures
being performed in other parts of a program. Combining unrelated functions into a single
module increases the likelihood of error propagation. A module, which exhibits high
cohesion is said to be "functionally bound".
In practice such modules are not always easy to develop using procedural
techniques. The problem of low cohesion in the procedural paradigm affects the testing
and maintenance of software. This is because a bug in a program cannot be totally
isolated. It can spread to other parts of a program and "infect" them too. Another idea
behind modularity and information hiding is that extending a module should not cause
other modules that call it to be rewritten.
It should be easy to add to code that is already in use, without extensive rewriting.
The use of preprocessor directives in procedural languages like C causes further
problems. If preprocessor directives are used excessively in a program the code, will not
be easily understood by other programmers. If you misuse preprocessor directives other
programmers will need to understand a large amount of context before they can
understand your code.
This means that each time a programmer writes code he effectively creates his own
language first. A programmer who wants to modify what another programmer has written
is then faced with a more complex task. It is less likely that reliable, efficient programs can
be produced quickly and maintained without great cost.

• Aims of object-oriented programming


The term "Software Crisis" has been coined to describe problems that are faced by
the software industry. For instance, traditional software development has been
characterized by high-cost, low quality, and ever-increasing demand. These problems
have been both caused and exacerbated by increasing software complexity. A new
approach to software development is needed to increase the productivity of the software
industry.
Productivity can be greatly enhanced by reducing software complexity. Object-
oriented programming (OOP) is being heralded as the methodology with which
programmers can reduce complexity and overcome these problems. As the 1980s came

Page 86 Go To INDEX
to a close, OOP began to mature into a practical and powerful approach to software
development. It was originally used in the field of engineering and in academic institutions.
Although it had been around for a period of thirty years it was not until relatively recently
that OOP found its way into the mainstream.
The focus of OOP is not on the procedures of the modeled world, but on the objects
that appear in it. This approach is a radical departure from the procedural model. At first
glance the aims of object-oriented programming (OOP) are like those of procedural
programming. Both methodologies aim to facilitate the production of high-quality, low-cost
software in the most efficient manner possible.
OOP aims to uphold the same principles of good programming as the procedural
approach. However, OOP upholds these principles more easily than procedural
programming. OOP observes the following principles of good programming:
Modularity
Reusability
Extensibility
OOP also observes the following principles of good programming:
Ease of maintenance
Preservation of data integrity
Efficient debugging
The unique methodology of object technology supports these qualities in a way that
produces less complex software.

OOP
Emphasizes "black box" functions
Embraces structured development
Encourages better programming design
Within a procedural environment the combination of software complexity together
with tight quality controls can result in considerable cost. OOP breaks complex tasks into
simple, manageable, independent modules. Simplifying complex problems in this way:
Improves quality
Reduces cost
However, OOP is not merely a new way to organize your source code. You can
achieve results using OOP that would be impossible with procedural techniques. To be
truly "object-oriented", a programming language should support these characteristics:
Inheritance
Data abstraction (encapsulation and data hiding)
Polymorphism and dynamic binding
In theory you can develop object-oriented software using any conventional
language - say C or PASCAL. However, in practice, support for object-oriented

Page 87 Go To INDEX
approaches should be built directly into the programming language that you are using to
implement your design. Java and C++ are examples of languages that have direct support
for object-oriented concepts. Software development using object-oriented principles aims
to:
Support the principles of good programming
Provide software of high-quality
Fulfill user expectations
Make code more portable and more reliable
Reduce development costs
Make code better represent real-world objects
One of the strengths of using OOP is that you can model the real-world better than
you can with other methodologies. The concept of an object allows you to do this. Objects
are a natural thing to model because the world can be viewed as being made up of them.
Cars, dogs, and computers can all be thought of as objects.
When you look around the real-world you can see a set of physical objects, which
can be identified, classified, and defined. Although it is not as obvious, a similar way of
approaching the development of a software solution will make its realization easier.
Software requirements analysis focuses on what function new software is to provide.
During this stage, as well as the design stage, it is useful for you to think in terms of
what objects are involved in the software problem. Under the OOP paradigm, objects are
represented in a system, not just their associated data structures. In object-oriented
programming objects can represent:
Entities
Roles
Data structures
By identifying suitable real-world objects you can create an accurate representation
of your problem domain. You can then map this representation into a solution domain that
is the final program. The object-oriented approach results in a program design that is
unlike that of any other approach. Data and processing operations are interconnected in a
way that modularizes information as well as processing.
It is the fundamental concept of an "object" that facilitates this approach. Let's look
at how the concept of an object fits in to OOP. Each object in the real-world and in the
problem space of new software has a set of attributes that describe it. For example, you
can describe a desk in terms of its weight, color, dimensions, cost, and the material it is
made of.
"Desk" is an object, and these things that describe it are its attributes. Each object
is also a member of a broader group of objects known as a class. A chair is another
object, which you can describe in terms of its weight, color, dimensions, cost, and the
material it is made of. This is because all furniture can be described using these
characteristics. So furniture is a class, which has a set of, generic attributes associated
with every object in the class.

Page 88 Go To INDEX
Each individual object in a class is called an instance of that class. A fundamental
concept of OOP is inheritance. A new class can be defined which inherits all the attributes
that have been defined for an existing class. This new class can change or extend the
functionality of the original class. The object-oriented environment is better able to model
real life than other approaches to programming.
This helps reduce the complexity of your resulting program structure. Objects are
not just composed of data. They also include the methods, which relate and manipulate
the data. A method is an operation that can be used to manipulate an object. For example,
each object of the furniture class can be manipulated in a number of ways. For instance
they could be painted, moved to a different room, or even sold.
In OOP, rather than processing data using a function, you pass a message to an
object telling it what to do. A message will invoke operations or methods, which can
modify the value of attributes associated with the object. An object's attribute values are its
data. Using messages to communicate means that data is not passed around a system
openly. In this way OOP achieves its aim of preserving data integrity. An object
encapsulates both the data and the operations associated with it.
Encapsulation implements information hiding and modularity. In OOP, classes are
independent stand-alone modules. They define both the data and the methods that may
operate on that data. Classes are "decoupled" from each other. In other words interface
complexity between classes is less than that between modules in procedural
programming.
Another fundamental concept of OOP is polymorphism. The word polymorphism is
derived from Greek words meaning "Multiple" and "Shape". Polymorphism enables you to
perform the same operation on different types of classes as long as they share a common
trait. This helps avoid complexity and redundancy in your code.
Another important mechanism closely linked to polymorphism is dynamic binding.
Dynamic binding means that a message can be sent to an object even though its specific
type may not be known until run time. In other words, it adapts to particular circumstances
rather than being predefined and rigid. This provides maximum flexibility when your
program is executing. Polymorphism and dynamic binding are very beneficial to network-
based systems.
Because objects might come from anywhere, possibly across a network, messages
need to be sent to them even if their specific type is unknown. The needs of distributed,
client/server based systems coincide with the encapsulated, message-passing paradigms
of object-based software. Programming systems must adopt object-oriented concepts to
function within increasingly complex, network-based environments.
In particular, object-oriented principles promote the development of code that is
highly portable. OOP aims to reduce code development time. Encapsulation and
inheritance make this possible. The reduction in development time occurs because you
can extend existing classes or derive new ones from existing ones. This saves you from
having to start at the beginning each time you need a new class. Because of the
importance that object-oriented environments attach to code reuse, libraries can be built
which can then be extended to provide new behavior. Library objects can provide
functionality ranging from basic data types through I/O and network interfaces to GUI
toolkits.

Page 89 Go To INDEX
Another important benefit of OOP is the reduction in testing and debugging time.
This occurs because of the inherent localization of bugs. Problems in one part of a
program will not infect other parts, and as a result can be traced more easily.
Object-oriented principles encourage the creation of objects and classes that you
can easily extend and maintain. Both maintenance and extensibility are made easy in
OOP because each object can be dealt with in isolation. As a result there are no
consequential detrimental effects in other parts of your program. You also have more
power to keep interfaces consistent. OOP aims to fulfill user expectations.
Application programs should be written so that they achieve their purposes without
exposing the user to the implementation details of the application. A program designed
using object-oriented programming practices should be easier to use because it models
the real-world.

3.2. Fundamentals of OOP

• Data encapsulation
At their simplest level, programs consist of two things: data and code. In traditional
programming models, data and code are treated as separate entities. Data is allocated in
memory and manipulated by code contained in subroutines or functions. In an object-
oriented environment, data is closely associated with the code that acts on the data. The
code or procedures that act on data are also known as "methods". A method is invoked by
a message requesting that some action be carried out on an object's data.
The combined unit of data and code (or methods) is called an object. And the
process of packaging an object's data together with its code is termed "data
encapsulation". Data encapsulation forms the basis of object-oriented programming. It
enables programmers to more accurately represent real-world objects in a software
environment. Just like objects in the real world, encapsulated objects exhibit two common
characteristics - state and behavior.
The data and methods that make up an object express everything that the object
represents (state) along with everything it can do (behavior).
Let's examine a real-world object, such as a car, to get an idea of how this works. In
programming terms, the state of an object is represented by its data. Like any software
object, a car has data variables that indicate its current state. Data variables describing
the state of a car might include the car's engine type, its current speed, its make, and its
model. A car also has methods operating on its data. For example, one method might
allow it to brake, a second might cause it to accelerate, and another might enable it to
change gears. So the behavior of the car is defined by the methods acting on the car's
data.
Data encapsulation provides two significant benefits for programmers:
The ability to hide data
Increased modularity
First, let's look at the concept of hiding data. Objects are composed of internal
(private) sections and external (public) sections. The private section is typically a
combination of internal data and methods. Any data variable or method in an object may

Page 90 Go To INDEX
be marked private or public. The external section of an object is often referred to as its
"interface". It represents everything that the external users of the object need to know, or
are allowed to know. And it acts as an object's point of communication with other objects.
Within a given object, the object's methods have full access to its data. So pressing the
accelerator of a car (its method) can act on the car's speed (its data). But by default,
object data is invisible, or inaccessible, to other objects. Any interaction between objects
must be handled through their interfaces. This is known as "data hiding". Limiting
communication to an object's external interface protects the internal portion of the object
from unwanted external access.
The second significant feature provided by data encapsulation is modularity.
Encapsulated objects are described as modular because the source code for their internal
sections are maintained separately from their published interface. Modularity enables
programmers to maintain an object independently of other objects. This makes it easier to
distribute objects throughout a system. And modularity enables programmers to make
modifications to an object's internal code without corrupting the communication interface.

• Inheritance
As an object-oriented program grows, the amount of object variables and methods
that must be managed simultaneously becomes complex. One way to simplify the
programming structure is to group similar objects together within a "class". A class is a
template that defines a set of objects. As you know, objects are made up of data and
methods. In a similar way, classes are created by defining all the data and associated
methods for a given set of objects.
You can view classes as a kind of blueprint, or outline, for objects that share a
similar structure or behavior. When we describe cars in terms of software objects, we say
that they have attributes such as engines and transmissions. And we describe them as
having certain behavioral characteristics, like the ability to accelerate and brake. This
description of a car's structure and behavior represents a class definition of cars. As the
number and diversity of objects in a system increases, classes are subdivided to form a
hierarchical structure.
For example, the car class might be logically split into two further classes based on
an engine's power source. Using the principle of "inheritance" this becomes a relatively
simple step. Programmers can create new gas and electric car classes based on the
properties of the existing car class. In effect, they are using an existing class as a template
for the new classes. The class that is "inheriting" properties is referred to as the subclass,
or child. The class providing the inherited information is referred to as the superclass, or
parent.
Since gas and electric cars are simply more precisely specified cars, they inherit
both data and methods from the car superclass. But each new class also has specific
attributes associated with it. For example, the gas car class might specify a fuel tank and
gas cap. And the electric car class's definition might specify a battery and a plug for
recharging. These unique, additional features distinguish subclasses from one another
and from their superclass.
While encapsulation provides the benefits of modularity and data hiding, inheritance
provides the benefit of code reusability. Programmers can create new subclasses that
reuse most of the code in existing superclasses.

Page 91 Go To INDEX
• Polymorphism
In most functional programming languages, programmers need to create two
separate functions with different names to complete the same task on two different
entities. This creates a great deal of code complexity and redundancy. Using
polymorphism, programmers can avoid this problem. Polymorphism lets programmers
define a generic command, which is implemented by a number of related classes. The
methods which implement the command in each class are tailored to suit their specific
requirements. Remember, using the process of inheritance programmers can define a
class structure so that all the objects in the structure have the same fundamental
properties.
For example, all the objects in this animal hierarchy are able to move. But each
animal moves in a different way. For example, the fish swims, the dog runs, and the bird
flies. Regardless of the specific way in which the animal moves, all animals in this
hierarchy will respond to the generic message "move". "Move" is described as a
polymorphic command - it can be understood by different classes of object. But each class
will respond to the same command in a different way.
To understand how the process of polymorphism works, let's look at how software
objects interact with one another. When one object wants another object to do something,
it sends a message to that object. When an object sends a message to another object, it's
requesting that a method carries out some action. In object-oriented programming,
messages and methods are synonymous. But in many cases the receiving object needs
specific information to carry out an action.
For example, if a driver object sends a message telling the car object to accelerate,
the car object needs to know by how much. The extra information included in a message
is known as a "message parameter". In fact, a method can be viewed as a parameterized
message. And objects anywhere in a system can communicate with one another through
these messages. In Java, polymorphic behavior can take two forms:
Method overloading
Method overriding
Method overloading enables programmers to specify different types of information
(parameters) in the message being sent to an object. For example, suppose you send the
message "move" to the bird subclass. If one of the parameters specified in the message is
"cat", then the bird, sensing danger, is likely to fly away. Now suppose you send the same
"move" message - but this time the associated parameter is "food". The bird is likely to hop
towards the food source specified in the message. The same method gives rise to
completely different behaviors, depending on the parameters included in the message. To
overload a method, programmers declare another version with the same name but with
different parameters. When a call to a method is encountered in a program, the compiler
checks the name and the parameters to determine which overloaded method is being
called.
Method overloading is a way for a single class to deal with different parameters and
objects in a uniform way. As the code is being compiled, the compiler determines which
method to call. This is known as static binding.
But since it is often desirable to extend a program after much of the source code is
developed, it can be inflexible. Method overriding provides a more dynamic and flexible

Page 92 Go To INDEX
form of polymorphism. It can do this because it utilizes "dynamic binding". The term
binding describes an association between two things. If binding occurs before run time, as
with method overloading, it's called static binding.
If it occurs during run time, as with method overriding, it's called dynamic binding.
Dynamic binding ensures that a polymorphic message is bound to the method at run time.
So the program uses the actual instance of an object to decide which method to call. If you
define a subclass of bird - for example you could subdivide this class on the basis of
species - you can override the "move" method so that it behaves differently for each
species.
A flightless species of bird will not be able to fly, even if the message includes a cat
parameter. All subclasses have the ability to override inherited methods and substitute
different ones for them. Dynamic run-time polymorphism is one of the most powerful
mechanisms provided by object-oriented design.
It facilitates code reuse and robustness because it enables programs to use the
existing code to call methods on new classes and objects. So the source code doesn't
have to be rewritten or recompiled.

3.3. Classes, methods, and messages:

• Overview of classes:
The most basic unit in a Java program is a class. A class is a template that defines
the properties of a set of objects. As you know, individual objects encapsulate data and a
set of methods that manipulate that data. Each object is derived from a class. So each
class can be viewed as a collection of objects, or more specifically, a collection of data
and methods. Where encapsulated objects provide the benefits of modularity and data
hiding, classes provide the benefit of reusability. Programmers can reuse the code of a
given class many times to create many objects.
Each new object gets its own data but shares a single set of methods with other
objects in its class. Any concept you want to represent in your Java program is
encapsulated in a class. Within a program, classes form a hierarchical structure of
superclasses and subclasses. Every class you declare must be derived from a superclass.
In Java, all classes are derived from a system superclass called Object.
This built-in class is at the root of the Java class hierarchy. Unless you explicitly
specify a different superclass, you automatically inherit from Object. Object is special
because it is the only Java class that does not have a superclass.
And because it is the root class, the methods defined within Object can be used by
all Java objects. Declaring a class in Java is relatively simple. To declare a class, you
need a source file with the class keyword in it. The class keyword is case-sensitive in
Java. The class keyword is followed by a valid identifier, specifying the name of the new
class. The body of the class is delineated with braces. Typically, the classBody is made up
of data variables and methods associated with the class.
The data variables of a class are called instance variables. Let's look at a class
declaration for the class Dog.

Page 93 Go To INDEX
The state of the Dog object is defined by three instance variables, representing the
color, age, and breed of the dog. At the moment the Dog class isn't all that useful. It needs
some methods acting on its data. Methods are declared inside a class definition at the
same level as instance variables. This is the basic format for declaring methods within a
class.

In some cases, methods may return results. The returnValueType lets you declare
the datatype for an object's response to a message. If no return value is required, then the
returnValueType "void" appears at the beginning of the declaration.
The methodName stated is a valid identifier specifying the name of the method.
The parameterList statement specifies the input parameters associated with the method, if
any exist. Parameters in this list are separated by commas. If the method does not receive
any parameters, then an empty set of parentheses follow the method name. The
declarations and statements enclosed within braces form the methodBody. The
methodBody is sometimes referred to as a block. Using this format you can define
methods in new classes.
You can also change the behavior of inherited methods. Here's a method
declaration for the bark method in the Dog class.

The returnValueType "void" indicates that no return value is desired. You can see
that the bark method includes the parameter age, which takes the form of an integer. The
age value is used to determine the amount of barking that the dog does. According to this
declaration, the younger the dog, the more likely it is to bark. If you make the bark method
a member of the Dog class, then the age parameter isn't necessary.

Page 94 Go To INDEX
This is because age is already a data variable of Dog, so all this class's methods
have access to it. With the addition of the bark method, the Dog class declaration looks
like this.

• Messages
Much of the design work in object-oriented programming involves designing
classes. But you don't really benefit from the class structure until you create instances, or
objects, of those classes. For example, once you've defined the class Dog, you need to
create a particular dog to work with. In other words, you need an instance of the class - a
single dog object. An instance is an individual occurrence of a class, with its own set of
data called instance variables. An instance of a class can be referred to as an object.
In fact, the term instance and object are used interchangeably. When you declare a
class, the class declaration states what type of object is being described. But the object
isn't actually created until the "new" operator is used. Here's an example of a new instance
of dog being created and stored in the variable Dog1.

The new operator creates a single instance of a named class and returns a
reference to that object. So Dog1 is a reference to an instance of Dog. The variable is a
reference to the object. It doesn't actually contain it. Instances require some type of
communication mechanism in order to interact. In an object-oriented environment,
software objects interact with each other through messages. Passing messages between
objects is known as "method calling". This is because when an object sends another
object a message, it is actually calling a method of that object.
So a method can be viewed as a message requesting that some action be carried
out on an object's data. If a driver object wants a car object to accelerate, it sends a
message to the car object. This message initiates the car's accelerate method. However,
in order to carry out the request effectively, the car needs information about the degree of
acceleration required. Sometimes the object receiving the message needs extra
information so that it knows exactly what to do.
This extra information is known as a message parameter. Message parameters are
actually method parameters. To effectively define a message for an object, the message
must consist of three components:
The name of the receiving object

Page 95 Go To INDEX
The name of the method to be performed on that object
Any values, or parameters, the method needs to know in order to carry out
the action
Any value returned by the method
The object receiving the message uses this information to invoke the appropriate
methods with the specified values. So in the case of the driver object sending a message
to tell the car to accelerate, the message needs to include the name of the car object, the
accelerate method, and the requested speed. These three parameters provide sufficient
information to fully describe the message for the car object.
Encapsulation facilitates the process of sending messages because it allows you to
send messages to any object without having to know how the object works. Since the
implementation details are hidden within the objects themselves, all you have to know is
what parameters a method will accept. This means you can drive a car effectively without
knowing details about how engines, transmissions, and brakes work internally.
Remember, using the principle of polymorphism, a single message will give rise to
different behaviors depending on the object it's being sent to.
For example, if the same "accelerate" message is sent to a car and a tractor, each
one will carry out the action in a slightly different way. And if the accelerate message
included a speed parameter, then the degree of acceleration would be dependent on this
parameter.

• Interfaces to classes
When creating new classes, programmers sometimes derive the class code from
previously defined superclasses. In this way, the new classes automatically inherit the
data and methods of an existing class. This process is known as inheritance and it
facilitates code reuse. Some programming languages, such as C++, enable you to derive
a single class from multiple superclasses. While this is a powerful feature, it can lead to a
very complex class hierarchy. Java supports single - not multiple - inheritance.
This means that each class in the Java hierarchy - with the exception of the Object
root class - has only one superclass. So any class you create can extend or inherit the
methods of only a single class. If you have programmed in a language that supports
multiple inheritance, single inheritance might seem like a limitation. But in fact it's quite the
opposite. A Java program avoids the difficulties of multiple inheritance. But it still allows a
new class to share the characteristics of multiple existing classes. Java supports the
multiple inheritance of class methods through the use of an "interface". An interface is a
type of abstract class that can be implemented by a number of real classes.
Abstract classes are superclasses that act purely as a template for more usable
subclasses. For example, a car class might be a candidate for an abstract class. You
might never want to create a car object - it is too general - but it serves as a logical
superclass for more specific car classes like electric cars and gas-powered cars.
An abstract superclass contains one or more abstract methods, which are
deliberately left unimplemented. This means they have been declared but have no
methodBody.

Page 96 Go To INDEX
These methods are actually implemented in the subclass, which is derived from the
abstract class. Interfaces allow you to declare abstract methods, which can be
implemented by unrelated members of a class hierarchy.
An instance of any class in the hierarchy can use these interfaces through the
process of polymorphism. Remember, polymorphism allows a class to implement methods
specific to it. This means that new classes are not restricted to inheriting methods from
only their superclass. No objects can be created from an abstract class. This means that if
you define an abstract class, you cannot instantiate it directly. Instead you create a class
that implements the interface. When a class implements multiple interfaces it must provide
all of the functionality for the methods defined in the interfaces. The major difference
between an interface and a typical class is that an interface cannot store data.
In addition, an interface does not provide an implementation for the methods in its
class. But it does provide a method declaration.

Interface declarations follow this general format.

The interfaceBody refers to the abstract methods and variables that make up the
interface. To implement an interface, you use the "implements" keyword.

Class declarations that use interfaces usually follow this format. Using interfaces,
Java programs can offer many of the advantages of multiple inheritance without the
associated problems. While the use of interfaces is not as powerful as multiple
inheritance, they do allow multiple classes to inherit the same method interfaces, even
when they're not related in the class hierarchy. And once an interface is supported by an
application, programmers don't have to write new application code to take advantage of
new classes, which implement the interface. So the use of interfaces facilitates rapid code
development. In addition, because a single class can implement more than one interface,
it is possible to share the same interface across several classes.

Page 97 Go To INDEX
4
Introduction to the Java Language
4.1. Java Syntax

• Identifiers and keywords


Java shares a common look and feel with the C language. If you have programmed
in C or C++ before, then Java syntax will appear familiar. But even if you have never
programmed in C before, Java's syntax is simple to learn. Java programs are free-format.
The compiler does not consider comments and white space to be meaningful. It strips the
source code of these elements before parsing it. You are allowed to indent your code in
whatever way you like. And you can put as many spaces or lines between statements as
you think appropriate. You can use three types of comment in Java.

The first begins with a /* and continues until the first */ sequence is found. You are
not allowed to nest /* */ comments.
You can insert a comment on a line starting with two slashes // and continuing until
the end of the line is reached. A good tip is to use // comments within your code blocks, so
that if you want to comment out a section of code later, you don't have to worry about
inadvertently nesting /* ... */ type comments.
There is a special "doc" comment beginning with /** and continuing till a */ is
reached. Doc comments are usually placed before declarations. This type of comment is
used in conjunction with the javadoc tool to produce online documentation. The source
code is parsed by the compiler into tokens. Tokens are the smallest meaningful elements
of code that the compiler recognizes. User-defined names, known as identifiers, are an
important category of token. Identifiers uniquely name all your classes, methods, or
variables.
It is considered good programming practice to choose identifiers that help describe
what they stand for. In other words, your identifiers should help someone reading your
code to better understand it. Java identifiers are composed of letters and, optionally, digits.
But they must begin with a letter.

Page 98 Go To INDEX
White spaces cannot be used to separate words in your identifiers. So these are
not valid Java identifiers.

Java would, in fact, treat each space-separated word as an identifier itself.


Underscores "_", and dollar signs, "$", count as letters too. So these two identifiers are
valid.

Identifiers are case sensitive. "theLargestInteger" is not equivalent to


"thelargestinteger". Identifiers can be of unlimited length in Java.
This allows you great flexibility in choosing meaningful names for your classes,
variables, and methods. You cannot use identifiers that correspond to a reserved keyword
in Java. For example, you cannot use 'while' as an identifier, since 'while' is a reserved
Java keyword. You should try to follow Java conventions for defining identifiers. By
following these conventions you make it easier for someone else to read your code. These
conventions are not part of the language, but through practical experience have come to
be considered an unofficial naming standard. The first convention is that identifiers should
all be in lowercase, except for the first character of embedded words. Here are some
examples.

Note how the first letter is in lowercase. Since you may not use spaces within
identifiers, another convention used is to separate words within identifiers by using the "_",
or underscore character, instead of a space. Here are some examples.

Java reserves a list of identifiers, called keywords, for itself. Here is a full list of the
Java keywords, in alphabetical order.

Page 99 Go To INDEX
You may not use any of these reserved keywords as an identifier. The compiler will
return an error if you attempt to use a keyword in an inappropriate manner. The keywords
are used:
To declare primitive types
To declare classes, variables, and methods
As flow control statements
To define visibility levels for class methods or variables
The other reserved words include those for:
Exception handling
Class definitions
Miscellaneous
Unused reserved words
If you use a development tool, then it will help you to read your Java code by
highlighting reserved keywords in a different color.

• Types and literals


Java emphasizes simplicity, platform-independence, stability, and ease of use.
These characteristics are especially apparent in the primitive data types. The full list of
primitive types in Java is:
Boolean
Char
Byte
Short
The list of primitive types also includes:
Int
Long
Float
Double
The boolean type has only two possible values - true or false. Booleans are not
integers, and true and false should not be confused with the numerals 1 or 0. Booleans
replace the conditional expressions of C/C++, where 1 or 0 is returned. In fact, booleans

Page 100 Go To INDEX


cannot even be cast to or from any other primitive type, including integers. Here are two
valid Boolean conditionals:

The first condition returns true, since it is greater than Zero. The second condition
returns false, since j and k added together do not exceed 99.
A byte is an integer of 8 bits long. It is a useful primitive type when dealing with I/O
and lower-level data manipulation. Java's implementation rules for primitive types are quite
strict. Strict size rules for primitive types help to enforce platform-independence. All
primitives occupy a strictly defined number of bits.
You can be certain that when you use, for example, a short integer, it will be
implemented in 16 bits. There are also standard default values for each type. If you do not
explicitly initialize variables, they will be set to this default value by the interpreter. All
integers (byte, short, long, and int) are signed.
Bytes, for example, range from -128 to 127, and short integers from -32768 to
32767. This means that you cannot use the C/C++ keyword "unsigned". The three types of
integer literal in Java are:
Decimal (base 10)
Hexadecimal (base 16)
Octal (base 8)
Integer literals in Java are equivalent to those in C and C++. Decimal literals appear
as normal whole numbers, unseparated by commas, with an optional minus sign, "-",
denoting negative integers. Here are some valid integer literals as they could be used in
initializing three int types.

Hexadecimals are defined by preceding the literals with "0x" (zero x).

Octals are defined with a leading zero, "0".


You place the letter "L", in upper or lower case, after an integer literal to specify that
it is a long integer, of 64 bits. Floating-point literals can have an "F", or "f", appended to
indicate that they are of type float.

Page 101 Go To INDEX


"D", or "d", indicates that they are of type double. These are examples of valid float
and double literals.

The letter "e", or "E", denotes an exponential value. For example, 7e3 evaluates to
a float value of 7000.00.
Char types are 2-byte, 16 bit Unicode characters. In most cases this makes no
difference to the way you use characters or strings. The first 128 Unicode characters are
identical to the ASCII set used in C. Using Unicode makes internationalization easier.
Some Unicode character literals may not be displayable on certain platforms, so Java
offers a way to refer to them using the "\u" escape sequence. These are valid Unicode
characters.

These are two of the standard escape sequences in Java.


Escape sequences represent special character values that cannot be displayed.
Java's escape sequences are the same as those in C and C++. This is a complete list of
the Java escape sequences.

These sequences can be used in both character and string literals. This string literal
has a newline escape sequence at the end.

This string literal has embedded tabs. String literals are defined between double
quotes, as in C.

Page 102 Go To INDEX


You are also able to use the "+" string concatenation operator when defining
literals.

• Arrays and strings


Arrays are non-primitive types, and share many features of the Java Object class.
Arrays in Java closely resemble arrays in C and C++. Both objects and arrays are passed
by reference, whereas primitive types are passed by value. Arrays that are no longer
referred to are garbage collected, just like objects. For these reasons, objects and arrays
are called the reference data types. Arrays, as such, are merely references to the data
elements they contain. There are two steps to using arrays:
Declaration
Allocation
Arrays are first declared to be of a particular type. Then space for their elements is
allocated. These two steps can be achieved using a single line of Java code. You can
declare arrays dynamically using the new keyword.

Square brackets in declarations, either after the type or object identifier, or after the
array identifier, indicate that an array is being defined. Arrays can also be declared
statically.

Any valid expression for the array type can appear as an element in the list. The
compiler automatically calculates the array size. The first element is indexed as element
"0", or zero. An array with 10 elements, therefore, is indexed from 0 to 9. In this example,
"Tony" is accessed with peopleNames[0], and the fifth element,"Vonzell", with
peopleNames[4]. Multidimensional arrays are defined as arrays of arrays. They are
declared using multiple square brackets after the array type or array name.

These examples show two-dimensional arrays, but you can also declare arrays of
three or more dimensions.

Page 103 Go To INDEX


Multi-dimensional arrays can be non-rectangular, or "triangular". Triangular arrays
have to be allocated dynamically in C, while they may be allocated statically in Java. This
example shows how a two-dimensional array of arrays of varying sizes is allocated
statically in Java.

You access array elements by putting a valid integer expression, or integer literal,
between square brackets after the array name.

The Java interpreter checks array bounds, and if they are too low or too high it
throws an ArrayOutOfBoundsException exception. You can find out the length of an array
by using the "length" field. So if you had an array called littleArray, you access its length by
the expression littleArray.length. The length field is read-only.
Strings are implemented as instances of a class called String, in the java.lang
package. In Java, strings are not null-terminated arrays of characters, as they are in
C/C++. Having a class for strings means that you can use a full range of methods to
manipulate them. You can convert booleans, characters, integers, and floating-point
numbers to strings using the valueOf method. For example, this code initializes two String
types to represent an integer and a double respectively.

Strings (i.e. String objects), once initialized, are immutable - there is no way for you
to change their contents. You must use the StringBuffer class instead.
Bounds checking takes place at run time, as with arrays, and exceptions are thrown
if invalid accesses are attempted. Strings can be initialized with the double quotes ("") and,
optionally, the "+" concatenation operator. The "+" operator concatenates two strings.

Page 104 Go To INDEX


• Casting, blocks, and scope
Casting is the conversion of values of one type to another, compatible, type. You
will cover only the issue of casting between primitive types here. You can also cast
between classes in limited ways. You may need to cast values returned from methods into
another type for further processing. You may also want to cast a variable of one numeric
type to another, in an expression that returns that other type. You cast from a source type
to a destination type. You place the destination type reserved word between parentheses
before the source expression.

In this example, we have to cast from an integer "hoursWorked" to a float before the
expression can be evaluated.
// where “salary” is of type float…
public float get WeeklyWageBill ( int hoursWorked ) {
if ( hoursWorked == 0)
return salary * (float) this.hoursWorked;
else
return salary * (float) hoursWorked;
}
So we place the destination type reserved word, "float", between parentheses
before the integer variable in the expression. When casting numeric values, sign is
retained. But when casting from a floating point value to an integer type, you will lose the
fractional part. There are some restrictions on casting between types. First, casting may
result in loss of information. Casting "down" to a smaller type results in the left-most bits
being eliminated. If you were, for example, casting from a long to an int, then the 32 left-
most bits are eliminated. Here is the list of casting operations, which result in no loss of
information.
From Type To Type
byte short, char, int, long, float, double
short int, long, float, double
char int, long, float, double
int long, float, double
long float, double
float double
In general, no information is lost when casting from an integer type implemented
with fewer bits to one implemented with more bits, or from float to double.

Page 105 Go To INDEX


Some casting operations are illegal. You are not allowed to cast to or from a
boolean type. So, boolean false will not translate to integer value 0, or vice versa. Here is
a useful way to translate from integers to booleans:
// 0 false, non-0 true b_var = (i_var != 0) ;
// false --> 0, true --> 1 i_var = (b_var)?1:0 ;
The conditional operator, "?:", will be explained in the unit Operators and flow
control. All statements in Java belong to blocks. Blocks group together sets of related
statements. Blocks can be nested to produce a hierarchy of blocks. Blocks appear
between braces, "{}". You will notice that most Java constructs, like classes, methods, and
flow control statements, use braces to group related statements together. This example
shows three nested blocks of a class, a main method, and an if/else flow control
statement.

Classes, methods, and flow control statements will be discussed in detail at a later
stage of this course. One standard convention is to indent nested blocks by two spaces.
This allows for easier visual identification of nested blocks, but has no effect on the
compilation of code. You are advised to be consistent in your indenting throughout your
code. Scope is the term used to define where a variable is visible, and its lifetime. Its
visibility determines what code can access or use it.
Once a variable's lifetime is ended it is destroyed and its value(s) lost. If you define
a variable within a block, it is only visible within that block, or to subnested blocks. It is not
visible to or accessible from its outer blocks. We say that the variable is local to that block.
The integer ifInt is created upon entry into the if block and destroyed upon exit from that
block. Similarly, the mainInt integer's lifetime covers the start to the end of the main block
only. Scoping ensures that local variables are hidden from outer blocks. This is a good
example of the concept of data hiding, which is encouraged by the Java language.

Page 106 Go To INDEX


4.2. Operators and flow control

• Unary and binary arithmetic operators


Unary operators work on a single numeric variable and return a single numeric
value. They are said to take a single operand. You can increment numerics by 1 using the
"++" operator, and decrement numerics by 1 using the "--" operator. The assignment
operator is "=". It assigns the right hand expression to the left hand variable. It follows the
general form:
variable = expression;
In these examples, the assignment is implicit.

We could have replaced them with these longer, but equivalent, expressions using
explicit assignment. You can also use an assignment with an operator, which you express
by combining the symbol for the operator with the equals sign. These two examples are
equivalent to incrementing and decrementing j and k respectively.
J + = 1;
K - = 1;
This example shows how to multiply j by 3.
J * = 3; // equivalent to J = J * 3
There are two forms of the increment and decrement operators:
Prefix -- K; //decrement K, prefix
Postfix J ++; //increment J, postfix
The prefix version modifies the variable before the rest of the expression it appears
in is evaluated. You place the operator before the variable in question, as in these
examples. The postfix version modifies the variable only after the expression it appears in
is evaluated. You place the operator after the variable. The difference can be made
obvious with this example.

Page 107 Go To INDEX


While j becomes 5 in both these examples, i will become either 4 or 5 depending on
whether the postfix or prefix form of increment is used.
The "-", or negation operator, negates a numeric expression. So j = -i; just negates
the value of i and assigns it to j. The value of i is not modified by the operation. The bitwise
negation operator, "~", toggles all the bits of an integer. All binary ones become binary
zeros, while all binary zeros become binary ones.

Java's integers are stored in two's complement form, where the leftmost bit
indicates sign.

A value of 1 in the leftmost bit denotes negative numbers, while a 0 denotes


positive numbers. A bitwise negation operation always changes the sign of an integer
value because the leftmost bit will change from 1 to 0, or from 0 to 1. Here are some
examples and the resultant values.

Page 108 Go To INDEX


In binary, you change a two's complement number's sign by toggling all the bits and
then subtract 1. So 0000 0011 (decimal value 3) becomes 1111 1101 (decimal value -3).

The complement, or bitwise negation, of 3 is -4, since 1 is not added after the bits
are inverted. And the bitwise negation of -3 is 2 for the same reason.

Page 109 Go To INDEX


Binary operators take two operands. Addition, subtraction, division and modulus all
work in the standard ways on integers and floating-point numbers.

The modulus operator applied to integers returns the remainder of a division


operation. The modulus operator applied to two floating-point numbers returns the
remainder, as a floating point number, after a division operation.

Bitwise operators work at the binary level of integers. Bitwise operations involve the
systematic comparison of the corresponding bits of two integers, one by one. They are
useful operators to have when integers are being used as bit fields, or groups of binary
flags.
In bitwise AND, "&", the result returned is 1 if and only if both bits are 1.

Page 110 Go To INDEX


In bitwise OR, "|", the result returned is 1 when either bit is 1.

In bitwise XOR, "^", 1 is returned only when the bits are different from each other.

The shift operators also work at the binary level.

The three shift operators shift the bits of an integer by a specified number of bits.
Because integers in Java are signed, the standard right-shift operation, ">>", preserves
sign. The alternative ">>>" operator shifts an integer and fills in the leftmost bits with

Page 111 Go To INDEX


zeros. This makes an important difference for negative integers, since they become
positive after a ">>>" operation.

• Relational and boolean operators


In Java, there are six relational operators:
Equal to "=="
Not equal to "!="
Greater than ">"
Less than "<"
Greater than or equal to ">="
Less than or equal to "<="

The relational operators compare arithmetic operands only, except for "==" and
"!=", which can also compare other primitive types. They all return boolean true or boolean
false.
Boolean types require their own set of operations.

These operators take one or two boolean expressions and return either boolean
true or boolean false. Logical AND, "&", returns true if both operands are true, false
otherwise.

Page 112 Go To INDEX


true & true = true
true & false = false
Logical OR, "|", returns true only if either operand is true, false only if both are false.
true | true = true
true | false = true
Logical XOR, "^", returns true only if the operands are different from each other.
true ^ true = false
true ^ false = true
Another way to state this is that logical XOR returns true if, and only if, exactly one
operand is true.
For logical AND, "&", the result is assured false when the first operand evaluates to
false.
For logical OR, "|", the result is assured true when the first operand evaluates to
true.
For logical XOR, "^", both operands must always be evaluated. This is often a more
efficient way to evaluate compound conditionals, as well as avoiding unwanted side-
effects.
Here, you can clearly see that (i++>1000) evaluates to false, and that the whole
expression then evaluates to false.

But using the & operator, the int j is incremented - a side-effect of evaluating the
second operand. The && operator would not increment j, since it would cease evaluating
the boolean expression after finding the first operand false. There is no need for a short-
circuit logical XOR operation, since both operands must be evaluated in any case, before
a boolean result can be returned.
The boolean negation operator, "!", toggles the boolean value.
!true = false
true = !false
It returns true for a false operand, and false for a true operand.

Page 113 Go To INDEX


The ternary if-then-else, or conditional operator, "?:", takes a boolean expression
and two other expressions.

If the boolean expression evaluates to true, then expression1 is evaluated and its
value returned. If the boolean expression evaluates to false, then expression2 is evaluated
and its value returned.

• Expression construction
You can use multiple operators in a single expression.
10 * 5 + ( 4 / 2 )
These operations are performed in a particular order that is strictly pre-determined
by the Java language. The first rule used to determine the order that operations are
performed in is operator associativity. When you use two or more of the same operators in
an expression, then the associativity rule states that they are evaluated in left to right
order. Here are three examples of multiple operators in a single expression.
i = j + k + l + m + n;
i = j * k * 1;
i = j / k / m;
In each case, the leftmost operation is performed before the others. In the third line,
j is divided by k and then the result is divided by m. Note that this is distinctly different to k
being divided by m first, and then j being divided by that result. When different operators
are used in a single expression, then the order of evaluation depends on the precedence
of the different operators.
All the operators have a strictly predetermined level of precedence, from highest to
lowest. For example, multiplication and division are higher precedence operations than
addition and subtraction. In this example, the multiplication of 8 by 99 precedes the
addition of j to 8.

Page 114 Go To INDEX


You use parentheses around a sub-expression to explicitly set it to the highest
precedence. This line shows how 8 is added to j first, then the result is multiplied by 99 - a
completely different result. This table sets out, from highest to lowest, the precedence of
Java operators.

Those appearing at the top are said to have higher precedence, and are evaluated
first in expressions. The highest precedence operators are "()", "[]", and ".". Parentheses,
as we have seen, explicitly promote the precedence of the expression they surround.
Array access expressions are evaluated first, before the element returned can be used in
another operation. The dot operator, ".", is used for de-referencing class members. At the
next level are the unary operators:
Increment, "++"

Page 115 Go To INDEX


Decrement, "--"
Bitwise negation, "~"
Boolean negation (NOT), "!"
Then comes multiplication, division, and the modulus operator. The lowest level of
precedence is reserved for assignment, "=", and assignment with operator, "op=".
Associativity and precedence determine the order that operators are evaluated. But
another issue still requires deciding - the order in which operands are evaluated. In binary
operations, the left hand operand is always evaluated before the right hand operand.

• Flow control statements


Flow control statements dictate the basic structure of your Java code. The two
categories of flow control statement are:
Branches
Loops
Branch statements execute blocks of code or do not execute them depending on
the result of evaluating some test condition. Loops constantly repeat a block of code until
some condition is met. You are forced to use proper boolean expressions that evaluate to
either true or false, in test conditions in flow control statements. Testing for an integer to
decrement to zero, using for example if (i--), is invalid in Java. The two basic branch
statements are:
if/else
switch/case
The if/else branch statement tests a condition that evaluates either as boolean true
or boolean false.

Page 116 Go To INDEX


It executes the "if" block when the condition is true. The optional "else" block is
executed when the condition is false. It you omit an "else" and the condition returns false,
then nothing is executed and control passes to the next statement after the if. If/else
statements can be nested.

This syntax illustrates three nested if/else statements. You may find nested if/else
statements quite confusing at first.
The rule of thumb is that an "else" belongs to the nearest prior "if" statement without
an "else" already. You are advised to use braces in your code, even with single
statements, to make the matching of nested if/else statements more explicit.
The other branch statement is the switch statement.

Page 117 Go To INDEX


It can be used to replace complicated, nested if/else statements. The switch
statement is the same in Java as in C/C++. An integer or character expression is
evaluated. The short, int, byte, and char types can be used as values for the case labels.
You may not use long integer types as values for case labels. The statement-list of the
case clause whose label equals the result is executed. A statement list is any series of
valid Java statements separated by semicolons. Unlike statement blocks, statement lists
do not require enclosing braces. If no case constant matches the expression, then the
default clause is executed. Once a statement list executes, then all subsequent statement
lists are also executed, regardless of the case clause constants. Control is said to "fall-
through" the rest of the switch statement. To prevent this, it is common practice to use
break statements after each statement list.

A break forces the interpreter to jump to the first statement after the closing brace
of the switch statement. Here you see a simple switch statement.

Page 118 Go To INDEX


The loop expressions are:
for
while
do/while
The for loop executes a block of statements, or a single statement, a given number
of times. There are three sections in the "for" clause:
Initialization
A test condition for terminating the loop
A step expression
A for loop generally has one or more loop variables.

Page 119 Go To INDEX


Loop variables are initialized in the initialization section, tested in the test condition
section, and altered in the step expression. Let's look at a simple example.
for ( int I = 0 ; I < 100 ; I++)
This for loop features a loop variable of i, initialized to 0 in the initialization section.
The for loop terminates when i reaches 100. And at the end of each step i is incremented
by 1. Variables can be declared in the initialization section. Their scope covers just the for
statement block alone. Variables with the same name outside of the block are not modified
in any way.
The initialization section has the facility to have multiple initializations or
declarations separated by commas. The step section also has the facility to have multiple
statements separated by commas. Here are some more examples.

The second example illustrates how to initialize two separate int loop variables. The
third illustrates a slightly different example using a String variable.
The while and do/while loops are very simple.

The statement body in a "while" loop executes until the test condition becomes
false. The do/while statement body is guaranteed to execute at least once. The while and
do/while loops are exactly the same as they are in C and C++. The goto statement is
banned in Java, and is replaced by a combination of the break and continue statements,
and labeled loops.

Page 120 Go To INDEX


You may notice that goto is a reserved keyword in Java, but is not implemented. A
compiler error will result if you try to use goto as an identifier in your code. A break
statement inside a while, do, or for loop stops the execution of that loop, as in C/C++. This
code, for example, shows two break statements - one inside a for loop and another inside
a while loop.
The key difference in Java is that you can label loops with identifiers, followed by a
colon, as in this example.

Notice the "top_loop" label before the while keyword. An optional label can follow
the break keyword. If there is a label following the break, then control transfers out of the
enclosing statement that the label refers to. You use "continue" in much the same way. It
stops the execution of the current loop cycle, but restarts at the beginning of the loop
again.

4.3. Java object orientation

• Building a simple class


Classes are the fundamental building blocks of Java programs. A class is a
collection of data and related methods that operate on that data. All data and functionality

Page 121 Go To INDEX


in a Java program is organized into classes. And the object-oriented principles of
encapsulation, inheritance, and polymorphism are implemented using classes. Classes
are the mechanism used to define objects in Java. Objects are instances of classes.
Classes define a "template" for objects, while objects are dynamically created to represent
instances of those classes. So a running Java program consists of interacting objects,
which are all instances of classes. Many instances of a single class can exist side-by-side
in a Java program. Methods operate on the data in the class. Data may include primitive
types or other classes. Classes are split into three basic components:
A class declaration
Data
Methods
Let's have a look at a simple class, called Employee. This will illustrate the main
syntax used to define classes in Java. Here, the class name is "Employee".

The convention is to use an uppercase letter to begin a class name. The class
access modifier used in this example is "public". This means that the class is accessible,
or visible, to all other classes. If a class is public, then the class name must correspond to
the source file name, and there can only be one public class per source file. Java
filenames and class identifiers are case-sensitive, so they must also correspond in case.
There are other access modifiers too, which restrict in various ways the visibility of
class members to other classes:
The default access
Private
Protected
Then the data for the class is defined. Here you can see four data variables
defined. There are three main parts to any data declaration. First we specify the data

Page 122 Go To INDEX


access modifier. In this case we specify public data access. Then we declare the
variable's type, String, a class itself. Data in classes can include primitive types or other
classes.
Lastly, we have the variable's name, "firstName". Convention specifies that the
variable's identifier begins in lowercase, with subsequent words within the identifier
beginning in uppercase. The Employee class has two Strings for names, an employee
number, and a salary amount. Notice the "protected" access modifier for the "salary"
variable. Next, the methods that operate on the data in the class are defined. The
Employee class has three methods:
Employee
salaryIncrease
getSalary
Like classes and data, methods have access modifiers. All three of these methods
have public access specified. You should notice that this method has the same name as
the class itself. Methods with the same name as their classes are called constructors.
Constructors are executed when new instances of the class are being made. Methods
must declare a return value. The salaryIncrease method returns a floating-point value. And
it receives an integer argument called "percentageIncrease". All classes have this general
form. Objects need to be declared to be of a particular class. Then they are actually
allocated space, or "instantiated".
Let's define a new Employee object and call that Employee "johnny". Precede the
object identifier, "johnny", with the class name, "Employee". We have only declared that
johnny is an Employee, and have not instantiated it yet. Objects are instantiated using the
new operator. Notice how we initialized johnny's first name, last name, employee number,
and salary.

We are using a special method defined for this purpose in the class - a constructor
method. Constructors are methods, which have the same identifier as the class name and
are used to initialize new objects.
Java allows us to declare and allocate objects in a single statement. You just
combine the declaration and instantiation into a single line, as you see here.

Object data is accessed using the dot operator, ".". So, to access the social security
number of an Employee in our example, we would use this syntax.

Page 123 Go To INDEX


currentEmployee is an int (an integer type) variable that takes on the value of
johnny's employeeNumber. To invoke a method in the Employee class is also quite
simple. Just use the object name, a dot, and the method name with any relevant
arguments. This line increases johnny's salary by 7%, for example.

Or we can access his salary by calling the access method getSalary.

• Packages and the import statement


Java classes are organized into packages. Packages usually contain groups of
related classes. Every class is a member of a package. The package statement appears
as the first statement in a Java file. The package's fully qualified name follows the package
keyword. In this case, the package is called company.people.
package company.people;
Package names mirror the directory structure of the class files. Thus, all classes in
the company.people package must appear in the path company\people (or
company/people).
Access to classes from within a package is different than access from external
packages. For example, a protected variable is accessible to another class within a
package, but inaccessible to packages from outside. Protected variables can be inherited
by subclasses in other packages, but cannot be accessed by them.
In other words, how you structure your packages can determine class, variable, and
method access. If you do not specify a package name in your files, then your classes
become part of an unnamed default package. The import statement is not to be confused
with the C language directive, #include. It does not read in, or load, the referred-to
packages or classes.
It simply allows the programmer to refer to classes directly, without having to
precede them with the package name. The java.lang package is imported by default into
every Java program. So when you refer to Object, which is in the Java.lang package, you
can refer to it as Object instead of as java.lang.Object.
The import statements appear after the package statement and before anything
else. There can be an unlimited number of them. There are only two forms of the import
statement. The first form is:
import package_name.class_name;
Here we can directly refer to the class name in the import statement, without
preceding it with any package name. So:
import java.awt.peer.ContainerPeer;
Means we can refer to ContainerPeer throughout our code.
The second form is:
import package_name*;
It allows us to directly refer to all classes in the relevant package. Thus:

Page 124 Go To INDEX


import java.awt.peer.*;
Allows us to access such classes as ContainerPeer and ListPeer without preceding
them with the package name. Regardless of the package that a class belongs to, it is
stored in a separate file. The name of the file is the class name, followed by a .class
extension.
A single source file can have multiple class definitions but only one public class.
The source file has to have a .java extension corresponding to its only public class. We
could, for example, store all the Employee-related classes in a common file, called
Employee.java.

• Deriving classes using inheritance


You can create a class in Java that inherits the data and methods of another class.
In this example, we have declared a new class called PartTimeEmployee, which inherits
from Employee. The class you extend is called the superclass of the subclass. In this
case, the superclass is Employee and the subclass is PartTimeEmployee. You may, in
turn, extend subclasses indefinitely.
For example, we can extend PartTimeEmployee to create a new class
StudentEmployee.

This means that one subclass may be the superclass of another class. As you can
see, the terms subclass and superclass are relative. There are two optional clauses in the
class declaration:
Extends [extends superclass]
Implements [implements interface]
The extends keyword, followed by an identifier, indicates the superclass. You
cannot extend a final class - a class deliberately defined to be unextendable. A class
inherits the data and functionality of its superclass, and the superclasses of its superclass.
If you do not explicitly specify a superclass, as in this example, then the default superclass
is Object.
public class Employee { … }
Even if you extend from a class other than Object, that class or one of its ancestors
will be a direct extension of the Object class. So, all classes have Object as an ancestor.
Java has no multiple inheritance but simulates it instead with the concept of interfaces.

A class declares that it is implementing an interface with the "implements" keyword


followed by the interface name. Object is the only Java class that does not have a
superclass.

Page 125 Go To INDEX


All Java classes belong to a single class hierarchy beginning at Object - the root
class - and continuing to the lowest-level classes.
That's why all classes inherit the methods of the Object class. The diagram
illustrates a sample class hierarchy for the Employee class and its subclasses. There are
three subclasses of Employee - PartTimeEmployee, ContractEmployee, and
FullTimeEmployee. And there is a single subclass of PartTimeEmployee -
StudentEmployee. Let's imagine a simple scenario. PartTimeEmployees do not work a full
week, so their salary will be specified as an hourly rate. And their weekly salary will be the
rate multiplied by a new variable - called hoursWorked. Here you have defined a class,
called PartTimeEmployee, and added an extra variable - hoursWorked.

This is the body of the PartTimeEmployee constructor method. Although a subclass


inherits all the data and methods of its superclass it can still override the methods of its
superclass. This is the salaryIncrease method, as defined in the Employee class.

Page 126 Go To INDEX


Let's see how you can override this class in the ContractEmployee class.
Imagine a situation where it was a company policy not to give contract workers
salary increases of more than 5%. You must change the salaryIncrease method to reflect
this fact. This method overrides the Employee salaryIncrease method.

Notice that their names are identical. And the types and number of their parameters
must be identical too, although the parameter names can be different.
And notice how you can still call an overridden method, using the super keyword.
There are two special modifiers used when declaring classes that change inheritance in
Java:
Final public final Employee { … }
Abstract public abstract Employee { … }
The final modifier means that the class cannot be subclassed. In turn, all methods
of a final class are final too. Clearly, final methods cannot be overridden, since the class
cannot be subclassed. Final classes and methods allow the compiler to perform certain
optimizations to the code. And the interpreter does not need to dynamically look up the
class and its methods. The keyword abstract indicates classes that are not fully
implemented, or which contain methods that are not fully implemented. The
implementation must be provided by a subclass. They must be subclassed, and their
abstract methods implemented, before they can be used.
Abstract classes cannot be instantiated, since they are missing vital implementation
details. And they cannot be declared final since they must be subclassed to be used.

Page 127 Go To INDEX


5
Anatomy of Java Classes
5.1. Overall Structure of a Class

• Structure of a Class Definition


Classes are the fundamental building blocks of a Java program. They act as
templates, defining the properties of objects within a program. Each instance of a class
template represents an object. And each object encapsulates the data and methods
defined by the class. Every Java class must be derived from a superclass. Within a Java
program, classes form a hierarchical structure of superclasses and subclasses.
Subclasses inherit data and methods from their associated superclass. But all Java
classes are originally derived from a root superclass called Object. All the classes in your
Java program can use the methods defined in the Object class. Object doesn't contain any
data.
The first step in generating a Java program is to define a class. The general form of
a Java class definition is similar to that of a C++ class. Each class declaration typically
includes:
Optional modifiers such as private and public
The class keyword
A valid identifier for the class
Optional clauses such as extends and implements
The function of the class declaration is to define data and methods for objects in a
given class. In Java, the data components of an object are called "instance variables".
Variables and methods are sometimes referred to collectively as "class members". You
can think of a Java class conceptually as having a public external section and a private
internal part.
The external section is made up of public methods and variables. Public methods
and variables represent everything the external users of the class need to know, or are
allowed to know. The internal part of a class is typically made up of private instance
variables. It may also contain some private methods.
Internal class members are invisible to the objects of other classes. Typically, you
control access between class members and other objects using one of three access
modifier keywords:
Private
Public
Protected
If you don't specify an access modifier keyword, the default access modifier is
applied. This modifier specifies that only classes in the same package can access a
class's variables and methods. A package is a group of related classes and interfaces.

Page 128 Go To INDEX


For more information about packages, see SmartForce’s Java course Introduction
to the Java language. Class members declared with the private modifier are accessible to
objects within their own class only. For example, an instance variable declared as private
cannot be manipulated by methods outside its class. And a private method cannot be
called from outside its class. In fact, the only way to gain access to a private variable or
method from outside its class is by calling one of the public class methods.
A public modifier denotes a class member as being directly accessible to all other
classes. If a public modifier precedes the class keyword, that class is visible to all other
classes. The protected modifier specifies that class members are accessible only to
methods of classes in the same package and to all subclasses of that class, regardless of
their package.
This modifier is useful because it gives derived classes the ability to directly access
protected variables within their parent classes. Methods are usually declared public and
instance variables are normally declared private. Public methods represent the public
interface of a class, or the services that the class provides.
Using public data is uncommon and is a dangerous programming practice. Several
access modifiers have been used in this program.

As you can see, these modifiers must explicitly precede an object's instance
variable or methods. But within a class definition, they can appear in any order. The ability
to hide instance variables and methods means that the exact layout of an encapsulated
object is hidden from other parts of the system.
In addition, data integrity is enhanced because unauthorized methods cannot
access hidden data. Once you have declared a class, you need to create, or instantiate,
objects within that class.
Using the new operator, you can instantiate a single instance of a named class and
return a reference to that object.

Page 129 Go To INDEX


className objectReference = new className ()
In this example, velazquez is a reference to an instance of Employee.
Employee velazquez = new Employee ();
The variable velazquez doesn't actually contain the object - the variable is just a
reference to it. You are not limited to creating single references to one object. In fact,
multiple variables can reference the same object. In this example, you create a single
Employee object, referenced by the variables velazquez and vinny. Any changes to the
object referenced by vinny will affect the same object referenced by velazquez.
Employee velazquez = new Employee ();
Employee vinny = velazquez;
Using the new operator is the only way to create an object in Java. You can check if
a particular object is an instance of a specific class by using the instanceof operator.
objectReference instanceof className;
The instanceof operator returns a true value if the object preceding the operator is
an instance of the class following the operator.
velazquez instanceof Employee
A true value will also be returned if the class named on the left implements the
interface on its right.
objectReference instanceof interfaceName
If the named object is not an instance of the specified class, or if it does not
implement the specified interface, a value of false is returned. The instanceof operator will
also return a value of false if the object specified on the left is null.

• Using Variables In Java


Data is encapsulated in a class within the braces of the class declaration. This
program declares a class named Employee, with four instance variables.

Page 130 Go To INDEX


A Java class can have both primitive data types and other classes as its instance
variables.
Every time you create a new object, you generate a distinctive set of instance
variables. In this way, the instance variables of each object are separate from the
variables of other objects. Each object has a copy of the instance variables of its class.
Sometimes it may be desirable to make a single copy of a particular variable available to
all instances of a class. You do this using the static modifier.
Using the static keyword, you can create a variable that can be used outside the
context of any instances. Static variables are equivalent to global variables and are
accessible to other pieces of code, subject to any access modifiers specified in their
declarations. The dot (.) operator is used to access instance variables within an object.
This operator can also be used to call methods within an object. Let's look at the general
form for accessing instance variables using the dot operator.
objectReference.variableName = value;
The variableName is the name of the instance variable inside the object that you
want to access.
You can see that Java uses the dot (.) operator in conjunction with the
objectReference to specify the instance variable to be called. Using the dot operator in this
way, you can store an employeeNumber value for velazquez.
velazquez.employeeNumber = 004081;
And this code lets you access the employeeNumber associated with velazquez.
Int currentEmployee = velazquez.employeeNumber;

Page 131 Go To INDEX


• Using object methods
Methods are functions attached to a class declaration. They enable a class to
perform specific actions. In Java, methods are declared inside a class definition at the
same level as instance variables. Because Java methods are all defined within a class,
the scope resolution operator, which will be familiar to C++ programmers, is unnecessary.
Remember; when methods are declared, you can specify a certain type of return value
and a set of input parameters.

If no return value is desired, then you replace the returnTypeValue with void. And if
no parameters are desired, the method declaration includes a pair of empty parentheses.
Using this example, three methods are declared inside the class braces.

These methods are declared within the same scope as the instance variables. As
you know, objects communicate with one another through messages. A message sent
from one object requests that some method, or action, be carried out on another object's
data. So passing messages is often referred to as method calling.
Methods are called on an instance of a class using the dot (.) operator. The general
form for calling methods within an object is shown here:
objectReference.methodName (parameterList);
The objectReference is any variable, which refers to an object. The methodName is
the name of a method in the class from which objectReference was instantiated. And
parameterList is a comma-separated list of values or expressions. The parameterList
values exactly match in number and type with one of the methods declared as

Page 132 Go To INDEX


methodName in the class (or inherited from the superclass). This code enables you to
increase the salary of velazquez by 7 percent.
velazquez.salaryIncrease (7);
Here the dot operator enables you to access salary information by calling the
getSalary method on the velazquez object.

• Using This And Super


Any variables that refer to objects of a class are known as "object references". In
Java, there are two special keywords, which act as object references:
this
super
In Java and C++, each object has access to a reference to itself called the "this"
reference. The "this" reference represents the current object. The “this” reference is not an
instance variable of an object. It is passed to the object as an implicit argument inside
every nonstatic method call and references the current object. So when any nonstatic
method of object is run, that method has access to the “this” reference. You can use the
“this” reference for any reference to an object of the current class. It can be used to refer
to both the instance variables and methods of an object. Let's look at an example of where
you might use a “this” reference.

Suppose a parameter of a class's method has the same name as an instance


variable of that class. When this method is called, the instance variable will be obscured
by the identically-named parameter within the method.
To access the hidden instance variable when you are using this method, you
precede the instance variable's name with the keyword this and the dot operator. This
enables the program to differentiate the object's hoursWorked variable from the parameter
hoursWorked.
Each time an object of a class is created, the variables defined in that class must
be initialized. To avoid this tedious process, classes may implement a special method
called a "constructor". A constructor is a method that initializes an object immediately upon
creation.

Page 133 Go To INDEX


When an object of a subclass is instantiated, the superclass's constructor is called
to initialize the superclass instance variables of the subclass object. The "super" reference
is used to call the superclass constructor for the current object. Let's look at an example.

Here you have defined a class called PartTimeEmployee. This class is a subclass
of the class Employee. Using the super reference you can invoke the constructor method
of the Employee superclass. Each subclass inherits the data and methods of its
superclass. But sometimes a subclass may redefine a superclass method using the same
methodName. This is known as overriding a superclass method.
Whenever an overridden method is referenced in the context of a subclass, the
method in the subclass is the one selected. But you can access the superclass version of
that method by using the super reference followed by the dot operator. For example, this
statement lets you call a superclass's getWeeklyWageBill method.
super.getWeeklyWageBill
If you don't want to allow subclasses to override superclass variables or methods,
you declare them as "final". All future references to a final class member will rely on the
superclass definition.

5.2. Object Life Cycle

• About Constructors
When you declare a class in Java, you can declare an optional type of method that
performs initialization when you instantiate objects from that class. A constructor is a
special type of method called when an object is instantiated. Constructor methods have
unique characteristics and a unique purpose. They are used to set properties and to
perform other initialization tasks when instances of a class are created.
Constructors use syntax similar to that of methods, but they don't return values. The
declaration of a constructor requires just a straightforward addition to the standard class
declaration. There are two main rules for declaring constructors:
The constructor name and the class name must be the same
No return type is specified when declaring the constructor

Page 134 Go To INDEX


Java requires that an ordinary method declare the data type of the value that it
returns. If a method does not return a value, it must be declared to return void. A
constructor is automatically called when an object is instantiated. Generally, constructors
are used to initialize the instance variables. Constructors can perform various tasks
related to object creation, such as connecting to a server or performing some initial
calculations. Constructors also provide one of the ways to give values to instance
variables. Instance variables can:
Be initialized in a constructor of the class
Be initialized implicitly
Have their values set later after the object is created
In most cases, it is appropriate to provide a constructor to ensure that every object
is properly initialized with meaningful values. For instance, it would be pointless to initialize
a variable representing the hour on a 24-hour clock to 25. When you create an object of a
class, arguments can be provided in parentheses to the right of the class name. These
arguments are passed as parameters to the class's constructor. The use of constructors is
closely linked to Java's use of dynamic memory allocation. Just as with other reference
variables, you must allocate instances of classes.
Instances of classes are dynamically allocated using the new keyword. Any time
you allocate memory with new, that memory comes from the heap. The heap is the
collection of memory from which class instances are allocated. The new statement tells
the compiler to generate code, which will allocate memory for an instance of the class, and
points a variable to the new section of memory. In the process of doing this, the compiler
also calls the class's constructor method and passes the appropriate parameters to it.
If you don’t create your own constructor, one will automatically be created for you
that calls the constructor of the class's superclass. This default constructor does not take
any parameters and if you could see it, it would look something like this.

This allows you to create new instances of your classes. The default constructor for
a class calls the constructor for the superclass.
YourClass yc = new YourClass();
It then proceeds to initialize the instance variables in the following way:
Primitive or numeric datatype variables are set to 0
Booleans are set to false
References are set to null
If you define constructors for a class, Java will not create a default constructor for
the class. However, you can overload a constructor in the same way that you would
overload a normal method. To overload a method of a class, you simply provide a
separate method definition with the same name for each version of the method.
Overloaded methods must have different parameter lists. An object can now be
instantiated with this constructor.

Page 135 Go To INDEX


This call creates an object with var1 set to 100 and var2 set to 2. The keyword "this"
in the declaration refers to the current instance of the object. You use it to differentiate the
var1 of the object from that of the parameter. Because local variables and parameter
variables hide instance variables, they will be used unless the “this” keyword is used.
Effectively, this appears in front of every call to an object's variable. So the var2
initialization of the constructor would be:
this.var2 = 2;
You could also use another constructor to set the initial values for both variables.
The call to this constructor is similar to the call to the constructor when only one instance
variable is to be instantiated. This call creates an object with var1 set to 100 and var2 set
to 200.

Note it is also possible for the programmer to provide a constructor without


parameters. This is done by placing an empty set of parentheses after the class name
when allocating a new object. Often, a class does not have any constructors without
parameters provided for it, but it has other constructors.
In such a case, a syntax error will occur if an attempt is made to call a constructor
without specifying arguments to initialize an object of the class. A constructor may be
called with no arguments only if:
There are no constructors for the class (the default constructor is called)
There actually is a constructor with no parameters in the class definition

• Finalization
Constructors can acquire various system resources such as memory. Because
Java has automatic memory management, you don't have to explicitly delete objects.
Each class in Java can have a finalizer method that helps return resources to the system.
When a resource is no longer referenced it is ready to be returned to the system.
Finalization is a disciplined way to begin to give resources that are no longer needed back
to a system to avoid resource leaks. If you define a finalize() method for your object, then
you’ve enabled finalization for your object.
Because finalize() belongs to the java.lang.Object class it is present in all classes. It
is declared to be protected in java.lang.Object and thus must remain protected. The
finalize method may be called some time after the system has determined that your object
is a candidate for being returned.
In effect, finalization means that before an object is returned to the system, the
Java run-time system gives the object a chance to clean up after itself. Before an object is
garbage collected, the run-time system calls its finalize() method.

Page 136 Go To INDEX


The finalize() method is the closest thing Java objects have to a destructor method.
While the finalize() method is very similar to the destructor method in C++, it has some
subtle differences. The intent is for finalize() to release system resources such as open
files or open sockets before garbage collection. A class’s finalizer method always has the
name finalize().
A finalizer receives no parameters. It does not return a value, so its return type is
void. The finalizer method is empty by default. A class can have only one finalize method -
finalizer overloading is not allowed. Finalizers are rarely used with simple classes. A class
can override the finalize method it inherits from a superclass. You can never be sure when
the finalize method will be called. Because resources are not returned to the system at
predictable times, you need to use the finalize() method carefully.
If a resource is in short supply it is better to release it when it is no longer required
rather than waiting for the finalize() method to be called. The finalize() method is declared
in the java.lang.Object class. This means that when you write a finalize() method for your
class you are overriding the one in your superclass. Your class can provide for its
finalization simply by defining and implementing a method in the class named finalize().
Your finalize() method must be declared as follows:
protected void finalize()
For example, in a class that deals with sockets, it is good practice to close all
sockets before destroying the object defined by the class. Therefore, you could place the
code to close the sockets in the finalize() method. Once the instance of the class is no
longer being used in the program and is destroyed, this method would be invoked to close
the sockets. An object must shut itself down in an orderly fashion. Let's look at an
example.

This finalize method merely closes an I/O file stream that was used by the object, to
ensure that the file descriptor for the stream is closed. You can force object finalization to
occur by calling the runFinalization() method in System:
System.runFinalization();
This method calls the finalize() methods on all objects that are waiting to be
garbage collected to free up system resources. You could also invoke:
runFinalizersOnExit(boolean)
This enables or disables finalization on exit. Doing so specifies that the finalizers of
all objects that have finalizers that have not yet been automatically invoked are to be run
before the Java runtime exits. While the finalize() method is a legitimate tool, it should not
be relied upon. This is because garbage collection is not a predictable process. Garbage

Page 137 Go To INDEX


collection runs in the background as a low-priority thread and is generally performed when
a system has no memory left.
Consequently, it is good practice to attempt to perform such "clean-up" tasks
elsewhere in your code. You should resort to finalize() only as a last resort and when
failure to execute such statements will not cause significant problems.

• Garbage Collection
C and C++ give the programmer the responsibility for reclaiming dynamically
allocated memory. However, in Java the run-time system performs memory management
tasks for you. Java provides a facility that automatically reclaims dynamically allocated
memory that is no longer needed. In Java there is no need for an equivalent of the delete
operator that C++ uses. This facility is known as garbage collection. The Java garbage
collector is a mark-sweep garbage collector that scans Java's dynamic memory areas for
objects, marking those that are referenced. After all possible paths to objects are
investigated, those objects that are not marked (that is, not referenced) are known to be
garbage and are collected.
Java’s automatic garbage collector eliminates many memory leaks of the sort that
occur in C and C++. Most of these memory leaks are due to orphaned objects. Orphaned
objects are objects that are no longer referenced. A reference to an object that is held in a
variable is dropped when the variable goes out of scope.
Java’s garbage collection is not as efficient as the dynamic memory management
code that experienced C and C++ programmers write. However, it is relatively efficient and
much safer for the programmer to use. Java’s garbage collector runs as a low-priority
thread waiting for higher-priority threads to relinquish the processor. When Java
determines that there are no longer any references to an object, it marks the object for
eventual garbage collection. The garbage collector runs when processor time is available
and when there are no higher-priority runnable threads. The garbage collector will run
immediately when the system is out of memory. Before an object is garbage collected, the
garbage collector gives it an opportunity to clean up after itself through a call to the
object's finalize() method.
The garbage collector is a daemon thread - a thread that runs for the benefit of
other threads. Daemon threads run in the background, usually when processor time that is
available would otherwise go to waste. Typically this happens when a user pauses while
interacting with an application. Java's garbage collection is an example of multithreading.
Multithreading means that applications run several processes concurrently.
You can explicitly drop an object reference by setting to null the value of a variable
whose data type is a reference type. Setting an object reference to null marks that object
for garbage collection provided there are no other references to the object. This can help
conserve memory in systems that operate in certain ways.
For instance, a system in which a variable referencing an object is not going out of
scope because the method it is in executes for a lengthy period. When your program has
finished using an object, there are no more references to the object. The object is finalized
and is then freed.
The finalization and freeing of the object happen asynchronously in the
background. However, you can force object finalization and garbage collection using the

Page 138 Go To INDEX


appropriate method in the System class. The garbage collector runs in a low-priority
thread, and runs either synchronously and asynchronously depending on the situation and
the system on which you are running Java.
The garbage collector runs synchronously when the system runs out of memory, or
in response to a request from your Java program. You can ask the garbage collector to
run at any time by calling System's gc() method:
System.gc();
Asking the garbage collector to run does not guarantee that your objects will be
garbage collected immediately. This statement invokes the static method gc of the System
class to schedule the garbage collector to execute as soon as it can. You might want to
run the garbage collector to ensure that it runs at the best time for your program rather
than when it is most convenient for the run-time system to run it. For example, your
program may wish to run the garbage collector right before it enters a compute or memory
intensive section of code or when it knows there will be some idle time.
Some systems require about 20 milliseconds for the garbage collector facility to
finish its job. So, your program should only run the garbage collector when doing so will
have no performance impact on your program. In other words, when your program
anticipates that the garbage collector will have enough time to complete its task.
Some systems allow the Java runtime system to note when a thread has begun
and to interrupt another thread. In this case, the Java garbage collector runs
asynchronously when the system is idle. As soon as another thread becomes active, the
garbage collector is asked to suspend what it is doing and then terminate.

• Serialization
Later versions of Java have added a new mechanism called serialization. The idea
of serialization is to allow an object to be converted into a form that can be moved outside
of the Java environment. The Java objects are bundled so they can be passed along in
streams. Objects which have been serialized can be attached to any stream including
FileOutputStream or PipedInputStream.
The key to object serialization is to store just enough data about the object to be
able to reconstruct it fully. The building of all but the most short-lived applications requires
the capability to store and retrieve Java objects. Serialization lets you store objects as
easily as you store text or numeric data. If you wanted to save information about objects to
a file, you would:
Save the type of the object
Save the data that defines the current state of the object
Previously if you wanted to do this you would have to write code for every class to
explicitly load and save its data fields. This in effect is a manual task whereas serialization
is automatic. When you read this information back from a file, you must:
Read the object type
Create a blank object of that particular type
Fill it with the data that you stored in the file

Page 139 Go To INDEX


Object serialization provides a much easier way to do all this. When you are saving
an object the class of that object must also be saved. The class description contains the
name of the class as well as a 20-byte hash code of the data field types and method
signatures. Java gets the hash code by:
Ordering the field types and method signatures in a systematic way
Applying the Secure Hash Algorithm (SHA) to that data
Using the SHA means that each class is given a unique identification scheme - a
fingerprint. The class fingerprint will change if the data fields or methods are altered in any
way. Checking to see if this has occurred is very useful. Let's see why.
Suppose a particular object is saved to a file on disk. And later, a change is made
to the class such as deleting a data field. Now the data layout in memory no longer
matches the data layout on disk. The memory could be corrupted if the data were read
back in its old form. Java takes great care to make sure this type of memory corruption
does not occur. It checks that the class definition has not changed when restoring an
object. It does this by comparing the fingerprint of the current class with the fingerprint on
disk.
Serialization allows you to keep track of object versions. Java serialization means
that all objects that are saved to disk are given a serial number. When Java is saving an
object to disk it can find out if the same object has already been saved to disk. If it has,
then the new version can be referred to as being the same as the previously saved object
with serial number x. When Java is reloading an object it notes its serial number and
remembers where it was put in memory.
When Java encounters the tag "same as previously saved object with serial number
x" it looks up where it put this object with serial number x. Then it sets the object reference
to that memory address. Of course this process is carried out automatically by Java. The
goals for serializing Java objects are to:
Employ a mechanism that is simple yet capable of being extended.
Maintain the Java object type and safety properties in the serialized form.
Be extensible to support marshaling and unmarshaling as needed for remote
objects. Marshaling and unmarshaling refer to the processes of packing and
unpacking a method name and its arguments for transmission to a remote
system.
Be extensible to support persistence of Java objects.
Allow the object to define its external format.
Objects to be saved in a stream must implement either the "Serializable" or the
"Externalizable" Interface. To allow itself to be serialized, a class should implement either
the java.io.Serializable or the java.io.Externalizable interface.
An example of a class which should not be serialized is a class, which represents
inherently transient state, such as a java.io.FileDescriptor. For Java objects, the serialized
form must be able to identify and verify the Java class from which the object's contents
were saved. It must also be able to restore the contents to a new instance.
For Serializable objects, the stream includes sufficient information to restore the
fields in the stream to a compatible version of the class. For Externalizable objects, the

Page 140 Go To INDEX


class is solely responsible for the external format of its contents. Objects to be stored and
retrieved often refer to other objects. Saving object references gives rise to a number of
issues. Often one object is shared by several objects as part of its state. It is easy for
several copies of an object to come into existence rather than several references to the
one object.
If you want to change an object, you then have to track down all copies of it to do
so. It is better if you save and restore only one copy. You have to copy and restore the
original references to the objects. This is because you want the object layout on disk to be
exactly like the object layout in memory. This is known as persistence. Lightweight
persistence is that which occurs in a relatively simple application. To maintain the
relationships between the objects, those other objects must be stored and retrieved at the
same time. When an object is stored all of the objects that are reachable from that object
are stored as well.
Object Serialization extends the core Java input/output classes with support for
objects. It supports the encoding objects and the objects reachable from them, into a
stream of bytes, and it supports the complementary reconstruction of the object graph
from the stream. Serialization is used for lightweight persistence and for communication
via sockets or Remote Method Invocation (RMI).
The Java RMI (Remote Method Invocation) API enables method invocation
between two remote Java applications. This can be accomplished in a client/server
manner or in a peer-to-peer manner. RMI means that applets and applications on different
machines can communicate with each other by invoking each other's methods.
The default encoding of objects protects private and transient data, and supports
the evolution of the classes. Object serialization produces a stream with information about
the Java classes for the objects that are being saved.
For Serializable objects, sufficient information is kept to restore those objects. This
occurs even if a different, although compatible, version of the class's implementation is
present.
The interface Serializable is defined to identify classes that implement the
Serializable protocol:
package java.io;
public interface Serializable { };
A Serializable object:
Must implement the java.ioSerializable interface
Must mark the object fields that are not to be persistent with the transient
keyword
Can implement a writeObjectmethod to control what information is saved or
to append additional information to the stream
Can implement a readObjectmethod so it can read the information written by
the corresponding writeObjectmethod or to update the state of the object
after it has been restored
ObjectOutputStream and ObjectInputStream are classes designed and
implemented to allow the Serializable classes they operate on to evolve. In other words,

Page 141 Go To INDEX


they allow changes to the classes that are compatible with the earlier versions of the
classes. For Externalizable objects only the identity of class of the object is saved. It is the
responsibility of the class to save and restore the contents. The interface Externalizable is
defined as:

An Externalizable Object:
Must implement the java.io.Externalizable interface.
Must implement a writeExternal method to save the state of the object- it
must explicitly coordinate with its supertype to save its state.
Must implement a readExternal method to read the data written by the
writeExternal method from the stream and restore the state of the object.- It
also must explicitly coordinate with the supertype to save its state.
It also must explicitly coordinate with the supertype to save its state. Supertypes
are those types defined in the class from which an object is instantiated. If writing an
externally defined format the writeExternal and readExternal methods are solely
responsible for that format. The writeExternal and readExternal methods are public. This
raises the risk that a client may be able to write or read information in the object other than
by using its methods and fields. These methods must be used only when the information
held by the object is not sensitive or when exposing it would not present a security risk.
Let's look at a basic serializing example that shows how to read and write objects and
primitives to a stream. The example shows you how to write today's date in serialized form
to a file.

First an OutputStream, in this case a FileOutputStream, is needed to receive the


bytes. Then an ObjectOutputStream is created that writes to the OutputStream. Next, the
string "Today" and a Date object are written to the stream. More generally, objects are
written with the writeObject method and primitives are written to the stream with the
methods of DataOutputStream. You could also read today's date from a file. Let's look at
an example:

Page 142 Go To INDEX


For most objects, the default writeObject and readObject methods provided by
object serialization are sufficient. They write or read each field individually. A field that is
marked transient or static will not be written by the default writeObject method, and will be
set to the type-appropriate default value by the default readObject method.

5.3. Interfaces, Casting, And Reflection

• About Interfaces
Some programming languages, such as C++, enable a single class to inherit
characteristics from several superclasses. This is known as multiple inheritance. While this
is a powerful feature, it is complex to use and can give rise to performance problems. Java
supports single, rather than multiple, inheritance. Using single inheritance, each Java
class can be derived from a single superclass only.
If you want to derive a class from multiple superclasses, single inheritance may
seem like a limitation. "But Java has a solution to this problem, called an ‘interface’ ".
Using an interface, a single Java class can inherit unimplemented methods from many
different classes. An interface is a special type of abstract class. As you know, abstract
classes are superclasses that act solely as templates for more usable classes. It is not
possible to instantiate objects directly from an abstract class. Instead, you define more
specific classes, which implement the methods in the abstract class. Each abstract class
defines at least one abstract method. Abstract classes are unimplemented classes that
typically describe general behavior. Classes describing general behavior are located high
in the class hierarchy. They provide unspecific methods that can be utilized by many
subclasses.
Interfaces and abstract classes are not synonymous. Abstract classes can define
abstract and nonabstract methods. But all the methods defined in an interface are
implicitly abstract and are therefore unimplemented. The unimplemented methods in an
abstract class represent an interface. They determine what the class using the interface
can do. An interface may also contain variables with constant values. These values are
used by the class implementing the interface.
An interface doesn't specify exactly how each of its methods work. A method's
implementation contains a description of how a method works. In Java, interface
declarations and the implementations of their methods are stored separately. Method
implementations are stored in the class that uses, or "implements", that interface.
Unimplemented methods are not much use on their own. They only become useful
when they are implemented by concrete, or "real", classes. An interface is linked to any
class that contains an implementation for the methods defined in that interface. So many
different classes in the class hierarchy can use the interface in a similar way to inheriting
from a superclass. Interfaces provide many of the same benefits as abstract classes. At
their most basic level, they provide a set of methods that can be implemented by many
classes.

Page 143 Go To INDEX


Like abstract classes, they can act as a template for deriving new classes in a
structured manner. Since interface methods are unimplemented, they allow you to define
methods for a class without worrying about the implementation details. This means that if
the implementation of an interface method is altered, the change will not disturb the
associated interface. And because implementation code changes are isolated, they help
prevent the propagation of bugs. Perhaps the most important advantage of using
interfaces is that they enable a single class to inherit methods from more than one
superclass. This is a new twist on the concept of multiple inheritance. A C++ class can
inherit method implementations from more than one superclass.
In Java, a class can inherit method implementations from only one superclass.
However, Java classes have the ability to inherit additional abstract methods through the
use of interfaces. In this case, the class inheriting the interface must provide the
implementation for the abstract methods.

• Declaring Interfaces
This is the syntax for creating an interface in Java.
interface InterfaceName {
interfaceBody
}
The interface keyword is used to declare a new interface. And the interfaceBody
refers to the abstract methods and variables that make up an interface. This code declares
a public interface.

All the methods and variables in a public interface are implicitly public, so the public
modifier is optional here.
Any variables declared in an interface are implicitly static and final. The declaration
of these modifiers is optional. Even if you don't explicitly state them, they will be implicitly
assumed by the program. In addition, interface variables may not be transient or volatile.
This ensures that interface variables have constant values. As you know, the declaration
of an interface method and its implementation are stored separately. The interface method
declaration is stored in the interface definition. And the implementation is stored in the
class that implements the interface. This is the syntax for declaring a method in a concrete
class.

Page 144 Go To INDEX


A method declared in a concrete class will include implementation details, in the
form of a methodBody.
An abstract method has no methodBody. It is simply a method signature followed
by a semicolon.
returnValue Type methodName (parameterList);
Any class that includes an abstract method is automatically abstract itself, and must
be declared as an abstract class. You can see that the abstract methods defined as part of
the Racket interface have a semicolon after their parentheses. There are no braces, and
no methodBody is defined.
Because all the methods in an interface are implicitly abstract, the abstract modifier
is obsolete. This modifier should not be used in new Java programs. As you can see,
declaring an interface in Java is very similar to declaring a class. But there are a few
differences. For example, the only modifiers that can be used with the interface keyword
are the public and abstract modifiers. Interface methods may not be declared as final,
native, static or synchronized.
In addition, the interfaceBody may not contain any constructors, static class
initializers, or instance variables. Just as you can derive a subclass from a superclass, you
can derive a new interface from an existing interface. You do this using the extends clause
of an interface declaration. The derived interface implicitly inherits the variables and
methods of the parent interface. But you can also define new variables and methods for
the new interface. You can even derive a single interface from several existing interfaces.
In this case, the interfaces named in the extends clause are separated by commas.

An interface acts as a template for a usable class. In fact, you can't use interface
methods until the interface is implemented by a concrete class. In order to generate a
class, which can implement interface methods, you use the implements keyword.

The className variable represents the class and interfaceName represents the
interface this class will implement. A class implementing an interface method must provide
an implementation, or methodBody, for that method.

• Casting
The process of converting one datatype to another is called "casting". Java
supports casting between data types. Since each class is considered to be a new type,
Java also supports casting between classes. Let's look at an example of class casting.
Suppose B is a subclass of A. If you cast B to A, then an instance of B can be used as an
instance of A. As you can imagine, casting can give rise to some potentially complex
manipulations. The Java language restricts casting to help prevent system corruption.

Page 145 Go To INDEX


Let's look at the casting relationship between superclass and subclass objects. In Java
programs, objects can be cast:
From a subclass to a superclass
From a superclass to a subclass
Casting between sibling classes isn't allowed in Java. Attempting to do this causes
a compile-time error. If a subclass object is cast to a superclass, the object will be treated
as if it were an object of its corresponding superclass. This is called "widening". You can
cast from a subclass to a superclass implicitly or explicitly. An explicit cast isn't required
when you are casting from subclass to superclass. But, for clarity, it's good practice to use
one. You use this syntax to cast a class explicitly.
(className) ref
The “className” is the object being cast to and “ref” is a reference to the object
being cast. The cast type must be provided in parentheses. Casting affects only the
reference to the object, not the object itself. Because subclasses contain information tying
them to their superclasses, casting from subclass to superclass is completely reliable.
However, superclass objects cannot automatically be cast as subclass objects. To cast a
superclass object as a subclass object, you must use an explicit cast reference. This is
known as "narrowing".
In this type of casting, the compiler has no way of knowing if the object being cast is
an instance of the subclass to which it is being cast. As a result, narrowing isn't considered
to be completely reliable. Whenever you cast from a superclass to subclass, the cast is
automatically checked at run time. This ensures that the object is actually an instance of
the subclass, or is one of its subclasses. If the object is not an instance of the subclass,
then a runtime exception is generated.

• Reflection
Reflection describes the ability of Java code to retrieve information about Java
classes during run time. Using reflection, you can find out the access privileges, fields, and
methods associated with a given class. You can also retrieve information about the
superclass and interfaces associated with a class. It is even possible to query the
constructors used in a class. In order to inspect Java classes, you need to specify a
reflection environment. This environment provides the functionality needed to view class
information. In Java 1.1, the Java root class Class has been extended to support the
concept of reflection. The API defines a number of new classes, including:
Constructor
Field
Method
Array
Each of these classes defines new methods in addition to those inherited from the
root class, Object. These classes are contained in the library java.lang.reflect. The
Constructor class is used to create new objects. The Field class provides "get()" and
"set()" methods. These enable you to read and modify the fields associated with objects in

Page 146 Go To INDEX


a class. The Method class is used in association with the "invoke()" method. This calls
methods associated with the objects in a class.
In this example, the call returns an array of Method objects that describe all public
methods of the class to which x belongs.
x.getClass.getMethods();
The Core Reflection API accommodates two categories of applications. One
category is comprised of applications that query and use all of the public class members of
a target object, based on its run-time class. These applications require run-time access to
all the public fields, methods, and constructors of an object.
Examples of applications that query public class members would include service
applications, such as Java Beans, and lightweight tools, such as object inspectors. These
applications use instances of the classes Field, Method, and Constructor. Instances of
these classes are obtained through the methods:
getField
getMethod
getConstructor
getFields
getMethods
getConstructors
The second API category consists of sophisticated applications that query and use
the members declared by a given class. These applications require run-time access to the
implementation of a class at the level provided by a class file.
Examples of applications in this API category include development tools, such as
debuggers, interpreters, inspectors, and class browsers. Run-time services, such as Java
Object Serialization, are also included in this category.
Development tool applications use instances of the classes Field, Method, and
Constructor. Instances of these classes are obtained through the following Object
methods:
getDeclaredField
getDeclaredMethod
getDeclaredConstructor
getDeclaredFields
getDeclaredMethods
getDeclaredConstructors
Of course, there are some limitations on the information you can retrieve using
reflection. Security provisions ensure that the private properties of a class are revealed to
authorized code only.

Page 147 Go To INDEX


5.4. Exception Handling

• Handling Exceptions As Objects


Programs are often designed with a view to making them work under ideal
conditions. A robust program is one that will function properly even under unusual or
exceptional circumstances. Java encourages the development of robust programs by
allowing you to anticipate exceptional conditions that might affect your program.
Exception handling is the feature that Java uses to help guard against errors and
exceptions. An exception is something unexpected or unusual that might occur during the
execution of your program.
For instance, a user could input a character when your program is expecting an
integer. One of the common exceptions that programs produce occurs when an attempt is
made to divide a number by zero. When an exception occurs the normal flow of the
program is interrupted. Your program could crash as a result. With a traditional
programming approach you would build some error correcting code into your program.
But this would lead to your code becoming expanded and bulky. The traditional
approach does not encourage strong error checking either. Java's implementation of
exception handling makes it easier to handle and recover from run-time errors. Using Java
exception handling enables you to separate the error handling code from the functional
parts of your program. This improves program clarity and enhances modifiability.
In this way exception handling separates normal processing from error handling.
Exception handling is provided to enable your programs to catch and handle errors rather
than let them occur and suffer the consequences.
Exception handling catches run-time errors that cannot be caught at compile time.
There are two basic approaches to exception handling. These are termination and
resumption. In termination (which is what Java and C++ support) a run-time error is
assumed to be so acute that it is not possible to immediately re-execute the code that
generated the error.
A block of code is terminated when an error occurs. An error handler is then
executed. Program execution continues at the next block of code. The other approach to
error handling is called resumption. When resumption is used the exception handler is
expected to do something to rectify the situation, and then the faulting piece of code is re-
executed, presuming success the second time.
If you want to implement the equivalent of resumption in your Java program, it
means you want to resume execution at the piece of code that generated the exception
after the exception is handled. To achieve this you can use the techniques described in
this unit to place your code inside a while loop that keeps reexecuting the code until it
executes successfully.
When an error occurs in your program, the Java run-time system generates an
exception object representing the error. The presence of exception handling code imposes
very little execution-time overhead on programs unless or until exceptions occur. This act
of generating an exception object is called "throwing an exception". A thrown exception
will crash your program unless it is dealt with or handled in the correct manner. To be
handled, the exception object must first be caught.

Page 148 Go To INDEX


An exception handler is a piece of code written into your program that catches and
performs actions on the thrown exception object. When an exception object has been
thrown, the Java run-time system begins the search for a handler to manage the
exception. It first looks in the method where the error occurred, checking to see whether it
has an appropriate exception handler — one that handles the class or a superclass of the
thrown exception.
Whether you need an exception handler to successfully compile the program
depends on the type of exception thrown. The class of the exception determines whether
a handler is required. You can derive your own customized exception classes if the ones
Java provides do not suit your particular needs.
If no appropriate handler is found, Java will continue up the run-time stack and look
at the next method. This process repeats until the top of the stack is reached or until an
appropriate handler is found. If there is no appropriate handler Java calls the default
exception handler which displays a message describing the exception and dumps the
stack trace to standard output. Your program will then terminate.
Exceptions, like everything else in Java, are objects. Consequently, you can
explicitly generate an exception object by instantiating it with the new operator. Exception
handling should be used in any scenario where you anticipate that code may generate a
run-time error due to factors that are not easily controlled by your program. There are a
number of categories of problems you need to consider:
User input errors
Device errors
Physical limitations of disks etc.
The exception object must be an object belonging to one of the subclasses of the
Throwable class. You can picture the Throwable class as being at the top of the Exception
class hierarchy in Java. All exceptions are derived from the Throwable class. Immediately
below Throwable are two subclasses that divide exceptions into two distinct branches.
One branch is headed by Exception and the other by Error. Usually, the exceptions
which will be handled by your programs will be instances of one of the subclasses of
Exception. The Error class is for internal errors and resource exhaustion inside the Java
run-time system. You should not normally attempt to catch exceptions derived from the
Error class because they represent serious errors within the run-time system. Instead the
main focus of your exception handling should be on catching exception objects derived
from the Exception side of the Throwable class hierarchy. Objects derived from the
Exception class can be of two types:
Those that are derived from RuntimeException
Those that do not.
A run-time exception typically results from something erroneous in your
programming. Any other exception usually occurs because an otherwise well-written
program was used incorrectly. Exceptions that are derived from RuntimeException
include:
Attempting to access an out-of-bounds array element
Bad casting

Page 149 Go To INDEX


Arithmetic exceptions such as divide by zero
Exceptions that are not derived from Runtime Exception include:
Reading past the EOF flag
Trying to open an incorrect URL
Trying to access a class or an object using a string that contains the nameof
a non-existant class

• Handling errors using try, catch, and finally


Once an exception object has been thrown it has to be caught so that it can be
dealt with properly. Catching an exception requires a little more effort than throwing one.
To catch an exception you must set up an exception handler. Exception handlers are often
referred to as try-catch blocks. They consist of a try block and a catch block, each of which
performs a particular role in the exception handling mechanism. It is really the catch block
part that handles the exception.
You place the code that may cause the exception in a try program block. The
exception handling code goes in the catch program block.

Java executes the code in the try block first. This is called the try block because
you try running your code there. If an exception occurs Java ignores the rest of the code in
the try block and jumps to the catch block. The program now handles the exception. If the
code in the try block executes without throwing, an exception Java skips the catch block.
There is no need in this case for an exception handler because no exception has
been thrown. Checking for errors in a programming language that doesn't support
exception handling is problematical. You have to surround every method call with setup
and error testing code, even if you call the same method several times.
But with exception handling, you put everything in a try block and capture all the
exceptions in one place. This makes your code much easier to write and read because the
goal of the code is not confused with the error checking. You can also catch multiple
exception types in a try-catch block and handle each type differently.
Each exception object (e1,e2,e3) contains information about the nature of the
exception. You can also find out more about the exception object. For instance, you can
get a detailed error message.
e1.getMessage();

Page 150 Go To INDEX


You can also find the actual type of the exception object. You will sometimes want
a particular block of code to execute even if an exception has occurred in a try block.
e1.getClass().getName();
To do this you use a finally clause after your exception handling code. Finally is an
optional block, which provides code to be executed regardless of whether an exception
occurs. Java stops processing all code in the try block within a method when it throws an
exception.

However, local methods often acquire resources that only they know about. A
problem arises if these resources are not cleaned up by the method. One solution to this
type of problem would be to catch and rethrow the exceptions. However, this is
cumbersome because you need to clean up in both the normal code and the exception
code. The finally statement is Java's solution to this problem. It is used for doing essential
cleaning up that under no circumstances may be omitted. Let's look at some possible
scenarios. If the code in your method throws no exceptions, Java first executes all the
code in the try block. Then it executes the code in the finally block. Your code could also
throw an exception, which gets caught by a catch block. In this case Java will execute all
code in the try block, up to the point at which the exception is thrown. The remaining code
in the try block is then skipped. Next, Java executes the code in the relevant catch block,
and then the code in the finally block.
If the catch block does not throw an exception, the first line after the try-catch block
is executed. If it does throw an exception, it will then throw it back to the enclosing block of
code, or to the part of the program that called the method containing the try-catch block.
Your code might throw an exception that is not caught by any catch block. Java will
execute all the code in the try block up to the point where the exception is thrown. Then
Java executes the code in the finally block.
Next, the exception is thrown back to the enclosing block of code, or to the part of
the program that called the method containing the try-catch block. You can also use
nested exceptions. In this case if the int variable y evaluates to 0, an arithmetic exception
is thrown. When this exception is caught the code attempts to perform another division
operation.
However, this is also a divide-by-zero error. Another exception is thrown and is
caught by the nested ArithmeticException catch block. Suppose that there was no divide-
by-zero problem but the array index was illegal. In such a case, the outer
ArrayIndexOutOfBoundsException catch clause would catch the exception.

• Exception Objects And The Throw Keyword

Page 151 Go To INDEX


Java allows every method an alternate exit path if it is unable to complete its task in
the normal way. In such a case the method does not return a value. Instead it throws an
exception object that encapsulates the error information. The method exits immediately
without returning a value. The code following the method call is not activated. Instead the
exception handling mechanism begins a search for a handler that can deal with that
particular error condition.
There are times when it makes sense for your program to deliberately throw an
exception. This is the case when your program discovers some sort of exceptional or error
condition, but there is no practical way to handle the error at the point where the problem
is discovered. The program can throw an exception so that another part of your program
will catch and handle the exception.
You use the throw keyword to throw an exception. The syntax of the throw
statement is:
throw exception-object;
In most cases, it will be a newly constructed object created with the new operator.
The string parameter in the constructor becomes the error message in the exception
object.
throw new ArithmaticException(“Division by Zero”);
You could also assign an identifier. When an exception is thrown during the
execution of a block of code and the exception is not handled in that block, then the block
is terminated.
EOFException e = new EOFException();
throw e;
Remember that try-catch blocks can also be nested.
Then the enclosing block of code or the calling method gets a chance to handle that
exception. If it doesn't do so, then it too is terminated and the next enclosing block of code
or the next calling method makes the next attempt at the exception. The exception will
crash the program only if it passes up through the entire chain of method calls without
being handled. A method that explicitly throws an exception must indicate this by adding
the following to the declaration of the method:
throws exception-class-name
This method returns a string if it executes as expected.
public string readLine() throws IOException
However a provision is made in case an error occurs. If an error occurs the method
will throw an object of the IOException class. Your program may throw an exception in one
of four possible cases:
You anticipate an error and write code which throws an exception with the
throw statement
You call a method that throws an exception
You inadvertently make a programming error which causes a run-time error
An internal error occurs in the Java run-time system

Page 152 Go To INDEX


In either of the first two cases, you must declare publicly that your method may
throw an exception. You do this by including an exception specification in the header of
the method. Note you can rethrow exception objects by calling throw in a catch block.

Occasionally, you may need to catch an exception without addressing its root
cause. For instance you may need to do some local cleaning up. In this case, calling throw
again sends the exception back up the calling chain.

Because the graphics object in the catch clause is a local object of the method, it
might not be disposed of for a long time unless you do so explicitly. You must specify in
the method declaration every exception that you throw within that method, but is not
handled within the method itself.
However you do not have to declare that a method may throw internal Java errors
that is exceptions derived from Error.

Neither should you declare that a method may throw exceptions derived from
RuntimeException such as ArrayIndexOutOfBoundsException. However if you expect
these types of exceptions to occur, you should handle them as close as possible to the
point in your program where they will occur.
An exception which is generated by the Java run-time system is often called an
implicit exception. All other exceptions are known as explicit exceptions. Explicit
exceptions are those explicitly thrown by code you write. They are normally derived from
the Exception class rather than the Error class. Implicit exceptions are typically due either
to programming errors (RuntimeException) or are out of your control (Error).
It is important to note that a method must declare all the explicit exceptions it
throws.

Page 153 Go To INDEX


6
Java User Interface Programming
6.1. User Interface Architecture

• Structure of an applet
Java is most often associated with the Internet and the WWW. Web pages can be
brought to life by embedding applets written in Java in them. But Java is not used merely
for writing applets. It can be used to write and develop full scale applications also. The
declaration of an applet is quite straightforward. You should note that the new class is
declared as public so that the class can be accessed when the applet is run in a Web
browser or in the applet viewer application.

If you fail to declare the applet class as public, the code will still compile but the
applet will refuse to run. So all applet classes must be public. The code for an applet does
not have a main method like the code in a conventional Java application program does.
The Applet class provides the foundation for applets - all applets are derived from the
Applet class. Every Java applet you create inherits a set of default behaviors from the
Applet class.
So you must import the java.applet package to begin with. In most cases, these
default behaviors do nothing. In fact, you have to override some of the methods of the
Applet class in order for your applet to provide useful functionality. There are five methods
in particular which trace the life cycle of an applet. The following four methods inherited
from the Applet class let you manage the life cycle of your applet:
init()
start()
stop()
destroy()
None of these methods are absolutely required to be overridden. However,
overriding them is necessary in all but the simplest applets. The fifth method, which relates
to the life cycle of an applet, paint(), isn't defined in the Applet class. Instead, Applet
inherits paint() from the Component class, a superclass in Applet's chain of inheritance,
which goes from Applet to Panel to Container and finally to Component.
An applet does not use a conventional constructor to perform initialization. Instead
it uses the init method, which works much like a constructor. A default constructor can be
provided for applets. However, all initialization will usually be performed in the init method.
You can use init() to initialize your applet's instance variables. It's called automatically by
the system when Java launches an applet for the first time. The init method takes the
following form:

Page 154 Go To INDEX


public void init() {
}
You typically override this method to set up resources that will be used throughout
an applet. Examples of such resources are fonts and buttons. This method is called once
and only once during the life cycle of your applet. However, if a new instance of the applet
is loaded for some reason or another, the init method will be called again. An example of
when you need to override init() is when you are allocating resources for the applet, such
as AWT components. The next stage in the applet life cycle is the start section which
begins when the start method is called. The start method takes the following form:
public void start() {
}
Start() is called automatically after Java calls the init method. While init() is called
only once during an applet's life cycle, start() may be called many times. Let's see why this
is so. Suppose you open a web page, which contains an applet. The init method is called
to initialize the applet. Next the start method is called.
You could then load another web page, which becomes the active page in your
browser. To keep the applet from the first web page running would be a waste of certain
resources. Each time you revisit the page that contains the applet the start method will be
called to reactivate the applet. This means that start() can be called repeatedly. Because
start() can be called repeatedly and init() only once, you put the code you need executed
only once into init() and not start(). If the start method is to be called repeatedly, there is
another method, which must be called in between each call to the start method.
This method is the stop method. The form of the stop method is:
public void stop() {
}
The stop method is the third of the four methods in the Applet class that give you a
structure on which you can build a useful Java applet. The stop method is automatically
called when the user moves off the web page in which the applet is embedded. So, it can
be called repeatedly just as start() can. The system can stop the applet by calling its stop
method and then later restart it by calling its start method again. The stop method is also
called just before an applet is destroyed. An applet that has been stopped will not receive
any events until it has been restarted.
The purpose of stop() is to give you a chance to prevent a resource-consuming
activity from slowing down the system when the applet is no longer the main focus of the
display. The stop method is the converse of the start method. Sometimes your applet does
not do anything that needs to be suspended when the user leaves the web page
containing the applet. In this case, you do not need to implement either the stop or start
methods. The init method also has a converse method in the life cycle of an applet. This
method is called destroy(). The destroy method takes the form:
public void destroy() {
}
Although Java is not guaranteed to call the finalize method for objects, it will call
destroy() when the browser shuts down normally. However, like finalize() the destroy

Page 155 Go To INDEX


method is a good place to do some cleaning up. And just like finalize(), it's unpredictable
when destroy() will be called. Therefore it should be used with some discretion. Applets
typically reside on a web page so you do not need to bother with destroying them. This
happens automatically when the user shuts down the browser. Any code for dereferencing
system resources should be put in the destroy method. These resources could include the
fonts that you might have used. The destroy stage occurs when the system is about to
remove the applet from memory. Like the initialization cycle, the destroy cycle occurs only
once.
If your applet has resources that need to be cleaned up before the applet exits,
destroy() is the place to do it. Although there is a paint stage between the stop and start
stages, it is often forgotten that the paint method is part of the life cycle of an applet. This
"paint stage" occurs whenever the applet's display has to be drawn on the screen. This
happens right after the applet's start stage, as well as whenever the applet is redisplayed
or changed. An applet's display is redisplayed or changed whenever it is brought to the
forefront of the screen, or when the program changes the applet's display in some way
and explicitly repaints the applet.
Every applet you write will have a paint method, which is the method you override
to display your applet. Note that you must import the java.awt.* libraries, which contain
information about the Graphics class, in order to override the paint method. The default
implementations of init(), start(), paint(), stop(), and destroy() have no effect. If you want
your applet to do something useful at these stages in its life cycle, you have to provide the
code yourself by overriding the appropriate method. The form of paint is as follows:
public void paint (Graphics g) {
}

• Overview of the AWT package


Java lets you write programs that use a Graphical User Interface (GUI). The class
library for basic GUI programming is the Abstract Window Toolkit (AWT). The AWT
package provides an Application Programming Interface (API) for common user interface
components such as buttons, menus, list boxes, and scrollbars. AWT provides an
underlying foundation for interfacing with the user. One of the main goals of Java is to
provide platform-independent GUI development. The GUI area has always been one of
the most problematical parts of creating portable code.
Java's AWT must interact with the GUI components of the native OS - a task that
an applet cannot otherwise accomplish. Applets do not make direct calls to an OS
because otherwise they could violate the security of the user’s machine. Components are
the building blocks of the AWT. The end-user interacts directly with these components.
Among the GUI elements provided by the AWT are:
Buttons
Radio buttons
Lists
Labels
Checkboxes

Page 156 Go To INDEX


Other AWT GUI elements are
Text fields
Text areas
Canvases
Scrollbars
Menus
The AWT addresses graphical interfaces on two different levels. At the lower level,
it handles the raw graphics functions and the different input devices such as the mouse
and keyboard. At the higher level, it provides a number of components like scrollbars and
buttons that you would otherwise have to code yourself. Lets look at some of the more
important classes in java.awt. The Component class is the foundation of basic controls
such as buttons and labels. It is also the superclass of more sophisticated controls, such
as dialog boxes, and even the Applet class. Container is a class that contains components
or other containers.
Panel is a visual container that can be used to hold other components, such as
buttons, list boxes, and other containers. The AWT Window class is used for popup-style
components, such as dialog boxes. The Font class is a class that produces font objects,
which can be customized, such as point size and style. The Event class encapsulates user
and system initiated events, such as mouse clicks, keyboard strokes, and the shutdown of
an applet.
The AWT notifies your applet whenever a key is pressed or released, whenever the
mouse moves, and whenever you press or release a mouse button. The Graphics class is
mainly used when a Component needs to be painted. Graphics encapsulates a wide
range of functions, including drawing text, polygons, and images. MenuComponent
provides the foundation for creating menus. AWT graphics utilities are low level utilities.
While not providing as much functionality as some 2D drawing packages, the Graphics
class lets you draw lines, boxes, circles, and polygons in different colors. Using the AWT
you can select different fonts and font styles for drawing text. You can draw text in
different sizes, proportions, and colors.
You can also determine the size of the characters you want to draw. Java has
become a popular tool for animating Web pages. Using the AWT you can create different
kinds of animation, from drawing a series of static images to creating flicker-free animation
applets. AWT lets you load images and draw them. The AWT contains methods for
loading GIF and JPEG files from the network and displaying them easily. You don't
necessarily have to know anything about the GIF and JPEG formats to use them.

• Designing a user interface with AWT


When you are building a GUI using the Java AWT you combine a number of
components. These are the essential building blocks of your user interface. Components
are things such as buttons, text areas, and scrollbars. You use the AWT to create the
code for most parts of your user interface. For instance, you need to write to:
Present the components exactly as you want them to look

Page 157 Go To INDEX


Position them correctly within a window. As a rule in the AWT you do not
specify absolute positions for interface elements.
Have them respond to user input
For a GUI-based program, you add the code to create the user interface elements
in the constructor of the derived class. Java programs with a GUI typically use a class
derived from Frame to represent the top-level window. Within that window you can have
divisions derived from the Panel class. Each Panel can group a bunch of components
together. This allows you to structure your interface more efficiently. One Panel could be
used to group buttons together while another could contain a text area. You might also
want to include an area where you can draw objects such as lines or circles on the
window. The solution for this is to add a canvas to the window.
A canvas is a rectangular area, which you can draw in. You derive a Canvas object
as follows:
class SomeCanvas extends Canvas
By default, a Canvas object has no specific size. At the minimum, you should
implement the setSize method in a canvas. It is also worthwhile implementing
getMinimumSize() and getPreferredSize(). In order to make your canvas do something
worthwhile, you should override the Canvas paint method. Most GUI displays incorporate
buttons. Clicking a button causes something to happen. You don’t explicitly paint a button
or any other kind of control. You simply place them on the frame and let them
automatically take care of painting themselves. You call add() to add the buttons to your
frame.

The add method takes as a parameter the particular component you want to add to
the frame. The constructor for a Button object lets you specify the string that you want to
be displayed on the button. If you want to customize the color of the button, you must:
Provide a name for the Button object
Invoke the setBackground method
Add the button

Sometimes it is better to get user input by offering a choice of options. Java uses
the Checkbox component for this. It overcomes problems associated with the user

Page 158 Go To INDEX


inputting plain text in response to a prompt. Error-checking code is also minimized by
using a series of checkboxes as opposed to receiving text input from the user.
A checkbox has two parts, a label and a state. The label is the text that is displayed
next to the checkbox itself. The state is a boolean variable that indicates whether the box
is checked. By default, the state of a checkbox is false, or Off. You can create a checkbox
using a constructor that takes the label string as an argument.

Whenever a checkbox is selected or cleared an event occurs, which you can


capture the same way you do a button event. You can check to see if a checkbox has
been selected by using the getState method.
public Boolean getState();
Radio buttons are another component that you can build into your GUI. They are
used in a different way to other buttons on a user interface. You can use radio buttons to
get user input.
Using radio buttons allows you to force a single choice among many. They are
called radio buttons because they work in the same way as the band selector buttons on a
radio. Each button can have one of two states - either Off or On. But only one button in a
group of radio buttons can be On at a given time. The AWT does not have a separate
class to represent the radio button so it reuses Checkbox instead.
To implement a group of radio buttons, you create an object of type
CheckboxGroup for every group you require. A CheckboxGroup has no constructor
argument. Its purpose is to group together a number of checkboxes to provide the
functionality of radio buttons. Radio buttons are not the best component to use if you are
dealing with a lot of possible options. For instance, a word-processing application interface
would become cluttered if you had to use a radio button for every font you could use. A
more suitable alternative is to use drop-down lists.
When the user accesses a drop-down list, alternative choices are displayed. As
with radio buttons, the user is forced to select only one element from a group of
possibilities. Customizing your interface using drop-down lists rather than radio buttons
can help you maintain consistency more easily.
This is because your interface changes every time you add another option with a
new radio button, but no matter how many new options you add to a drop-down list you
still need only one list. Drop-down lists are implemented using the Choice class. The
addItem method is used to add choice items.

Note java.awt has no combo box facility to combine a text box and a choice list.
Combo boxes allow the user to pick one of the choices or type in an option that is not
listed.

Page 159 Go To INDEX


The List component is similar to a drop-down list with multiple options visible at
once. For this reason it is suitable for cases with only a few options. Otherwise it would
occupy too much space on your interface. The advantage of Lists is that the user can
quickly and easily see what choices are available.
You can allow the user to make multiple selections in a List component but not in a
Choice component. The target operating system may have a keyboard shortcut, which
allows multiple selections to be made. For instance, under Windows 95 holding the Ctrl
key while clicking items will allow more than one to be selected at a time. The constructor
for a List has:
A parameter that takes then umber of items you want to display at one time
A boolean flag to indicate whether or not you want to allow multiple selection

You initialize a List just as you would a Choice component. Java's AWT also allows
your program to receive text that the user inputs. The TextField component is a one-line
area that allows the user to enter and edit text. TextField is inherited from TextComponent,
which lets your program:
Set the text to display
Select a portion of the text
Get the selected text as a String
Set whether the TextField is editable or not
The easiest way to create a TextField is by calling the constructor with no
arguments.
public TextField();
The constructor with no arguments will create an empty TextField with a default
width. You can add text to a window by putting it in a Panel.

You can initialize a TextField by passing a string argument to the constructor. The
second parameter of the constructor determines the width of the text field. Note that this
number is not an upper limit on the amount of characters that can be entered.
Instead it represents the width of the text field, or the maximum number of
characters, that will be shown on the screen at one time. The user will need to scroll to
see the rest of the text. Whether or not the text can be edited is controlled by passing a
true or false value to the setEditable method.
You can also use the setText method from java.awt.TextComponent to change the
contents of a text field.

Page 160 Go To INDEX


You can use another component to display more than one line of text at a time.
This is the TextArea component. It shares many common methods with TextField because
both are derived from a common class called TextComponent.
A TextArea object is like a TextField except that it can have multiple lines and has
significantly more functionality. You can create an empty TextArea with a default height
and width by calling the constructor with no arguments. When specifying the dimensions
of a TextArea, you must give both height and width arguments to the constructor.
For instance, this code creates a TextArea called "A text area" with 10 lines, each
30 characters wide.
UsersText = new TextArea(“A Text Area”, 10, 30);
Again the user is not restricted by the size you set. The text will scroll if the user
enters more text than the screen text area can display. The TextArea and TextField
classes have methods, which allow your program to get the text, which the user has
selected.
The TextArea class has an associated method called append().
Append(string)
It takes a string and appends it to the end of whatever text is in the TextArea. A
similar method is insert().
insert(string, int)
It takes as parameters a string as well as an integer, and is used to insert the
specified text (String) at the specified position (int).
The AWT also provides a very useful scrollbar facility. The Scrollbar class provides
a basic interface for scrolling that can be used in a variety of situations.
You can create a simple vertical scrollbar with an empty constructor.
public Scrollbar()
You can also specify whether your scrollbar is to be horizontal or vertical.
Scrollbar someScrollbar = new
Scrollbar(Scrollbar.HORIZONTAL,75,10,0,100);
Four other arguments can be passed in the declaration of a new scrollbar:
The initial scroll position
The size of the slider
The minimum value of the scrollbar position
The maximum value of the scrollbar position
Moving a scrollbar can update the value of the scroll position in three ways:
Line by line
Page by page

Page 161 Go To INDEX


An absolute value
If the user clicks the arrows of the scrollbar Java updates the display value in
increments or decrements of a number of lines at a time. Java updates page by page
when the user clicks on the space between the arrows and the slider part of the scrollbar.
An absolute update occurs when the user drags the slider up or down the scrollbar. You
have no control over how the position value changes for an absolute update, except that
you are able to control the minimum and maximum values. Many scrollbar features are
implemented in the AWT:
You can set the line increment value which is added to or subtracted from
the scrollbar position
public void setLineIncrement(int increment);
You can query the current line increment
public int getLineIncrement();
You can set the page increment value which is added to or subtracted from
the scrollbar position
public void setPageIncrement(int increment);
You can also query the page increment
public int getPageIncrement();
The AWT provides other useful scrollbar features:
You can find out the scrollbar's minimum and maximum position values
public int getMinimum()
---
public int getMaximum()
You can set the scrollbar's current position
public void setValue(int value)
You can query the current position
Public void getValue()
Menus are a fundamental part of any GUI. Java's AWT supports pull-down menus.
At the top of a window, you can place a menu bar, which contains the names of the pull-
down menus. As with other GUI menus, each Java pull-down menu can contain a number
of options that the user can choose from. Creating a menu bar is quite straightforward.
MenuBar someMenuBar = new MenuBar();
Once you have created a menu bar, you can add it to a Frame by using the
setMenuBar method.
someFrame.setMenuBar(someMenuBar);
You then create a menu object for each menu.
Menu fileMenu = new Menu(“File”);

Page 162 Go To INDEX


You can also put separators between the items in the menu to group related
actions together.
fileMenu.addSeparator();
Adding an item to the menu is also straightforward.
fileMenu.add(new MenuItem(“Open”));
You can now add the menus themselves to the menu bar.
someMenuBar.add(fileMenu);
You can add an instance of a menuItem class to a menu.
MenuItem saveMenuItem = new MenuItem(“Save”);
fileMenu.add(saveMenuItem);
You can enable and disable menu items by using enable() and disable(). When you
disable a menu item, it still appears on the menu, but it usually appears in gray and cannot
be selected by the user.
You can also create special checkbox menu items. These items can be toggled
between checked and unchecked. A string parameter containing the name shown in the
menus is used in creating a checkbox menu item, just like a regular menu item.
public CheckboxMenuItem(string ItemLabel);
The getState method returns true if a checkbox menu item is selected.
public boolean getState();
You can set the current state of a checkbox menu item with setState().
public void setState(boolean newState);

6.2. Event Handling

• The Delegation Event Model


The delegation event model was introduced in JDK 1.1. It supercedes the JDK 1.0
and JDK 1.0.2 inheritance event model, although backward binary compatibility is
maintained. If you use methods from the old event model, the compiler produces warnings
telling you that they are not approved. In the inheritance model, you subclass GUI
components and override their handleEvent() method. You can also override more specific
event handling methods in some components, such as action() or mouseDown().
These methods return a boolean value to represent the status of the event. If
boolean true is returned by the method, the event has been declared "handled", while if
boolean false is returned, then the event is propagated up the GUI component hierarchy to
the containing components.

Page 163 Go To INDEX


You can decide to handle all events in one place, using the handleEvent() method,
and use complex if/else or switch statements to process them. Or you can subclass each
particular component to handle its own events.

For example, the FocusButton subclass switches its foreground color when it gains
and loses the focus, from DEFAULTCOLOR to FOCUSCOLOR and back again.

The gotFocus() and lostFocus() methods are overridden event handling methods of
the Component class. The inheritance model suffers from many defects:
The requirement to subclass components is unwieldy
There is no clear separation between the user interface and the application
It is too complex and error-prone
Events are delivered to components even if they are not handled, making it
inefficient
The delegation-based event model aims to solve some of the problems in the
original inheritance event model. In this model, all events are objects - instances of
predefined event classes. Each type of event is represented by the combination of an
event class and an event id.

Page 164 Go To INDEX


You can even create events of your own by subclassing these event classes. Event
sources "fire", or originate, events. In the AWT, event sources are typically GUI
components. They define the events they fire by registering "listeners" for those event
types. The API provides predefined listener interfaces. One listener interface is defined for
each set of event types that a source can fire. These listener interfaces declare suitable
methods for handling events fired from event sources. Listeners are implementations of
one or more listener interfaces. They can include:
Classes that directly implement listener interfaces
Subclasses of abstract classes that implement listeners (adapters)
Extended GUI components
Adapters are abstract classes, each of which implements a listener interface. You
can subclass adapters to selectively override event handling methods. This means that
you need only override the event handling methods for the events you are interested in
and can ignore the others. Listeners have to be "registered" to receive method invocations
from event sources when events occur. Each component has a set of methods available
for registering listeners for each event type, of the form:
component.addeventlistener(theListener);

When listeners are registered, the Java run-time system automatically invokes the
correct method in the listener in response to events. Event sources can "fire" events to a
single listener or to multiple listeners. However, the Java run time system does not deliver
the events to the listeners in any predetermined order.
To achieve ordered delivery, you must broadcast to a single listener that can then
deliver the event to various other listeners in an ordered fashion. There is a special class,
called AWTEventMulticaster, that allows you to efficiently chain multiple listeners together.
Components can handle their own events. You extend components to override the default
methods defined for handling events. Subclassed components can override selected
event handling methods and ignore the others. The delegation-based event model allows
you to clearly separate the user interface from the application code. You can redevelop
your GUI without altering your application code in any way, and vice versa.
You will find debugging much easier when the interface and application are
separated, which is particularily important in large applications. Events are filtered by the
system, meaning that unwanted events can be prevented from reaching your event
handling code. This makes the model more efficient than the earlier one, which is
particularly important for frequent events, like mouse moves. The delegation event model
is equivalent to the event model used in the JavaBeans API.
Events can be introspected during design time, meaning that visual builder tools
can manipulate the events generated by components during design time. Once you grasp
the general principles involved in the AWT event model, you should be able to understand
the JavaBeans event handling model.

• Event Objects

Page 165 Go To INDEX


All events are instances of event classes in the event class hierarchy. There are no
public fields, or variables, for these events, but each event class defines all the methods
necessary for accessing information describing the event. All events belong to the class
hierarchy starting at java.util.EventObject.

This class has only two methods - getSource() and toString().


The getSource() method returns the Object that originated the event.
The toString() method returns a string value representing the event.
The root event class for all AWT events is AWTEvent, a subclass of EventObject.
The getID() method in AWTEvent returns the event identified as an int. All event types are
represented as predefined constants in the different event classes to which they belong.
There are five subclasses of AWTEvent:
ItemEvent
AdjustmentEvent
ComponentEvent
ActionEvent
TextEvent
Semantic events are higher-level events, which are common across a series of
visual components. ItemEvent, AdjustmentEvent, ActionEvent, and TextEvent are all
semantic event types. ItemEvents occur in components that have implemented the
ItemSelectable interface, which includes lists, checkboxes, and popup choice menus.
Events are generated when items within the component are selected or deselected by the
user. There are methods in the ItemEvent class for discovering which items are selected
or deselected. AdjustmentEvents occur in components, like scrollbars, that have numeric

Page 166 Go To INDEX


values that can be incremented or decremented by the user. As a scrollbar is moved, its
new position is notified to an adjustment listener as an adjustment event.
There are methods in the AdjustmentEvent class for finding the type of adjustment
event that occurred and the extent of that adjustment. TextEvents occur when text is
entered, deleted, or edited inside text entry fields. ActionEvents are semantic events that
include such actions as clicking a button or pressing a function key. Several different user
inputs may result in the same action event being generated. Allowing for generic action
events means that logically related, higher-level events can be grouped together for
handling in one place.
Low-level events occur as specific input, or as a windowing-event, to a particular
visual component on screen. ComponentEvent and all its subclasses are counted as low-
level events. The ComponentEvent subclasses are:
InputEvent
WindowEvent
PaintEvent
FocusEvent
ContainerEvent
InputEvent is the root event class for all component-level input events. InputEvent
has two subclasses:
MouseEvent
KeyEvent
There are times when you may need to consume an event to prevent it being
processed in the default manner by the originating component. For example, visual builder
tools may want to intercept events generated by components during design time.
However, only input events for extended components can be consumed. The consume()
method in java.awt.event.InputEvent is called to prevent an input event being processed in
the default manner.
All registered listeners will still receive the event for processing in the normal
manner, even if another listener has consumed the event. The normal, and easiest, way to
handle mouse events in a listener is to implement the MouseListener interface. The
interface defines one method for each mouse event type, such as mouseReleased() and
mouseClicked().
The relevant method matching the mouse event type is then automatically invoked
by the system. The MouseEvent represents each of the following mouse events using int
constants:
Clicked
Dragged
Entered
Exited
Moved

Page 167 Go To INDEX


Pressed
Released
You can obtain the id of the mouse event using the getID() method defined in
AWTEvent, and can then compare it to each constant in turn to see which subtype the
event belongs to. There are three types of key event defined, listed below, and each has a
corresponding method and constant:
Key typed
Key pressed
Key released
A key typed event is just a combination of a key press and a key release. Key
events include a method called getKeyChar(), which returns the char representing the key
pressed. For special characters, like function keys, constants representing each one are
defined in the class. The window event types are:
Activated
Deactivated
Closing
Opened
Closed
Iconified
Deiconified
An opened event occurs once, when a window is first opened. A closing event
occurs when a user selects an option to quit, while a closed event occurs after the window
has been actually closed. The iconified and deiconified events occur when a window is
reduced to, or expanded from, an icon on the desktop.
PaintEvents are special system events that aid the serialization of repaint/update
events for components. You should not use PaintEvents, or expect to handle them, in the
delegation event model. The two focus events are focus gained and focus lost. Permanent
focus is gained through a successful requestFocus() method call, a user mouse click, or
tab. Temporary focus on a component is gained as a side-effect of another operation, like
a window deactivation or scroll-bar drag.
Permanent and temporary focus events are distinguished using the isTemporary()
method. This hierarchy gives you great flexibility when handling events. It allows you to
choose at what level of abstraction you want to handle an event. A key event can be
handled as a key event, a component event, or as a semantic action event.
ContainerEvents occur when components are added to, or removed from, a container.
The registered container listener receives notification and can get the identity of the new
component using a getChild() method call. This allows containers to smoothly add or
remove input event listeners to their components as each one is added or removed. You
are free to add extra event types by extending any of the classes in the EventObject
hierarchy. You will, however, not normally need to extend event classes in this way.

• Sources, listeners, and adapters

Page 168 Go To INDEX


AWT events almost always originate from GUI components, in response to mouse
actions, key strokes, or other user activity. In the standard model, the system filters each
event by checking to see whether there is a listener registered to receive events of that
type for the component in which the event occurs. If the event is registered, it is sent to the
processEvent() method of the component firing the event. The processEvent() method
then selects the relevant method for handling that type of event. Then the event is passed
to the registered listener method that corresponds to that event type.
If you extend a component, you can override the processEvent() method. If no
listeners are registered, then the system will filter out all events, so you must explicitly
enable the events you wish to handle. You do this by calling the enableEvents() method in
Component with a relevant event mask. Event masks for each type of event are long
integer constants defined in the AWTEvent class.
You only need to explicitly enable events if you are not registering listeners for
those event types, since they will be enabled automatically by the system when you
register them. Here is an example of an extended button component, called ActButton,
with its constructor.

Note how this method call enables mouse events for this new extended component.
Listeners are the objects that handle events fired from sources.

They are all implementations of the EventListener interface or its interface


subclasses. An easy way to know what listener interfaces there are is to remember that
there is one defined for each type of event in the event hierarchy.
There are eleven types of listener interface defined. They include:
ComponentListener
ActionListener

Page 169 Go To INDEX


AdjustmentListener
FocusListener
KeyListener
Other types of listener interface are:
MouseListener
WindowListener
MouseMotionListener
ItemListener
TextListener
ContainerListener
To use a listener interface you must:
Implement a listener interface
Override the relevant methods
Code the event type(s) you want to handle

The listeners represent each event type they handle with a separate method. You
must provide empty methods for the events you wish to ignore. AWT event sources are
usually on-screen GUI components. The types of events an event source supports are
defined by the kind of component it is and by its registered listeners. To handle an event
you must register a listener for that particular GUI component. The registration method
calls are all of the form:
component.addEventTypeListener(eventListener)
For the Component object the following listener registration methods are defined:
addComponentListener

Page 170 Go To INDEX


addFocusListener
addKeyListener
addMouseListener
addMouseMotionListener
Each of these methods takes a listener class or subclass as an argument. Each
low-level listener interface has a corresponding adapter class that implements it.

These adapter classes can be extended quite readily to shortcut the requirement of
having to override all the interface's methods. They are there, in effect, as a convenience
to Java programmers. This example shows how to extend the MouseAdapter to handle a
subset of the possible mouse events.

Moving the mouse over a component causes the foreground color to switch from
black to red and back again when the mouse exits. This handler implements
mouseEntered and mouseExited only, and ignores the other mouse event handling
methods like mouseClicked.

Page 171 Go To INDEX


• Event handling examples
Since an applet is also a component, it is possible to extend an applet to handle its
own events. The first example you will see here shows how to write a simple event
handling applet. This applet consists of a single button, labelled "Switch colors", and a
black background.

You click the button to switch background color from blue to black and back again.
The applet itself, as you will see, implements the mouse listener itself. Here is the applet
code.

You must first remember to import the java.awt.event package, along with any other
relevant packages. The applet, Events0, implements the mouse listener interface itself.
These lines define the button and the background color variable.
You define and instantiate the button and then add it to the applet's display in the
normal way. You then register a mouse listener for the button switchColors. The method
addMouseListener is the method used to register mouse listeners to GUI components.
And you pass the method a reference to the applet, meaning that the applet is registered
as being the mouse listener for this component. The applet will now receive all mouse
events from the button.
The mouseClicked method is an implementation of part of the mouse listener
interface.

Page 172 Go To INDEX


The method simply tests bkgroundColor and switches between black and blue
colors. Because you are implementing the MouseListener interface, you have to provide
empty methods for all other mouse event methods defined in that interface, even if you are
not interested in handling them. This simple example illustrates event handling alongside
application code. One advantage of the new delegation event model in JDK 1.1 is that it
allows you to easily separate the GUI interface from the application code.
The next example illustrates how to create a mouse listener, which separates the
event handling from the applet. This applet consists of a text field and three buttons called
search, reset, and exit.

The user enters some text in the text field, and can then search a database to
produce a listing (not shown). The Reset button will clear the screen and reset the focus to
the beginning of the text field. The Exit button stops execution of the applet. Additionally,
when you pass the mouse pointer over any button its foreground text turns to red, and
when the pointer exits it switches back to black again. HandleMouseEvents is the class,
defined later, that handles mouse events on buttons. The buttonHandler instance of
HandleMouseEvents is declared and instantiated here.

To set up the Search button, you must:


Declare and instantiate the button
Give the button a name (optional)
Add the button to the applet
Register a mouse listener, buttonHandler in this case, for the button

You follow a similar procedure for the Reset and Exit buttons.

Page 173 Go To INDEX


In this example, each button has buttonHandler registered to listen to button
events, but you could have chosen to register another listener with different functionality.
HandleMouseEvents is an extension of MouseAdapter, making it convenient for you to
only override those methods you are interested in.

The source object, a Component, will refer to the source of the mouse events. And
parent is the applet on which the event occurred. This method responds to mouse clicks
on one of the buttons.

You call the getComponent() method, defined in the ComponentEvent class, to


retrieve the source of the event. Then you retrieve the applet in which the source button
was placed. Here you check the source's name to discover which button was clicked. This
is not the only way of handling multiple buttons on a single applet. You could, for example,
have registered a different instance of HandleMouseEvents for each button, and

Page 174 Go To INDEX


instantiated them using a constructor that specified what type of button it was. This would
make HandleMouseEvents capable of handling many more different types of buttons.
This example illustrates how you can extend a component to handle events
occurring on it, in this case buttons.

Here you add three ActButtons, the extended button component, to the applet.
Notice that you do not have to register listeners on these extended components, since
they handle their own events. You extend a button, and there is no need to implement any
of the listener interfaces.

This is the constructor for ActButton, in which you:


Call the super classes constructor in the first line
Enable mouse events
Set the button's name (optional)

Page 175 Go To INDEX


You must override the process MouseEvent method in the extended component. All
mouse events have been enabled in the component's constructor, so you distinguish
between different types of mouse event by getting the event's id with getID(). Most
importantly, you must remember to call the super classes process event method.

6.3. Useful AWT Utilities

• Simple Graphics
Java's Abstract Window Toolkit provides capabilities for drawing on the screen.
These capabilities are provided by a number of classes in the java.awt class hierarchy.
The java.awt classes, derived directly from the Object class, include the following:
Color
Font
Component
Polygon
Graphics
The methods for drawing simple graphical items such as lines, ovals, and
rectangles are contained in the Graphics class. The Graphics class is an abstract class
that models a graphics context. A graphics context is an abstract representation of the
surface that is being drawn on.
Using a graphics context makes life easier for the programmer by hiding the
physical details of the implementation. This means that the graphics routines used for
drawing on screen can also be used for printer output. The abstract nature of the Graphics
class also supports one of Java's key features - platform independence. Each platform
that supports Java implements graphics routines in different ways. In each case a derived
class of Graphics implements the low-level details of the drawing process.
These details are hidden from the programmer who simply uses Java's Graphics
class. Graphical output can be displayed in a number of ways:
In an applet
In an application's frame or dialog box
On a canvas

Page 176 Go To INDEX


All these objects are derived from the Component class. These objects inherit the
Component class methods used to create graphical output. These include the paint
method and the repaint method.
public void paint(Graphics g);
public void repaint();
The paint method takes a Graphics object as an argument, and renders the output
on the appropriate component. The repaint method - which normally takes no argument -
repaints the component. It will result in a call to the update method as soon as it is
possible.
public void update(Graphics g);
Java uses an x-y coordinate system to position objects on the screen. The origin -
that is the (0, 0) coordinate - is located at the top left corner of the screen. Positive x
values are drawn to the right of the origin, and positive y values are drawn below it.
The values are measured in pixels, which are the smallest elements that can be
displayed on screen. To draw a line in a Java program you use the Graphics object's
drawLine method.
public void drawLine(int startX, int startY, int endX, int endY);
This method takes four int parameters: startX, startY, endX, and endY. The first pair
is the coordinates of the line's starting point and the second pair is the coordinates of the
finishing point. Let's use the drawLine method to draw some lines with an applet.

This code draws three lines - two are connected because the finishing point of the
first line coincides with the starting point of the second.
To draw a rectangle in Java you use the Graphics object's drawRect method.
public void drawRect(int top, int left, int width, int height);
The first two parameters specify the location of the top left corner of the rectangle.
The third and fourth parameters specify the width and height respectively. You can use the
fillRect method to draw a filled rectangle.
public void fillRect(int top, int left, int width, int height);

Page 177 Go To INDEX


It takes the same parameters as drawRect, but it fills the rectangle with the current
drawing color. If you want to erase a previously drawn rectangle you can use the
clearRect method.
public void clearRect(int top, int left, int width, int height);
Again this takes the parameters of top and left coordinates, width, and height.
However it draws a rectangle in the background color of the current drawing surface. As
well as drawing regular rectangles, you can use the drawRoundRect method to draw
rounded rectangles.
public void drawRoundRect(int top, int left, int width, int height, int arcWidth,
int arcHeight);
The first four parameters specify the position and size of the bounding rectangle.
This is the area inside which the rounded rectangle is drawn. The arcWidth parameter
specifies how much of the horizontal component of the rectangle will be rounded.
Likewise arcHeight specifies how much of the vertical component is rounded. A
fillRoundRect method is also available, with the same parameters as drawRoundRect.
public void fillRoundRect(int top, int left, int width, int height, int arcWidth, int
arcHeight);
Drawing oval shapes in Java is just as straightforward as drawing rectangles.
public abstract void drawOval(int x, int y, int width, int height);
The drawOval method has four parameters - x, y, width, and height. The first two
parameters specify the top left coordinate of the bounding rectangle that encloses the
oval. If width and height have the same value, a circle is produced. The fillOval method
takes the same parameters as drawOval.
public abstract void fillOval(int x, int y, int width, int height);
The Graphics class uses the drawArc method for drawing an arc, which is a portion
of a circle or oval.
public void drawArc(int x, int y, int width, int height, int startAngle, int
arcAngle);
The drawArc method is similar to the drawOval method, with its first four
parameters specifying the location and size of a bounding rectangle. The startAngle
parameter specifies the point on the oval where the arc begins - zero degrees is the 3
o'clock position.
The arcAngle parameter then gives the angular extent of the arc. The arc is drawn
counterclockwise if arcAngle is positive, while negative angles are drawn in a clockwise
direction. The fillArc method takes the same parameters as the drawArc method, but fills
the space swept by the arc with the current drawing color.
public void fillArc(int x, int y, int width, int height, int startAngle, int
arcAngle);
A polygon is a shape with three or more straight sides. The Graphics class provides
methods for creating polygons. Some of these methods take, as parameters, the
coordinates that define a number of connected lines. But others take a polygon object as a

Page 178 Go To INDEX


parameter - such an object is created by instantiating a Polygon class. The drawPolygon
method draws lines between a number of points.
public abstract void drawPolygon(int xPoints[ ], int yPoints[ ], int
numberOfPoints);
The x-coordinates of these points are specified in the xPoints array, and the y-
coordinates in the yPoints array. The number of points is specified in the numberOfPoints
parameter. If the number of points specified in the numberOfPoints parameter doesn't
match the number of array elements, an error will be generated.
If the first coordinate is different from the last, the polygon is automatically closed
by drawing a line connecting those two points. The fillPolygon method takes the same
parameters as drawPolygon.
public abstract void fillPolygon(int xPoints[ ], int yPoints[ ], int
numberOfPoints);
Let's use these methods to create two polygons.
First the x and y coordinates of the two polygons are assigned to the relevant
arrays. Then the drawPolygon command creates the first polygon. And the fillPolygon
command creates the second polygon, which is filled with the current drawing color. The
drawPolygon and fillPolygon methods can accept a Polygon object as a parameter.

A Polygon object is created with the Polygon constructor.


public Polygon(int xPoints[ ], int yPoints[ ], int numberOfPoints);
This takes similar parameters to the drawPolygon method. However you can
construct a Polygon object that does not contain any points.

Page 179 Go To INDEX


public Polygon( );

• Containers and layout managers


Graphical user interfaces can have a wide variety of components. Text boxes, list
boxes, buttons, and labels are just some of the components that can be found in a typical
GUI. The Java AWT provides classes for most common GUI elements. It also provides
classes for organizing these elements into an effective user interface. The Container class
is the superclass for these organizing classes. It is an abstract class, so it cannot itself be
instantiated.
But two of its derived classes, Window and Panel, play vital roles in constructing a
graphical interface. The Window class provides a top-level window without borders or
menu bar. Window is not often used directly - usually its subclasses Frame and Dialog are
used. The Frame class provides a window with the following features:
Borders
Resizable corners
Menu bar
Title bar
Icon
The Dialog class provides a dialog box window, which is generally used for two
purposes:
Eliciting information from the user
Giving warnings or notices to the user
It is often used in a modal fashion, which means the user must dismiss it before
interacting with any other part of the interface. The Panel class provides a container that
occupies part of an existing window. It is useful for grouping related components - this
enables you to subdivide the interface into discrete areas.
The Applet class is a subclass of Panel. This is why applets are displayed in a
borderless area inside a Web browser's window. Java provides a number of classes to
organize the user interface elements in a logical and user-friendly way. When writing GUI
programs in other languages, it is common practice to specify the positions of user
interface elements in terms of screen coordinates. These coordinates are usually
measured in pixels. Because Java is designed to run on multiple computer platforms, such
an approach does not always guarantee a good result.
This is because different windowing systems will have different fonts, font metrics,
and component sizes. Java's AWT provides a way that helps you create a screen layout
that will be consistent across different platforms. Every container object implements a
LayoutManager interface. This provides a layout manager that rearranges components
within a container whenever it is resized. Java provides the following LayoutManager
classes:
FlowLayout
GridLayout
GridBagLayout

Page 180 Go To INDEX


BorderLayout
CardLayout
Each container or panel can have its own layout manager. It is passed as an
argument to the setLayout method, usually during a program's initialization.

The FlowLayout class provides the simplest means of laying out components.
Components are added to the panel one at a time, building up a row from left to right.
When a component won't fit at the end of a row, it's wrapped to the start of a new row. The
default alignment of the FlowLayout class is centered. However you can change this to a
left or right alignment by passing the constant FlowLayout.LEFT to the FlowLayout
constructor.
setLayout(new FlowLayout(FlowLayout.LEFT));
FlowLayout creates a default gap of five pixels between components. You can
change both the horizontal and vertical gap between components by passing the
appropriate arguments to the FlowLayout constructor. The following line of code specifies
a horizontal gap of ten pixels and a vertical gap of four pixels:
setLayout(new FlowLayout(FlowLayout.CENTER, 10, 4));
The GridLayout class gives you more control than FlowLayout.

Page 181 Go To INDEX


You can specify the number of rows and columns in a rectangular grid layout. In
this example, the buttons are added in sequence - the first three buttons fill the first row.
Then Button4 and Button5 are added to the second row. By default there is no gap
between components arranged with the GridLayout class. However you can specify
horizontal and vertical gaps by passing suitable arguments:
p1.setLayout(new GridLayout(3, 4, 12, 14));
This code creates a grid that can hold up to 12 components in three rows and four
columns. There is a horizontal gap of 12 pixels between components, and a vertical gap of
14 pixels. The GridLayout class is useful when you need to lay out a number of
components of similar size. However when the components are of different sizes,
GridLayout may not give you sufficient control over the end result.
In this case the GridBagLayout class may be more appropriate. GridBagLayout
functions are like GridLayout in using a grid of rows and columns. These rows and
columns do not need to have the same width and height. GridBagLayout places the
components into the grid's cells without any overlap. Each component has a
GridBagConstraints object that specifies how it should be displayed.
The GridBagConstraints class has a number of instance variables such as anchor,
fill, gridheight, gridwidth, and insets. It also has a number of static variables such as
NORTH, EAST, CENTER, and VERTICAL. GridBagLayout uses this GridBagConstraints
information to lay out each component with great precision.
The BorderLayout layout manager can arrange up to five components in a
container.

Page 182 Go To INDEX


The position of the components is specified by one of the following strings passed
to the add method:
North
South
East
West
Center
You must start these strings with an upper-case letter. Within the confines of the
container, the North, South, East, and West components get laid out according to their
preferred sizes. The Center component then gets any space left over.
The CardLayout class manages a set of components in such a fashion that only
one is displayed at any given time.

These components are held in a parent container. You can use methods such as
first, last, next, and previous to select the component to be displayed.

These components can, in turn, be containers that hold other components arranged
with other layout managers. This scheme would be ideal for creating a tabbed dialog box
or set of property sheets.

Page 183 Go To INDEX


• Fonts and metrics
The ability to use different fonts to display text is an important part of a graphical
user interface. Java provides a number of methods and constants for controlling the
display of fonts. Most of these methods and constants belong to the Font class. Java
maintains platform-independence by defining the following set of standard fonts:
Helvetica
TimesRoman
Courier
Dialog
DialogInput
In practice these fonts are mapped to the available platform-specific fonts. For
example, on the Windows platform the Helvetica font is displayed as Arial. The constructor
for the Font class has three parameters:
Font name
Font style
Font point size
public font (string name, int style, int size);
The font name is one of the supported fonts, for example TimesRoman. The font
style is one of the static constants of the Font class, which are Font.PLAIN, Font.ITALIC,
and Font.BOLD.
If a style is not specified, the PLAIN style is displayed. The font size is specified in
points - a point is 1/72 of an inch. If a font size is not specified, the default size is 12
points. The setFont method is used to set the current font.
public void setFont(Font f);
This method takes a Font object as its argument, and is a member of the Graphics
class. Once this method is invoked, all the following text will be displayed in the new font.
The Font class has a number of methods that can be used to retrieve information about
the current font.
The getName method returns the font's name as a string.
public string getName()
The getFamily method returns the font's family name as a string. The name of the
font family is platform-specific.
public string getFamily()
The getStyle method returns an integer value indicating whether the font is plain,
bold, or bold italic.
public int getStyle()
You can also use a method to determine if a particular element of a font's style is
being used. For example, the isBold method returns a boolean value indicating whether
the text is bold.

Page 184 Go To INDEX


public boolean isBold()
public boolean isItalic()
public boolean isPlain()
The Font class's getSize method returns the font's size in points.
public int getSize()
However it is sometimes necessary to have more detailed information on the size
characteristics of a font.
For example, if you were writing a page layout program in Java it would be
necessary to have such detailed information. Java has a class called FontMetrics, which
provides many methods for handling such information. Let's look at the detailed
characteristics of a font. All letters stand on the baseline. The starting position of a string's
baseline is specified by the x and y parameters of the drawString method. The space
taken up by the descenders of lower-case characters is called the descent. The distance
from the baseline to the top of the highest upper-case character is called the ascent.
A further space, called the leading, provides the separation between successive
lines. The height of a font is the sum of the descent, the ascent, and the leading. This is
the same as the distance between the baselines of adjacent lines of text. The following
FontMetrics methods all return their respective values in points:
getAscent
getDescent
getLeading
getHeight
public int getAscent()
public int getDescent()
public int getLeading()
public int getHeight()
These methods can be used in conjunction with the getFontMetrics method of the
Graphics class. For example, to get the ascent of the current font of Graphics object g,
you would use the following code:
int gAscent = g.getFontMetrics().getAscent();
Two FontMetrics methods that are useful for aligning text are stringWidth and
charsWidth. The stringWidth method takes a string parameter and returns the advance
width required to display that string in the current font.
public int stringWidth(string str)
The advance width of a character is the amount by which the current point is moved
from one character to the next in a line of text.
In the context of this function, it means the width of the string when displayed using
the current font. The charsWidth method also returns the advance width required to
display an array of characters.

Page 185 Go To INDEX


public int charsWidth(char data[ ], int off, int len)
The first parameter is an array of characters. The second parameter is an offset to
the first character in the array to be displayed. And the third parameter is the number of
characters to be displayed.

• Customizing colors
Color plays an important role in a good graphical user interface. The ability to
display text, controls, and graphics in color enhances the user interface. When used
effectively, color can make programs more intuitive and easier to use. Most computer
systems use the RGB model to handle the on-screen display of colors. RGB stands for
red, green, and blue, which are the three primary colors, which together produce white
light. Any color can be modeled by specifying its RGB components - this is often called an
RGB triplet.
In many computer graphics systems, each RGB component is specified by a value
between 0 and 255. So, pure red is specified by the RGB triplet (255, 0, 0), while pure
blue is specified by (0, 0, 255). In the additive color model, white is represented by the
presence of all primary colors - so its value is (255, 255, 255).
And black is represented by the absence of all color - (0, 0, 0). This RGB color
model gives a possible maximum of over 16.7 million colors - 256 x 256 x 256. Most
computer graphics systems can't display this many colors, but they will display the nearest
available color instead. The process of displaying an approximate color on a computer
monitor is called dithering. Java supports the RGB color model with the Color class, and
its associated methods and constants.
A Color object represents an RGB color. It is created with the Color class
constructor, which has three variants. You can specify the color as a set of three integers,
each with a value between 0 and 255.
public color(int r, int g, int b)
Alternatively you can specify a set of three floating point values, each between 0.0
and 1.0.
public color(float r, float g, float b)
You can also specify the color with a single 32-bit integer value.
public color(int rgb)
A pure green Color object is created by calling the constructor Color (0, 255, 0).
The same color is created by calling the constructor Color (0.0, 1.0, 0.0). Although Java
uses the RGB color model, it provides support for the alternative HSB model. HSB stands
for Hue, Saturation, and Brightness. Hue indicates the color shade - red, yellow, blue, and
so on. Saturation indicates the intensity of the color. The Color class provides methods for
converting between RGB values and HSB values.

public static int HSBtoRGB(float, float, float)


public static float[ ] RGBtoHSB(int, int, int, float[ ])

Page 186 Go To INDEX


A programmer can treat an RGB color as a set of three integer values, each
between 0 and 255. However Java's internal representation of a color is a single integer of
the form
0xAARRGGBB
RR, GG, and BB stand for the red, green, and blue components, as you would
expect. The AA stands for the alpha component, which represents the transparency of an
image. When you create a Color object, AA is always set to 0xFF, which means fully
opaque. The transparency component can be used in image manipulation. However it is
not used in any of Java's drawing operations, and it can't be manipulated by any of the
Color class methods. The Color class has a number of color constants.

These have the following form:


public final static Color color
The Color class has a number of methods for retrieving the characteristics of a
Color object. For example, the getRed method returns an integer between 0 and 255
representing the red content of the color.
public int getRed()
public int getGreen()
public int getBlue()
And the getRGB method returns a 32-bit integer representing the color in the
default RGB color model.
public int getRGB()
With the getRGB method, bits 24-31 - the alpha component - will contain 0xFF.
Two important color-related methods belong to the Graphics class. The setColor method
sets the current drawing color to the specified color.
public void setColor(Color c)
And the getColor method returns a Color object representing the current drawing
color.
public Color getColor()
Let's use the setColor method to draw text in different colors in an applet. First you
import the relevant classes - Applet, Graphics, and Color.

Page 187 Go To INDEX


The new class will be called Show3Colors. The work of the applet is done in the
paint method, which receives the Graphics object g as a parameter. We want to change
the current color from black - the default - to red. So we create a new Color object,
passing it an RGB triplet of (255, 0, 0) to create a pure red color.
The Color object is then passed to the setColor method, which changes the current
drawing color of the Graphics object g. The line of text is then written with the drawString
method, starting at x coordinate 50 and y coordinate 20. The next line of text will be drawn
in green. Pure green is very vivid and difficult to read on a monitor, so we reduce the
green component to 0.6. In this case floating point parameters are being used, rather than
integers. The line of text is again drawn with drawString, this time with a y coordinate of
40.
For the final line the current color is changed to blue. This time we pass the Color
object's blue constant to setColor.

• Using the clipboard for data transfer


Most graphical user interfaces allow you to copy objects to a system clipboard, and
paste them into an application. Previous versions of Java did not have this copy and paste
functionality. Java 1.1, however, has a clipboard API that enables these operations. The
relevant classes are contained in the java.awt.datatransfer package. The
java.awt.datatransfer package contains three new classes - Clipboard, DataFlavor, and
StringSelection. It provides two interfaces called ClipBoardOwner and Transferable. And it
has an exception called UnsupportedFlavorException. Let's create an applet that will
demonstrate clipboard functionality. This program allows the user to type text into a text
field. A Copy button causes the text to be copied to the clipboard. A Paste button transfers
the text from the clipboard to an internal string and then paints it to the applet surface.
First the necessary classes must be imported, including all those in the
java.awt.datatransfer package.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
Then the applet declaration begins - it is called ClipboardApplet.
public class ClipboardApplet extends Applet

Page 188 Go To INDEX


implements ClipboardOwner, ActionListner {
TextField sourceText;
Button copyButton;
Button pasteButton;
Clipboard clipboard;
String paintText;
public void init () {
clipBoard = getToolkit().getSystemClipboard();
sourceText = new TextField(20);
add(sourceText);
paintText = new String(“No Text yet !”);
copyButton = new Button(“Copy”);
copyButton.SetActionCommand(“Copy”);
copyButton.addActionListener(this);
copyButton = new Button(“Copy”);
add(copyButton);
It implements the ClipboardOwner interface, which defines the interface for classes
that will provide data to the clipboard.
Now we declare variables for the five objects that the applet will use, including the
Clipboard object. The applet initialization is started by getting a handle for the system
clipboard. The text field is created and a variable is initialized with the message "No text
yet!".
The next section of code creates the Copy button, assigning it the name
copyButton. It sets the applet as an action listener. Then it adds the button to the applet.
The code for the Paste button is similar, although it is initially disabled.

The next section of code creates a method called actionPerformed.

This method handles events from the Copy and Paste buttons. If the button clicked
was the Copy button, the text is transferred from the edit control to the clipboard.

Page 189 Go To INDEX


To achieve this we create a StringSelection object. StringSelection is a class which
implements the capability required to transfer a simple Java string in plain text format.
Because there is now data in the clipboard, the Paste button is enabled. If the Paste
button was clicked we use the getContents method.

This method returns a transferable object representing the current contents of the
clipboard. The StringSelection class has a method called getTransferData. This method is
used to transfer the data into a string called clipData. The DataFlavor object represents
the format of the data involved.

In Java 1.1 it has two static variables, stringFlavor and plainTextFlavor. In this
example we are expecting stringFlavor, which represents a Java Unicode String class.
There is a possibility that another program may have written to the clipboard. The
clipboard can accept data in many different formats - it can store graphics files just as
easily as text, for example. If the data is in any format other than stringFlavor an exception
is thrown and an error message is printed. Finally the paint method draws the paint string
on the applet's surface at the specified location.

6.4. Java applications

• Comparing applets and applications


Java's initial impact has been in the development of applets. These are programs,
which are downloaded from either the Internet or a corporate intranet, and execute within
a browser. However Java can also be used to develop stand-alone applications. These
applications reside on the local hard disk, and can execute without a browser. Applets and
applications have many similarities. This is because both are developed using the Java
API. So both applets and applications can benefit from Java's strengths, such as

Page 190 Go To INDEX


multithreading and platform-independence. The differences between applets and
applications arise from the fact that they execute in different environments. All Java
programs execute within a Java Virtual Machine (JVM). In the case of an applet, the JVM
is implemented within the browser. With Java applications, however, the JVM is provided
by the Java interpreter, which must be invoked each time the application runs.
The fact that applets run within a browser has important implications for the user
interface. The browser provides a ready-made interface that the user will normally be quite
familiar with. For example, its File menu contains the Cut, Copy, and Paste menu items for
clipboard operations.
The features of the applet's interface should complement those provided by the
browser itself. Because the browser provides ready-made interface features, the applet
developer has less work to do. However the developer suffers the disadvantage of being
more restricted in terms of interface design. Applets do not usually have menus, for
example, because the browser already has them.
So the developer must provide other means of user input, such as buttons and list
boxes. The developer of a Java application has full control over the user interface. Menus
and dialog boxes - features not normally found in applets - can be used in applications.
This does mean more work for the developer, however. Even the simplest application has
to be displayed inside a Frame object, which has to be explicitly created by the
programmer. Some of the biggest differences between applets and applications are found
in the area of security. Applets, like web pages, are usually downloaded from a remote
computer. But unlike web pages, which are static documents, applets are programs.
This means that if their source is not trusted, it is possible that they may contain
malicious code. Java implements a multilayered security system to prevent malicious
applets causing damage:
Features of the Java language, such as its memory management, make it
difficult to write malicious code
The bytecode is verified when loaded
The browser's security manager places severe restrictions on what the
applet can do
An applet is not normally allowed to perform certain actions that applications
routinely perform. Applets are not allowed to write to or read from the local hard disk. They
can't create directories on the local disk, either. And they are not allowed to check the
details of existing files, such as file size and type. Another major restriction placed on
applets is that they are not allowed to execute native methods.
Dynamic Link Libraries (DLLs) are an example of a library containing native
methods. Native methods are sections of code that are written in another programming
language and compiled for a particular platform. For example, code could be written in
C++ and compiled for the Solaris platform. The most common reason for calling a native
method is the increase in performance. Using native code circumvents many of the
security restrictions that are inherent in Java's design. For example, it is possible to write
to specific memory locations. For this reason the applet's security manager does not
permit the execution of native methods.

Page 191 Go To INDEX


However these methods can be called by Java applications. Another restriction
normally placed on an applet is that it can only make a network connection to the
computer from which it was downloaded. The restrictions on applets are imposed by the
browser's security manager. They only apply to applets that have been downloaded from a
remote server and loaded by the applet class loader.
Certain browsers allow the user to configure the security restrictions on such
applets. If an applet exists on the local disk in a directory specified in the CLASSPATH
environment variable, it is loaded by the file system loader. These applets are not subject
to the security restrictions imposed on applets downloaded from a remote server. Another
area where applets can differ from applications is performance. When an applet is
executing it requires a certain amount of memory. The requirement varies with the
complexity of the applet, but is usually relatively small.
An applet can only run in an external viewer such as a browser. The browser also
requires memory - several megabytes in the case of the most recent browsers. So the
applet inherits the memory overhead of the browser in order to execute. A Java
application runs in conjunction with a Java interpreter. The interpreter's memory overhead
is much smaller than a browser's. This means that an application's performance is often
better than that of a corresponding applet. When deciding whether to develop a program
as an application or as an applet, another important issue is distribution.
There are several advantages to distributing applets over the Internet or a
corporate intranet. The most important is that the most recent version of the applet is
made available to the user. However not all users have access to the Internet or to an
intranet. If a section of the target audience does not have such access, it may be
necessary to develop the program as an application. A program that runs as an
application always contains a method called main.
This method acts as a starting point for the execution of the program by the Java
interpreter. The main method is contained in a class that defines the application and is
named after it. The format of the main method is rigidly defined, and it always contains
certain elements.

The public and static keywords must be present. The return type is always void,
unlike C and C++ programs, which usually return an int. The only parameter is an array of
String objects.
These strings correspond to command line arguments being passed to the
application. Unlike C or C++ programs, the first element of the array args[0] does not
contain the command name. If the application took three arguments, you would use the
following syntax at the command prompt to start it:
java MyApplication arg1 arg2 arg3
There is an important difference between applets and applications in how they
handle initialization and starting. In the case of an applet, the browser automatically calls
both the init method and the start method.

Page 192 Go To INDEX


These methods are not called by the Java interpreter in the case of an application,
so they must be explicitly called in the main method. Another fundamental difference
between applets and applications is their derivation.

Applets are always subclassed from java.applet.Applet. Applications are not


derived from this class - if no superclass is explicitly extended, they are derived from
Object.

• Frames and dialogs


Creating a user interface for a Java application requires more effort than does an
equivalent applet. This is because an applet runs within a browser, which provides a
framework to hold its interface components. The browser also provides interface
components of its own, such as menus, which can be used by the applet.
Java applications need a framework to hold the user interface components. The
java.awt package provides a Container class for holding components. Container is an
abstract class that can't be instantiated, however. Container has a subclass called
Window, but this class does not provide borders or a menu bar. These features are
provided by the Frame class, which is a subclass of Window.
In practice an application's main window is often provided by subclassing
java.awt.Frame. The main method is then included in this subclass.

The Frame class provides many of the interface features that users expect to see in
an application. It has a title bar, which can display a title specified by the setTitle method.
public synchronized void setTitle(string title)
A Frame object can have an associated icon to represent the frame when it's
minimized. The icon is specified by the setIconImage method.
public synchronized void setIconImage(Image image)
Menus play an important role in most applications. The setMenuBar method is used
to associate a particular MenuBar with a Frame. And menu components can be removed
with Frame's remove method.
public synchronized void remove(MenuComponent m)
The MenuComponent class is the superclass of all menu-related components. The
Frame object provides a wide variety of cursors, including the following:
A default cursor
A text cursor

Page 193 Go To INDEX


A wait cursor
A crosshair cursor
A hand cursor
Eight resize cursors

The cursor for a Frame is specified with the setCursor method, and can be
determined with the getCursor method.

These methods are from the Component class, and they use a Cursor object. Most
applications make extensive use of dialog boxes. These are windows, which are generally
borderless and smaller than the main window of the application. Dialog boxes have two
main purposes:
Giving information to the user, especially warnings
Eliciting information from the user
A dialog box can be either modal or modeless.
A modal dialog box does not allow the user to interact with any of the application's
other windows until it is dismissed. The user can, however, interact with other applications.
Modeless dialog boxes do not impose such a restriction, but they are not as widely used.
Java provides the Dialog class to implement dialog boxes. Dialog is a subclass of
Window, so it is also a container. Components such as buttons and labels can be added
to the Dialog object with the add method. The default LayoutManager used by Dialog is
BorderLayout.

Page 194 Go To INDEX


Let's look at one of Dialog's constructors.

The first parameter refers to the parent window of the dialog box. The second
parameter is a string that appears in the box's title bar. The third parameter determines
whether the dialog should be modal or modeless. A true value indicates modal operation.
Let's create a dialog box to warn the user that a file could not be found. We start by
subclassing the Dialog class to create a class called FileWarning.

The current frame will be the parent window, so it is passed to FileWarning's


constructor. This is then passed to the constructor of the superclass, which is Dialog. The
second parameter - "Warning!" - appears in the box's title bar. The third parameter
indicates that the dialog box is modal. Now we can create the components for the dialog
box. These are simply a label containing the warning message, and an OK button to close
the window. We will also use a panel to hold the button. This is because we don't want
BorderLayout to stretch the button across the dialog box. Now we add the components,
using the default layout manager, which is BorderLayout. Dialog boxes don't have a
default size so we specify the dimensions with the resize method.
Finally we use the show method to display the dialog box. Java provides a useful
class called FileDialog for handling files. FileDialog is derived from Dialog, and can be
used to create both "Open File" and "Save As" dialog boxes. The constructor takes an
argument called mode, which specifies which type of dialog to create.

The value of mode is an integer specified by the constants FileDialog.LOAD and


FileDialog.SAVE.

Page 195 Go To INDEX


You can specify a FilenameFilter object to control which files are displayed by
FileDialog.

FilenameFilter is an interface that is part of the java.io package. The appearance of


the dialog box created by FileDialog depends on the windowing system being used. So an
"Open File" dialog box on a Windows NT machine will look different from one on a
machine using Solaris. However their functionality will be the same in both cases.

• Menus
Menus play a vital role in most GUI applications. They provide a lot of functionality
without taking up large amounts of screen space in the user interface. And, when well
organized, menus are easier to use than a large number of components such as buttons
and checkboxes. A menu consists of one or more menu items. When a menu is clicked, it
expands to show a listing of its menu items. When a menu item is clicked, an event is
generated that causes the application to perform some action.
Menus are usually grouped together in a menu bar, often located at the top of an
application's window. However another type of menu is sometimes used which can appear
anywhere within the window. This is called a popup menu - it usually appears at the same
location as the cursor. Java provides a number of related classes for implementing menus.
In the class hierarchy MenuComponent is the superclass of all menu-related classes.
MenuItem, which is derived from MenuComponent, has the methods required to manage
menu items.
In the Java 1.1 event delegation system, a MenuItem object acts as an event
source. MenuItem has a method called addActionListener. This method registers a
specified listener to receive action events from the menu item. MenuBar, which is also
derived from MenuComponent, is the class that acts as a container for menus.
The Menu class is derived from MenuItem - it defines a pulldown menu. This
means that a menu can itself be a menu item, enabling the use of submenus. A popup
menu is defined by the PopupMenu class, which is a subclass of Menu. PopupMenu is a
feature of Java 1.1, and was not available in earlier releases.
Another menu-related class is CheckboxMenuItem, which is derived from
MenuItem. This class defines a particular type of menu item that can be toggled between
two states - checked and unchecked. Let's create a menu system for a simple paint
program. This system will have the following menus:
A Color menu for selecting the paint color
A Brush menu for selecting the brush type
You first create the menu bar to hold the menus with the MenuBar constructor.

Then you create the Color menu with the Menu constructor.

The String passed to the constructor is the menu name. Now you create menu
items and add them to the menu.

Page 196 Go To INDEX


In this case, you use the MenuItem constructor to create menu item objects. Then
they are added to the menu with the Menu method add. Alternatively you can add an item
name as follows:
colorMenu.add("Black");
In this case, the method accepts a String rather than a MenuItem object. The Brush
menu is created in a similar fashion.

Now you can add the menus to the menu bar.

This is done with the MenuBar object's add method. The menu bar is now attached
to the application's Frame with the setMenuBar method.

The appearance of menus is often improved by adding a separator bar between


groups of menu items. This is done by passing a hyphen to the MenuItem constructor.

Alternatively you can use the Menu class's addSeparator method.


AddSeparator();
Separator bars do not generate any events when they are clicked. Some menu
items can be toggled between two states. In your paint application, you may want to add
an airbrush effect, which can be switched on or off. You use the CheckboxMenuItem class
for this purpose.

The state of the checkbox menu item can be either true or false. When it is true, the
menu item will have a checkmark beside it. The state can be determined with
CheckboxMenuItem's getState method.

Submenus are a very useful way to enhance menu structure. Let's change the
Brush menu to incorporate a submenu for brush width. First you create a new menu called
Width.

Then you add the three menu items - Thin, Medium, and Thick.

Page 197 Go To INDEX


Now when you create the Brush menu, you simply add the Width menu to it.

This makes Width the first menu item on the menu. When it's clicked, the Width
menu opens.

• Running an applet as an application


The principal difference between an applet and an application is the environment in
which the program runs. A Java applet runs inside a Java-enabled browser or the applet
viewer provided in the JDK.
A Java application is run by the Java interpreter. Let's take a Java applet and
enable it to work as a standalone application. It will still be able to function as an applet if
loaded by a browser. The applet you will use is a very simple one.

All it does is print the following message to the screen: Runs as an applet!
Java programs start by importing all necessary classes. You will need more AWT
classes than simply Graphics, so you import all of its classes. The next line starts the
declaration of the new class, which you call Application. Because you still want the
program to function as an applet, it is derived from Applet.
If you did not have this requirement you would extend it from another class - Frame
would be the obvious choice here.

Now you declare a variable called StandAlone. StandAlone will be set to true when
the program is running as an application. Now you come to a crucial part of this program.
The main method acts as the applet's entry point when it is running as a standalone
application. All applications must have a main method with this format. This method is
ignored if the applet is running within a browser.

A graphical application has to be displayed inside some kind of framework. So you


create a Frame object and give it the title Application.

Page 198 Go To INDEX


You want the display area of the program to be a certain size - 320 pixels
horizontally and 240 pixels vertically.

Java programs can run on computers with different windowing systems. So you can
not be certain of the size of borders and title bars at design time. You use the getInsets
method to determine these values at run time. The frame is briefly made visible so that
getInsets will return valid values. The next section of code starts the applet running within
the frame window.

The StandAlone flag is set to true as the program is now running as an application.
Immediately after the application is initialized the frame is made visible. The next section
of code is the Application class constructor.

This is followed by code that initializes the size of the applet.

The final code section in our program is the paint handler. This writes a string to the
screen with the drawString method.

Page 199 Go To INDEX


7
Features of Java
7.1. Java packages

• String handling utilities


Java does not have a built-in string type. However, the java.lang standard library
contains a predefined String class. In C, operations on strings occur on character arrays.
But in Java they occur through class methods. In Java, String objects are constant so their
values cannot be changed after they are created. Instead you apply methods to them in
order to create new String objects. The String class is best used for string constants -
strings that are not going to change after they are created. Fixed, immutable strings can
be implemented more efficiently than changeable strings. However, you are not wholly
restricted to using fixed strings.
The StringBuffer class is used for strings that need to be modified after they have
been created. To create a string you can explicitly instantiate an object of the String class.

You can also declare a variable, which references a String object and then set its
value later in another part of your program.

The declaration for an empty string is also straightforward.


string a = “”;
There are in fact nine constructors that you can use to explicitly create a String
object.
string ()
string (byte [ ])
string (byte [ ], ByteToCharConverter)
string (byte [ ], int, int)
string (byte [ ], int, int, ByteToCharConverter)
string (char [ ])
string (char [ ], int, int)
string (string)
string (StringBuffer)
In Java you can use the plus (+) sign to join two strings together. This operation is
known as concatenation. In this example, the string variable fullname will contain "Cheryl

Page 200 Go To INDEX


Wong" but note that you need to have a space in one of the strings if you want the name
stored in the correct format.

The + sign joins the two strings together exactly as they are given. The string
fullname would then contain "Cheryl Wong". You can use the concatenation operator
many times in a single line:
String somestring = "This " + "is " + "a string";
You could also use the concat method. It concatenates the specified string to the
end of another string and returns a new String object representing the concatenation.
Another method that can be used to manipulate String objects is replace(). This method
takes two characters and replaces all occurrences in a string of the first character with the
second character. In this example, secondstring contains "PICK A OTRING, ANY
OTRING", because the call to replace() requests that every occurrence of an "S" be
replaced with an "O".

Note that firststring remains unchanged and that secondstring is a new String
object. Another useful string handling utility is the ability to extract a substring from another
string. To do this you make a call to the substring method of the String class. This let's you
create a new string object out of a larger string.

In this example, the new string object 'a' equals "Chery". Java assigns position 0 to
the first character in a string. The first argument of substring is the position in the string of
the first letter that you want to be part of the new substring.
The second argument is the stopping position. The substring returned will contain
all the characters from the starting position up to but not including the stopping position.
So in this example the characters starting with position 0 ("C") will be copied but the
copying will stop when the character at position 5 ("l") is reached.
You can also find out the length of a given string. You do this by calling the length
method of the String class.

The method that Java uses to count the position of characters in a string makes it
easier for you to find out how long a substring is. The string a.substring(x,y) always has y-
x characters. You can also find out whether a string starts with a certain prefix.
Just call the startsWith method. Here, the boolean variable result is equal to true.

Page 201 Go To INDEX


This is because the string somestring does start with "This". A similar method is
endsWith(). This method determines whether the string object ends with a given set of
characters. In this example, result is equal to true.

If you want to find the location of the first occurrence of a character within a string,
use the indexOf method. In this example, index is equal to 3, which is the index of the first
"s" in the string.

To find the location of subsequent characters you can use a slightly different
version of indexOf(). In the example you're looking for the next occurrence of "s". By
including the index+1 as the method's second argument, you're telling Java to start
searching at index 4 in the string (the old value of index, plus 1).

This results in index becoming equal to 6, which is the location of the second
occurrence of "s" in the string. One of the most important aspects of dealing with strings is
the ability to compare them. In Java you can use the equals method to test strings for
equality. You should never use the == operator to test for equality between strings in Java.
This is because Java does not always arrange for equal strings to be shared. In this case,
equals will return true if the string called somestring is the same as the string called
anotherstring.

You can use string variables or string constants as the arguments to equals.

The equalsIgnoreCase method compares two strings without regard for uppercase
or lowercase letters. If you want to know more than just whether or not the strings are
equal, you can call upon the compareTo method. The compareTo method returns a value:
Less than zero when the String object on which the method is invoked is
lessthan the string argument
Zero when the strings are equal

Page 202 Go To INDEX


Greater than zero if the String object on which the method is invoked
isgreater than the String argument
The regionMatches method enables you to compare part of one string with part of
another. The regionMatches method's four arguments are:
Where to start looking in the String object on which the method is invoked
The string to compare with
The location in the comparison string at which to start looking
The number of characters to compare
In the example, the boolean result will be true.

The first letter to be compared in the main string is the character in position 10
which is S. The location in the second string is the letter in the second position which is S.
The next six characters in each are compared and are equal - "S, T, R, I, N, G".
Remember that String objects are immutable. That is, you cannot change the individual
characters in the string. The string "Cheryl" will always contain the sequence of characters
"C", "h", "e", "r", "y", "l" and they cannot be changed.

You could however change the contents of the string variable firstname by making
it refer to a different string. You could modify the firstname string by taking the substring
you want to keep and concatenating the characters you want to insert.

This changes the value of the firstname variable to "Cherub". Note that the new
string had the same number of characters as the original string had. You could however
have changed the firstname variable to hold a string larger or smaller than the original
one.

The firstname variable can just as easily be changed to contain the strings
"Chernobyl" and "Cher". Because String objects are immutable, Java allows the compiler
to arrange the sharing of strings. Strings sit on the memory heap and variables of type
String reference locations on the heap. So in reality the substring firstname.substring (0, 4)
is just a reference to the existing "Cheryl" string. The range of characters used in the
substring are stored with the reference. You can use a method called trim() to remove
both leading and trailing whitespace characters.

Page 203 Go To INDEX


Examples of whitespace characters are spaces, tabs, carriage returns, and
linefeeds.

• Math Methods
The java.lang standard class library also has a class, which provides math
operations. This class is called java.lang.math. It provides many useful methods, from
simple minimum and maximum to logarithm and trigonometry. Two of the most familiar
math methods are those that return the minimum and maximum values of a group of
numbers. There are four versions of min() and max() depending on the type of numbers
you are using. A math method that operates on a number in Java might have to deal with
each of Java's basic types - int, long, float, and double.
Many of the methods in the Math class are overloaded to work on different types of
numbers. The declarations for both the min and max methods are straightforward.

They take two parameters, which represent the numbers that you want to compare.
In this case the method will find which of two integers, a and b, is the largest.
The absolute value method abs() returns the absolute value of a number. The
absolute value of a negative number is the corresponding positive number. The absolute
value of a positive number is itself. So the absolute value of -7 is 7 and the absolute value
of 7 is also 7.
abs()
-x = x
x=x
The declarations for abs() are similar for the four different types of numbers. Often
you will want to generate random numbers in some part of your program. Java provides a
facility for doing this.
The random method of the Math class generates a random number in the range 0.0
to 1.0. You can generate a random number between 0 and 10 quite easily.

Page 204 Go To INDEX


Or you could generate a random number between 1 and 100.

Math also contains a number of methods for rounding numbers. For instance, the
round method takes a float number and rounds it to an integer value.
public static int round(float a)
This code rounds to the closest whole number, which means that 9.4 gets rounded
to 9, but 9.6 gets rounded to 10. You can also round a double to a long value.
public static long round(double a)
The rint method rounds to the closest whole number.
public static double rint(double a)
The ceil and floor methods are also particularly useful. If you want to find the next
whole number greater than or equal to a double you use ceil().
public static double ceil(double a)
The ceil method takes its name from ceiling. The floor method gives you the "floor"
or largest whole number less than or equal to a double.
Trigonometric methods are provided for by the methods sin(), cos(), and tan().
The logarithm of a double can be found by calling the log method. It takes a double
argument and returns the natural logarithm (base e) of it.
The pow method takes two doubles and returns the first number raised to the
power of the second.
The ability to get the square root of a number is very useful in programming. The
sqrt method in the Math class provides this function.
public static double sqrt(double a)
Version 1.1 of the JDK contains the java.math package, which contains the classes
BigIntegers and BigDecimals. BigIntegers are immutable arbitrary-precision integers,
which provide analogs to all of Java's primitive integer operators, and all relevant static
methods from "java.lang.math".
BigIntegers provide other operations for modular arithmetic, primality testing, prime
generation, and single-bit manipulation. BigDecimals are immutable, arbitrary-precision
signed decimal numbers, suitable for monetary calculations. BigDecimals provide
operations for basic arithmetic, comparison, scale manipulation, format conversion, and
hashing.

• Streams and I/O


At the most basic level all computer programs receive input and transform it to
generate output. Streams are little more than the flows of data in this process. An input
stream could contain data entered by a user through a keyboard and an output stream
could be the flow of data to a printer. The Java class libraries provide you with a vast
number of classes that give you the ability to read and write data in your programs.

Page 205 Go To INDEX


The System class of the java.lang package contains the standard input and output
stream objects. You can use these in your programs without having to create your own
stream objects. The system.in class variable enables your programs to read data from the
keyboard and is a reference to an InputStream class.
The system.out class variable is a reference to the PrintStream class and routes
output to the computer's screen. You can use these stream objects directly in order to
handle standard input and output in your Java programs. In Java, all streams are
represented by classes. The simplest of these classes represent basic input and output
streams that provide general streaming abilities.
From the basic classes, Java derives other classes that are more specifically
oriented toward a particular type of input or output. The java.io package provides classes
for basic input and output, as well as file handling and inter-thread communications. All of
Java's I/O is based on the classes InputStream or OutputStream. Because InputStream
and OutputStream are abstract classes, you cannot use them directly. InputStream is an
abstract class representing an input stream of bytes.
OutputStream is an abstract class representing an output stream of bytes.
InputStream defines nine methods that provide the basic functionality common to all input
stream classes. These are:
available()
close()
mark(int)
markSupported()
read()
read(byte)
read(byte,int,int)
reset()
skip(long)
The available method returns the number of bytes that can be read without
blocking. It also throws an IOException.
public abstract int available () throws IOException
The close method closes the input stream.
public void close () throws IOException
It must be called to release any resources associated with the stream. It throws an
IOException. The mark method marks the current position in the input stream.
public synchronized void mark (int readlimit)
If a subsequent call is made to reset(), the stream will be repositioned at the last
marked position so that subsequent reads will re-read the same bytes. The stream allows
readlimit bytes to be read before the mark position becomes invalidated.
The markSupported method returns a boolean value indicating whether or not the
stream type supports mark/reset.

Page 206 Go To INDEX


public boolean markSupported ()
The boolean value will be true if the stream type supports mark/reset and false
otherwise. The read method is overloaded and is an abstract method.
public abstract int read () throws IOException
There are three different read methods for reading from a stream.

The first version of read() reads one byte and returns the byte read. If it encounters
the end of the input source it returns -1. The second version of the read method reads
multiple bytes into a byte array. It returns the number of bytes actually read. The third
version also reads data into a byte array, but enables you to specify an offset position
(offset) in the array at which to start storing characters. It also indicates the maximum
number of bytes to read (length). The concrete subclasses of InputStream implement the
read method. For instance, the FileInputStream class defines the read method to read a
byte from a file.
The reset method repositions the stream to the last marked position.
public synchronized void reset () throws IOException
If the stream has not been marked, or if the mark has been invalidated, it throws an
IOException.
The skip method skips x bytes of input. It throws an IOException.
public long skip (long x) throws IOException
The OutputStream class is the counterpart of InputStream. It provides the basic
functionality for all output streams. The methods associated with the class are as follows:
close()
flush()
write(byte[])
write(byte[], int, int)
write(int)
The close method closes the stream.
public void close () throws IOException
In order to release any resources associated with the stream, this method must be
called. It throws an IOException.
The flush method flushes the stream.
public void flush () throws IOException
It will write any buffered output bytes. It throws an IOException. OutputStream's
write method is also overloaded.

Page 207 Go To INDEX


The first version of write() is defined as abstract and it writes one byte to an output
file.
public abstract void write (int buffer) throws IOException
The second version writes all the bytes contained in the given byte array.
public void write (byte buffer[ ]) throws IOException
The third version allows your program to write data from a byte array, specifying a
starting offset position (offset) for the write and the number of bytes to write (length).
public void write (byte buffer[ ], int offset, int length) throws IOException
Both read() and write() can block a thread while waiting for the byte to be read or
written. For example, if a network connection is busy there could be a problem reading or
writing the byte.
In that case the thread in which the call happens is suspended. This allows other
threads to operate effectively while the method waits for the stream to become operable.
Streams utilize operating system resources so it is wise to monitor their usage. Both
InputStream and OutputStream have a close method that can be used to shut off a stream
when you are finished reading or writing to it. When you close an output stream you also
flush the output stream.
This clears the stream of any data that has been temporarily placed in a buffer
before transmission. Buffered data may not be transmitted unless you close the file or
explicitly call the flush method. A call to the flush method flushes the stream explicitly. The
Java libraries give you a choice of dozens of stream types. Streams are often used for
retrieving data from the keyboard and displaying it on screen. File I/O is another
fundamental part of any computer system. Java provides several classes for reading from
and writing to files. When an applet is downloaded it is unable to access the file system of
the computer. This is an important security measure. However, a standalone application
usually needs to access the file handling resources of the system it is being run on.
If your file-reading needs are relatively simple, you can use the FileInputStream
class in the java.io package. This is a simple input-stream class derived from InputStream.
It implements many of the abstract methods defined in the InputStream class. However, it
does not implement mark() or reset(). There are three constructors for initializing an object
from the FileInputStream class.

The first constructor, FileInputStream(File), creates an input file from the specified
File object. The second constructor, FileInputStream(FileDescriptor), creates the object
from a FileDescriptor object. The third constructor, FileInputStream(String), creates an
input file with the specified system-dependent filename. The counterpart to the

Page 208 Go To INDEX


FileInputStream class is FileOutputStream. This class provides basic file-writing
capabilities.
There are four constructors for the FileOutputStream class.

The first constructor, FileOutputStream(File), creates an output file with the


specified File object. The second constructor, FileOutputStream(FileDescriptor), creates
the object from a FileDescriptor object.
The third constructor, FileOutputStream(String), creates an output file with the
specified system-dependent file name. The fourth constructor, FileOutputStream(String,
boolean), creates an output file with the specified system-dependent file name. Practically
everything you want to do with a file can be done using the RandomAccessFile stream
class. It is one of the few stream classes not derived from InputStream or OutputStream. A
random access file is one, which allows information stored in it to be accessed at random
positions, rather than in the sequential order of the data in the file.
There are two constructors for initializing objects from this class. The first
constructor, RandomAccessFile(File, String), creates a RandomAccessFile from a
specified File object. The second parameter specifies the mode - "r" for read and "rw" for
read/write. Calling the second constructor, RandomAccessFile(String, String), will create a
RandomAccessFile with the specified system dependent filename and the specified mode.
There are over 30 methods with which you can manipulate the file once your
RandomAccessFile object has been created. A random access file has a file pointer
setting also. This indicator always points at the position of the next byte that will be read or
written. The getFilePointer method returns the current position of the file pointer. The seek
method sets the file pointer to a specified byte position within the file.

• Collections
The java.util package provides several utility classes that give improved
functionality to the Java run-time environment. The java.util package defines a number of
container objects, that is, objects that contain or hold other objects. Some classes provide
you with the ability to store a collection of objects without knowing ahead of time how
many objects you want to store.
Some also allow you to associate one object with another. The Vector class is a
powerful alternative to conventional arrays. Vectors are array-like objects that can grow or
shrink to meet storage requirements. This is more flexible than an array, which has a fixed
length. Vectors can only hold references to objects. When you create a vector, you can
specify how big it should be initially, and how fast it should grow. The Vector class has
three constructors.

Page 209 Go To INDEX


The first constructor, public Vector(), creates an empty vector with an initial capacity
of the default size 10. The second one, public Vector(int initialCapacity), creates a vector
with space for initialCapacity elements. The third one, public Vector(int initialCapacity, int
capacityIncrement), creates a vector with space for initialCapacity elements and a
specified capacity by which the vector will increment when it is full and needs to store
another element. Suppose you create a vector that has the capacity for four items and you
fill it with four items.
Then you want to add a fifth item. The vector will relocate and resize itself to do
this. By default the vector allocation will double each time it relocates. There are two ways
to add new objects to a vector. You can add an object as the last element in the vector, or
you can insert an object in between two existing objects.
Accessing elements in a vector is similar to accessing array elements. You use the
elementAt method to access vector elements.
someVector.elementAt(4)
You might want to use a vector to build up a container of objects initially, but then
convert the vector into an array for maximum efficiency. You usually do this only after you
have all the objects you need. For instance, if you are reading objects from a file that can
contain any number of objects, you store the objects in a vector.
When you have finished reading the file, you create an array of objects and copy
them out of the vector. Java also has a BitSet class from which you can create bitsets. A
bitset is really a vector of bits. It is used if you want to efficiently store a whole lot of two-
state (i.e. binary) information. Because a bitset collects the bits into bytes, it is far more
economical in terms of memory than using a vector of boolean objects. The java.util
package also contains a Stack class. The Stack class is derived from Vector. A stack
contains objects and is manipulated in a "last in, first out" (LIFO) manner. So when you
take an element from a stack it is always the most recently added element. To add an
object to the top of the stack, you push it onto the stack.
public Object push(Object newItem)
The pop method removes the top object from the stack.
public synchronized Object pop()
The Dictionary class is an abstract class that provides methods for associating one
object with another.
Dictionaries are often used to associate a name with an object and retrieve the
object based on that name. In a dictionary, the name object is called a key, and it can be
any kind of object. The object associated with the key is called the value. A key can be
associated with only one value, but a value can have more than one key. You use the put
method to store an object in a dictionary with a specific key.
public abstract Object put(Object key, Object Value)

Page 210 Go To INDEX


The get method lets you retrieve objects from a dictionary.
public abstract Object get(Object key)
The Hashtable class is an implementation of the Dictionary class that uses the hash
codes of the key objects to perform the lookup. It collects keys into "buckets" based on
their hash code. Searching a hash table is efficient because only elements that hash into
the same bucket are searched.
Firstly, the key's hash code is computed. Next, the hash code is used to get the
correct bucket. Finally, the bucket is searched for the correct key.

7.2. Threads and Synchronization

• Introduction to multithreading
When they're running on your computer, programs sometimes execute using
separate "threads". Each of these threads can be viewed as a piece of work that the CPU
must carry out. Threads are sometimes called "lightweight processes". Like processes,
they can be executed independently. But threads don't generate the same level of
overheads as processes. In a single-threaded system, programs are restricted to carrying
out one task at a time. Each thread must finish its activity before another thread can begin.
But very often, important operations within a program are designed to occur
simultaneously.
For example, your computer may want to download a file, update a screen, and
respond to user input at the same time. For this reason, single threading can be restrictive.
The ability to run more than one program thread at a time is called multithreading. Java
has a built-in multithreading capability, unlike most other programming languages. This
means that Java threads can execute concurrently.
Writing multithreaded programs can be tricky. But as you can see, they give Java
programs a powerful advantage over single-threaded languages, such as C and C++.
Both C and C++ are capable of multithreading on certain platforms. However, their
multithreading capabilities are much less sophisticated than those of Java. Each thread
has a distinct life cycle, during which it passes through a number of states. Most of these
states don't require complete control of the CPU.
A newly created thread is said to be in a "born" state. Threads remain in this state
until their start method is called. Once the start method is called, the thread enters the
"ready" state. When a system assigns a CPU to a thread and that thread begins
executing, it is described as being in a "running" state. If a running thread issues an
input/output request, it enters a "blocked" state. A blocked thread must wait for some input
or output to complete before it can continue.
In a single-threaded system, the entire program must pause until the I/O process
completes. In Java, the blocked thread is the only one that pauses. All other threads can
continue running. A running thread enters a "sleeping" state when a sleep method is
called. This thread automatically returns to a ready state as soon as the designated sleep
time expires. A thread's activity can be temporarily "suspended" by calling the suspend
method. A suspended thread becomes a ready thread when its resume method is called
by another thread.

Page 211 Go To INDEX


Blocked, sleeping, and suspended threads cannot use a CPU, even if one becomes
available. When a running thread calls the wait method, that thread enters a "waiting"
state. A waiting thread will resume running when the notify method is called. A thread
enters the "dead" state when its run method completes or when its stop method is called.
The stop message sends a ThreadDeath object to the thread. ThreadDeath is a
subclass of the class Error. Once stopped, a dead thread cannot be restarted. This thread
will eventually be disposed of by the system. A good example of Java's multithreading
capability is the process of garbage collection. Remember, garbage collection describes
the process of reclaiming dynamically allocated memory when it is no longer being used.
In C and C++, programmers must explicitly dispose of dynamically allocated
memory. However, in Java, this process runs as an implicit, "low priority" thread in the
background. This means that this thread runs when the CPU is idle. This means that it
doesn't use valuable processing time, or cause higher priority threads to wait.

• Priorities and daemons


A CPU can execute instructions from only a single thread at a time. But Java
programs often contain several ready threads. To coordinate thread execution, you assign
a priority to each thread. Thread priorities range between Thread.MIN_PRIORITY and
Thread.MAX_PRIORITY. In current Java implementations, Thread.MIN_PRIORITY is
defined as a constant with value 1 and Thread.MAX_PRIORITY is defined as a constant
with value 10. As an absolute value, a thread priority is meaningless. A thread of priority 9
doesn't run any faster than a thread of priority 1, if it is the only running thread. By default,
each thread is given a priority of Thread.NORM_PRIORITY, which is currently defined as
a constant with value 5.
Java provides an internal scheduler to ensure that higher priority threads receive
more CPU time than lower priority threads. A running thread is automatically pre-empted
by a higher priority thread. Alternately, a running thread can voluntarily relinquish control
to another thread by yielding, sleeping, or blocking. In some cases, several threads of
equal priority may compete for CPU time.
The way these threads are treated depends on whether your Java run-time system
implements timeslicing. In timeslicing systems, each thread receives a limited amount of
time - called a quantum - to execute on a CPU. When a quantum expires, the CPU is
taken away from that thread - even if the thread hasn't finished executing. The Java
scheduler makes this thread wait while all other threads of equal priority get their chances
to use their quantum in rotation. When all the other threads have had a chance to run, the
scheduler lets the original thread resume its execution. Depending on the way timeslicing
is implemented by your system, threads of a given priority may have to run to completion
before that thread's peers get a chance to execute.
A running thread will be interrupted only if a higher priority thread becomes ready to
run. You can't be sure how the system on which your program is running will implement
timeslicing. So it's good policy to periodically call the yield method. This gives each thread
of equal priority the chance to run. This program illustrates some basic threading
techniques.

Page 212 Go To INDEX


You can see that two classes have been defined - ThreadApp2 and SimpleThread.
Class ThreadApp2's main method instantiates four instances of SimpleThread.
The program launches the execution of four threads by calling the Thread class
start method. This places the threads in a ready state. Class SimpleThread is derived from
the class Thread.

Page 213 Go To INDEX


It consists of:
The instance variable MyID
A constructor
A run method
The run method is automatically called by the start method. It contains the main
body of code to be executed by a thread. You can set or change a thread's priority using
the setPriority method. This method takes an int argument. If the argument is not in the
range Thread.MIN_PRIORITY (1) to Thread.MAX_PRIORITY (10), then this method
throws an IllegalArgumentException. In this program, the priority of threads t1 and t2 is set
to 4. And the priority of threads t3 and t4 is set to 2. If you want to find out the priority
value assigned to a given thread, you use the getPriority method.
You can see that the priority value for each running thread is displayed in the
program output.

Page 214 Go To INDEX


The output of this program may vary from one system to another. Two important
methods have been used in this program:
Join
Yield
Using the join method, you force the main method to wait for threads t1, t2, t3, and
t4 to finish before it can proceed. If the main thread finished first, the child threads would
immediately be terminated, even though they may not have completed their task. The
yield method is a static method that forces a running thread to yield a CPU to its peers
after a preset time. As you can see, threads of equal priority, like t1 and t2, yield to one
another until one or both complete. Remember, this output may vary slightly from one
system to another. When the last running thread completes, the program generates this
statement. The yield method is unnecessary in a fully timeslicing system because threads
of equal priority will automatically execute for their quantum in rotation.
A daemon thread is a low priority thread that runs in the background for the benefit
of other threads. A garbage collector thread is an example of a daemon thread because a
program will terminate if the garbage collector thread (and/or other daemon threads) are
the only remaining threads. You designate a daemon thread with this method call.
SetDaemom(true)
An argument of false means that the thread is not a daemon thread. If a daemon
thread is not set to daemon before its start method is called, an
IllegalThreadStateException is thrown. Similarly, the method isDaemon returns true if a
thread is a daemon thread, and false if it is not.
final boolean isDaemon()

Page 215 Go To INDEX


Programs typically include a mixture of daemon and non-daemon threads. Non-
daemon threads are conventional, user threads. When only daemon threads remain in a
program, the Java program quits.

• Synchronization, wait, and notify


Sometimes two or more program threads need concurrent access to a shared data
resource. For example, in this program, the transaction threads t1 and t2 are executing
concurrently.

Both threads use the incBalance method to increment the instance variable
balance.

In order for this program to work, the balance variable must be incremented twice.
But as you can see from the program output, balance has been incremented only once.

These threads must be coordinated so that only one thread can increment balance
at a time. To do this, you use synchronized methods, and you coordinate these methods
by using "monitors". A monitor is an object that acts as a mutually exclusive lock, or
mutex. Every object that contains a synchronized method acts as a monitor. As soon as a
synchronized method is called, the thread that executes that method is said to "own" the
monitor. Since only one thread can own a monitor, no other threads will be able to call a

Page 216 Go To INDEX


synchronized method on that object. Here the incBalance method has been altered to
include the keyword synchronized.

This ensures that only one synchronized thread can execute the synchronized
incBalance method at any given time.
When the synchronized method finishes executing, the lock on the object is
released, and the next thread is allowed to proceed. If several threads are waiting to act
on the same object, the highest priority ready thread is allowed to proceed.
You can see from this output that by synchronizing the incBalance method, t1 was
able to increment balance before t2.

Sometimes a thread executing in a synchronized method will determine that it


cannot immediately proceed. In this piece of code, the print method can print a character
only when the register buffer has been filled.
Suppose the print thread controls the monitor. The register must contain a
character in order for the print thread to complete. If the register buffer is not full, the print
thread voluntarily calls the wait method. The wait method instructs the running thread to
give up the monitor. The print thread will wait in a queue while other threads try to run.
This allows the fill thread to execute its synchronized method and read a character into the
buffer. When the fill thread completes, it releases its lock on the monitor and uses the
notify method to wake up the waiting print thread. The notify method acts as a signal to the
waiting thread that the condition the waiting thread was waiting for has been fulfilled. The
print thread will now attempt to obtain a lock on the monitor object and execute again.
This output illustrates the synchronized behavior between the threads executing the
print and fill methods.

Page 217 Go To INDEX


If several threads have called the wait method on the same object, you can wake
them all by using the notifyAll method.
All the threads waiting for the object become eligible to re-enter the monitor. Since
only one of these threads can obtain a lock on the object at a time, the highest priority
thread that wakes up will be the first to run.
Any threads waiting for a monitor object must be wakened explicitly with the notify
keyword, or they will wait indefinitely. So every call to wait, must have a corresponding call
to notify that will eventually end the waiting. The wait, notify and notifyAll methods are
implemented as final methods in the root class Object, so all classes inherit them.

• The Runnable Interface


Suppose you want to create a class that can make use of threads.

Page 218 Go To INDEX


One way to do this is by extending the class Thread.

All classes derived from Thread can support multithreading. The Thread class
defines four default methods:
Init

Page 219 Go To INDEX


Run
Start
Stop
These methods are automatically inherited by any classes derived from Thread.
The only problem with extending classes from Thread is that it creates some unusual
relationships. In Java, each class can only be derived from a single superclass. By
extending the Thread class, you make your multithreaded class a subclass of the Thread
superclass.
You can avoid the problem of deriving classes from Thread by implementing a
special interface called Runnable. Remember, an interface is a type of abstract class. The
Runnable interface is a simple interface that defines an abstract run method. Java classes
can implement one or more interfaces without disrupting their superclass. So by
implementing Runnable, existing classes can support multithreading without having to
change their superclass to Thread. In fact, the Thread class itself implements the
Runnable interface. As you can see, this applet implements the Runnable interface.

The code that controls the threads is placed in the run method. Unlike the Thread
class, the methods init, start, run, and stop are not implicitly defined in the Runnable
interface. If a class implements Runnable, these methods must be defined explicitly.

Page 220 Go To INDEX


7.3. Internationalization

• Internationalizing programs
The Internet is a global resource, incorporating every major world language. So
Java software designed for the Internet must be global in scope. To create global
software, programs must be developed independently of the countries or languages of
their users. But these global programs must also be localized in order to be understood in
specific geographical regions. The process of writing global software that can be easily
localized is known as "internationalization". In the past, internationalization tended to be a
separate process that was performed after the original product development. But Java has
been designed to make it easy to create internationalized programs from the very start.
Included in JDK 1.1 is a diverse set of Internationalization APIs. Using these APIs,
Java programmers can adapt text, numbers, dates, currency, and user-defined objects to
any country's conventions. And this facilitates the development of global applications and
applets. Several Java packages contain classes that assist the internationalization
process. Two examples of these packages are
java.text
java.util
These are not Java's only internationalization packages. The java.io package
contains classes capable of converting character sets. And the java.awt package provides
support for the internationalization of a program's GUI. The java.text package contains
classes and interfaces designed for handling text in an appropriate way for a given country
or language. This is important because cultural and language conventions can become
significant when data is formatted for output. The java.text class Format is an abstract
base class for formatting and parsing locale-sensitive information. Three main subclasses
are derived from Format:
NumberFormat
DateFormat
MessageFormat
The abstract class NumberFormat contains static methods for supporting locale-
specific number formats. In this example, a currency format is being set for the German
locale.

The DateFormat abstract class is used to format and parse date or time values
according to the customs of a country. And the MessageFormat class enables
programmers to write code that handles messages in a language neutral way.

Page 221 Go To INDEX


The java.util package defines a number of useful localization classes, including the
Locale class and other support classes. It also contains new classes for date and time
handling. For example, the Calendar class is used to convert between the internal Java
representation of dates and times and the different calendar systems used around the
world.
Subclasses of the calendar class can represent specific calendar systems.
Calendar and its subclasses don't handle the formatted representation of dates. This is the
job of the java.text class DateFormat and its subclasses. However Calendar is used by
DateFormat.

• Using locales with Java


In many programming environments, locales are groups of characteristics defining
the language and cultural conventions of a particular region. Internationalized programs in
such environments are usually assigned a single "global" locale. This global locale
contains information that implicitly determines the behavior of the whole program. The use
of a global locale is inflexible because it groups unrelated pieces of information into a
locale, rather than associating the information with the classes to which it applies. In this
example, the global locale file en_US is being passed to two objects.
date M/D/Y
time HH:MM:SS
currency $
numeric 1,000.27
As you can see, both objects have access to all the information contained in the
locale. This means that each object receives information it doesn't need. Another
disadvantage of single global locales is that multilingual applications often require several
locales to be active at the same time. And where programs handle input from various
sources, multiple locales are needed to handle multiple character encodings.
Unlike traditional internationalized programs, Java programs are not assigned a
single global locale. Instead, operations which are sensitive to region or language are
explicitly given a locale as an argument. This greatly simplifies multilingual programs
because it means that each operation can be assigned a locale.
In this way, a Java locale acts as an identifier for a specific combination of
language and country. Every locale-sensitive class in a Java program maintains its own
locale-specific resources. It's good policy to group these resources by locale, and separate
them from the locale-neutral parts of the program. To help programmers do this, Java

Page 222 Go To INDEX


supports an abstract class called ResourceBundle. Using ResourceBundle, programmers
can create subclasses that contain all the resources for a specific locale.
This means that new resources can be added to this class, or new ResourceBundle
subclasses can be added to your program, without disrupting existing code. In addition,
packaging resources as classes allows developers to take advantage of Java's class
loading mechanism to load resources. In cases where programs are not designed to
manage locales explicitly, a system-wide default locale is available. Using a system-wide
locale, it is possible, with a single modification, to alter the look of an entire application.
A number of standard localizations are provided by Java's Internationalization APIs.
These are listed in your JDK 1.1 documentation. You can view a locale as a request for
certain behavior from a given object. Let's look at an example.
Suppose a French Canadian locale is passed to a Calendar object. As you know,
classes derived from the java.util Calendar class are used to represent specific calendar
systems. In effect, this locale is instructing the Calendar object to behave correctly for the
customs of French-speaking Canada. If an object has not been localized for a specific
locale, it will try to find a "close match" with the locale for which it has been localized. So if
the Calendar object isn't localized for French-speaking Canada, but is localized for the
French language, then it will use the French localization instead. As you know, the java.util
package defines the Locale class. Locale objects are generally created from a language
name and a country name.

All Java's International classes use the same convention for naming languages and
countries.
Language names are two-letter ISO-639 language codes and country names are
two letter ISO-3166 country codes. In this case, an empty country string is passed to the
Locale constructor.

This defines a locale for the entire English language. The Locale class contains a
number of handy constants for creating Locale objects for commonly used languages and
countries. For example, this specifies the Locale object for Great Britain.
Locale.UK
Using this constant, you can avoid creating a new locale.

The Locale class contains two static methods - get and set - for accessing the
system's default locale. At start-up time, the default locale is automatically set by the Java
run time to match the locale of the computer environment in which the program is running.
If this is not possible, the en_US locale is used.

• Java Support for Unicode

Page 223 Go To INDEX


Internet users often use a combination of languages to communicate with one
another. So not only must Java programs be capable of supporting many individual
languages, but they must also provide multilingual support. The set of all characters used
to write programs and represent data items on a particular computer is called a character
set. Because Java designers wanted Java to be both portable and support multiple
languages, they chose to adopt Unicode as Java's built-in character set.
The Unicode Standard is an internationally recognized (ISO) character encoding
system. In its current version (Version 2.0), the Unicode character set contains 34,168
distinct coded characters, derived from 24 language scripts. These include many non-
Latin characters used by East European and Asian languages. Unicode was designed to
support the interchange, processing, and display of diverse, written texts.
Since it is capable of encoding the characters used in the majority of world
languages, its use facilitates the development of multilingual programs. And it is well
suited to supporting the many languages used on the Internet. Each character in a Java
program is represented by a two-byte Unicode character. Each byte is composed of eight
bits.
So the implementation of a Unicode character is a 16-bit unsigned value. Using this
character encoding, the lowercase letter 'a' is represented in Unicode by the integer 97.
JDK 1.1 programs are able to display any Unicode character that can be rendered
with a host computer's font. Java provides a small number of predefined "virtual" font
names that can be mapped to a number of host fonts. In JDK 1.0, each Java font name
can be mapped to exactly one host font. But in JDK 1.1, a Java font name can map to a
series of host fonts. The series of host fonts can be chosen to cover as much of the
Unicode character set as is desired. The font mapping is specified in a font properties file.
One of the difficulties in using Unicode is the poor availability of fonts that can
display all of the Unicode characters. In addition, many Java programs run in language
environments where characters are usually encoded in 8-bits.
This means that storing each character in 16-bits as supported by Unicode is not
always the most efficient way to transmit text. To get around the problems associated with
Unicode, Java designers developed support for other encodings called "transformation
formats". For example, Java supports a UTF-8 character encoding with the
DataInputStream.readUTF() and DataOutputStream.writeUTF() methods. The UTF-8 is a
variable-width, or "multibyte" encoding format, that supports all the characters in the
Unicode character set. This means that different characters occupy varying numbers of
bytes, with characters from Western European languages each occupying only a single
byte.
Sometimes Java programs need to handle text data in non-Unicode character sets.
To do this, Java provides a set of classes that convert many standard character sets to
and from Unicode. These classes are grouped together in the java.io package. Java
programs typically convert non-Unicode text data into Unicode, process this data as
Unicode, and then convert the result back to the external character encoding.

Page 224 Go To INDEX


8
Java Security, Networking, & Internet
8.1. Java Security

• Security features of the Java language


Security becomes a critical issue when downloading applets and using programs
that interact with the Internet. You worry about hackers targeting your system with viruses,
Trojan horses, and in rare cases, "web-spoofing". Web-spoofing involves an attacker
slipping between a Web user and the web site being accessed. The attacker can read
sensitive data such as credit card details, while still allowing "through" access to the web
site in question. By pretending to be from a trusted source, a hacker's malicious program
might persuade your system to reveal valuable data.
Complete security cannot be guaranteed when interacting with a dynamic medium
such as the Internet. With Java, however, you can provide a significant level of security for
your computers and data, even in a networked environment. Java provides you with a
series of interlocking defenses that together form a barrier to most, if not all, attacks.
Java's powerful security mechanisms operate at four different levels of the system
architecture. Much of the security is inherent in the Java language itself. Java was
designed from the ground up to be a safe object-oriented language that would operate
effectively in a networked environment. The Java compiler - javac - ensures that the
source code doesn't break the language's strict safety rules. At run time, additional
security comes into play. All bytecodes are checked by a verifier to ensure they comply
with the safety rules. In the JDK, the Java interpreter is simply called java. The bytecode
verifier guards against an altered or rogue compiler producing code that violates these
rules.
The third level of Java's security involves the class loader. It ensures classes don't
violate name space or access restrictions when they are loaded into your system. Finally,
Java provides protection from attack through the use of the SecurityManager.
SecurityManager is an application-wide object that determines whether or not to
allow potentially threatening actions. The classes in the Java packages cooperate with the
SecurityManager. Basically they ask the SecurityManager's permission to perform certain
tasks. Java started off with an extremely conservative security model, which will become
more flexible as time goes on. Unfortunately, flexibility and security cannot both be
maximized. There is always a trade-off between absolute security and practical
functionality.
So far on the Internet, many users have chosen maximum flexibility at the cost of
compromising security. Java provides considerable security while sacrificing only a
minimal amount of the flexibility that has drawn so many users to the Internet. The Java
language and its compiler are the first line of defense in its elaborate security system.
Java was designed to be a safe, object-oriented language and to avoid some of the
problems associated with the C and C++ languages. Java's object-oriented features
protect data structures and limit the likelihood of unintentionally flawed programs arising.

Page 225 Go To INDEX


Object-oriented code also facilitates maintenance and so enhances system security. Java
enforces strict adherence to the object-oriented model.
Its private data structures and methods are encapsulated within Java classes.
Access to these resources is granted only through a public interface provided by the class.
Moreover, many classes and methods within the Java API are declared final, preventing
programs from further subclassing or overriding specific code. Java's language definitions
are strict.
All its primitive types, for example integers and floats, are guaranteed to be a
specific size. All operations are performed in a predefined sequence. This is very different
from C and C++, where the size of the primitive types are machine and compiler
dependent. With these languages, the order of execution is undefined also, except in
certain specific cases.
Java has learnt much from the shortcomings of the C and C++ languages. Most C-
like languages have facilities to control access to objects, but they also have ways to
"forge" access to objects, usually by mis-using pointers. This introduces serious security
flaws.
In the first place, it means no object can protect itself from outside modification,
duplication, or "spoofing". In addition, a language with powerful pointers is more likely to
have serious bugs that compromise security. Java eliminates these dangers in one stroke
by excluding pointers and pointer arithmetic from the language altogether.
Java still has pointers of a kind, called object handles, but these are carefully
controlled. Java's object handles are unforgeable, and all casts are checked before being
allowed. With Java, you cannot create code that thrashes system variables or accesses
private information. Java offsets the loss of pointers by providing powerful new array
facilities. Array bounds are strictly enforced, avoiding the bugs that in other languages
might lead to unexpected problems.
With Java, any attempt to index an element before the beginning or after the end of
an array will throw an exception. Unlike C or C++, Java is a strongly typed language,
which further enhances security. Its strict typecasting ensures that an object cannot be
arbitrarily cast to another type. This means that programs cannot access values of
uninitialized local variables, reference class variables, or private methods. Java also
provides support for thread-safe programming. Multi-threaded programming is an intrinsic
part of the Java language.
Special semantics ensure that different threads of execution modify critical data
structures in a sequential, controlled fashion. With C and C++, programmers have to
allocate and deallocate memory, as common bugs arise from careless memory
management. Sometimes programmers forget to free memory once it's no longer needed.
In other cases, they accidentally free the same piece of memory twice. Failing to free
memory can cause a program to use increasing amounts of it.
Accidentally freeing the same piece of memory often causes subtle corruption bugs
that are difficult to locate. The Java language eliminates the need for programmers to be
concerned with memory issues provided that they dereference unused objects. With Java,
memory management is dynamic and automatic. When you create a new object, for
example, Java automatically allocates the right amount of memory for it. When you finish
with an object, and carefully dereference it, Java's automatic garbage collector cleans up.

Page 226 Go To INDEX


The garbage collector searches for unused objects and reclaims the memory that
those objects were using. Besides plugging "memory leaks", automatic memory
management also prevents the "dangling pointers" problem - where valid storage is freed
prematurely. The Java language is in the public domain and so has been subjected to
close scrutiny for some time. The Java compiler's stringent compile-time checking of
source code ensures errors can be detected as early as possible. The source code for
both the Java compiler and interpreter are available to all and they have undergone
stringent security reviews. Java has by no means an infallible security system, but it's
probably more secure than most current software, precisely because it's been subjected to
such intense public scrutiny.
Any bugs or security loopholes detected are given maximum exposure and
consequently fixed quickly.

• The verifier
Java's security would be easy to undermine if it were merely reliant on the
protection afforded by the Java language and compiler. The compiler converts Java
source code into bytecodes. Java bytecode, the machine code for the Java Virtual
Machine, is the essence of what is transmitted over the network. When the Java run time
gets bytecodes from the Internet, it has no way of knowing whether those bytecodes were
generated by a trustworthy compiler or not.
A hostile compiler could easily create bytecodes that would perform dangerous
operations on your system. You cannot assume that bytecodes have been generated by a
benevolent compiler such as javac. From the start, the verifier adopts a conservative
approach.
All class files are presumed to be hostile unless proven otherwise. To guarantee a
safe execution environment, the verifier runs a comprehensive battery of tests on the
bytecode to ensure that they are observing the rules. These tests range from simple
format checks all the way to running a theorem prover. The verifier is able to detect
whether bytecodes forge pointers or violate access restrictions.
It can also ensure that bytecodes don't call methods with inappropriate argument
values or types, or try to overflow the stack. Another Java run-time requirement is that
when a set of bytecodes takes more than one path to reach the same point in a program,
all must arrive there with exactly the same type state. This is a strict requirement, and
means, for example, that compilers cannot generate bytecodes that load all the elements
of an array onto the stack.
This is not allowed because each time through such a loop the stack's type state
changes. The start of the loop would then have more than one type state.
In the interests of security, Java bytecodes actually carry more type information
than is strictly necessary for the interpreter. For example, iload and dload will both load a
local variable onto the stack. However, iload is always used to load an integer, and dload
is used to load a double. This additional type information allows the run-time system to
guarantee that Java objects and data aren't illegally manipulated.
The verifier checks all bytecodes for compliance with the extra type requirements of
Java. It examines each bytecode in turn and constructs the full type state as it goes. It
checks that all the types of parameters, arguments, and results are correct. The verifier

Page 227 Go To INDEX


acts as your system's security guard, allowing access only to those bytecodes with the
right credentials. You can only be certain of a safe execution environment when the
verifier has proved that the bytecodes are trustworthy. Once the verifier has done its job,
the interpreter can run much faster than before. In addition, object references can now be
treated as capabilities because they are unforgeable.
Capabilities allow advanced security models for file I/O and authentication to be
safely built on top of Java.

• The class loader


Once bytecodes have been approved by the verifier, they can then enter the class
loader. Working closely with Java's security manager, the class loader acts as a protector
of your system. The class loader's main function is to enforce Java's name space
hierarchy. It guarantees that separate namespaces exist for classes that come from your
local file system, and different network sources. When a new class is loaded into your
system, it is placed in one of several different realms.
For example, it may be placed on your local computer, on your firewall-guarded
local network, or on the Internet. Each of these realms is treated differently by the class
loader. In particular, the class loader never allows a class from a "less protected" area
replace a class from a more protected space. For example, the class loader wouldn't allow
a class downloaded from the Internet replace a class on the local file system.
You may, for example, have particular security concerns about your file system's
I/O primitives. These are all defined in a local Java class, which means that they live in the
local computer area. The class loader ensures that no class from outside your computer
can take the place of these classes or "spoof" Java code into using "rogue" versions of
these primitives. Furthermore, classes from one source cannot call on class methods from
other sources, unless those classes have explicitly declared those methods public. This
means that classes outside of your local computer cannot "see" your file system I/O
methods, much less call them.
They can only be called if you, or your system, wants them to be called. In addition,
every applet loaded from the network is placed into a separate package-like namespace.
This means that applets are even protected from each other. No applet can access
another's methods or variables without its cooperation. Applets from inside the firewall can
even be treated differently from those outside the firewall. The class loader essentially
divides the world of Java classes into small, protected groups, about which you can safely
make assumptions that will always be true. This type of predictability is the key to secure,
well-behaved programs.

• The security manager


The security manager and class loaders are at the heart of a Java application's
security policy. Together, they make the decisions about whether to grant requests for
access to your system's resources. The SecurityManager class collects in one place all
the security policy decisions that the Java system must make when bytecodes are run.
Browsers, such as HotJava and Netscape Navigator, enforce security policies by
implementing the SecurityManager class.

Page 228 Go To INDEX


In the case of browsers, an instance of some subclass of SecurityManager is
always installed as the current security monitor. The security monitor has complete control
over a carefully specified set of "dangerous methods" that are allowed to be called by any
given class. These methods usually concern file or network I/O.
In order to enforce the policy, the security manager takes into account the source of
the downloaded class. It also considers whether the class is from an applet or an
application. Security policy decisions for applets, including file I/O and network access,
can be configured by users within particular browsers.
They can change the security manager settings with the HotJava browser, either
allowing or preventing file reads, file writes, and network I/O by applets. You can enforce
the settings on an area by area basis, or you can give applets unrestricted access to your
system. Needless to say, giving applets unrestricted access is not recommended. The
Netscape browser currently does not allow you to change the default settings of the
security manager. Unfortunately, the JDK doesn't come with a working security policy
mechanism that's ready for an application to use.
By default Java applications, as distinct from applets, start without a security
manager. This means all the resources that SecurityManager could restrict are readily
available. However, by implementing a SecurityManager, you can add a significant
measure of protection to your system. Existing browsers and applet viewers create their
own security manager when starting up.
So an applet is subject to whatever access restrictions are imposed on it by the
security manager for the application in which the applet is running. The Java API provides
the java.lang.SecurityManager class as a way of creating a clearly defined set of tasks an
application can or cannot perform, such as accessing files or network resources. The
SecurityManager class allows you to establish a specific security policy appropriate to the
level of trust you want to give to a particular program. Let's see how the security manager
makes a decision about granting access to a system's resources.
Suppose an applet called Snoop has been loaded onto your system from the
Internet and wants to read one of your files, my.doc. To read the my.doc file, the Snoop
applet must use one of Java's core classes in the java.io package, for example,
FileInputStream. Because this class is a part of the overall security model, it must ask the
security manager for permission to read the file. How does a security manager decide
whether to allow my.doc to be read?
The SecurityManager class contains several native methods that can be used to
inspect the current state of the Java virtual machine. In particular, the methods being
executed while the security manager is being queried - the execution stack - can be
vetted. By checking the execution stack, the security manager can tell which classes are
involved in the current request.
It can then decide whether those classes can be trusted with the resources being
requested. The security manager needs the help of its class loader partners to do its job.
For each class on the execution stack, the security manager can determine which class
loader is responsible. For example, if it discovers that a class was loaded from the
network, it can then decide to reject the request to read the my.doc file. Until recently,
Java applications didn't support multiple levels of trust - a class was either trusted or not.

Page 229 Go To INDEX


Now that digital signature technology is available for Java classes, it will be
possible to verify the network source of Java classes. Security restrictions can then be
relaxed appropriately to provide greater flexibility and functionality.

• Applet security
It's important to note the differences between Java applications and Java applets as
they have definite implications for security. Java applications are stand-alone programs
that can be run by using the Java interpreter from the command line. Most Java applets,
however, run inside a WWW browser, with a reference to the applet embedded in a Web
page using a special HTML tag. JDK is intended to enable browsers to run untrusted
applets in a trusted environment.
When Java applets run inside a Java browser, they have the advantage of the
structure that the browser provides - an existing window, an event-handling and graphics
context, and a user interface. The convenience that applets have over applications in
terms of ready-made UI capabilities, however, is hampered by restrictions on what applets
can do. Because Java applets can be downloaded from anywhere and run on a client's
system, restrictions are necessary to prevent an applet from causing system damage or
security breaches.
Prior to JDK 1.1, there was no mechanism for establishing proof of ownership. As a
result, all applets were assumed to be untrustworthy and in general that still is the case.
Untrusted applets downloaded from the Internet are basically treated as suspicious by the
local system and restricted in several ways.
They are not allowed to read or write files, or execute programs on the local
computer. In addition, these applets are not allowed to create, modify, or delete local files.
Untrusted applets cannot make a network connection to a site other than the one from
which the applet was loaded. They cannot act as network servers either, or listen for or
accept socket connections from remote systems. Windows opened by an untrusted applet
are always identified clearly as Java windows.
This prevents a Java window from masquerading as something else, such as a
window's dialog box requesting your name and password. Unlike Java applications,
untrusted applets are also prevented from using dynamic or shared libraries from any
other programming language. Applets cannot make use of this feature because there's no
way to adequately verify the security of the non-Java code being executed.
The restricted applet execution environment is often referred to as the "applet
sandbox". The idea is that an applet has to play inside the sandbox, and any attempt to
leave it is prevented by the applet security manager. As you can see, the applet sandbox
model isn't meant to be a complete Internet security solution in and of itself.
However, it is an important safety net protecting your system against bug-ridden or
malicious code downloaded from the Internet. Java applets are more limited in
functionality than stand-alone Java applications. This loss is a trade-off for the security
necessary for applets to run remotely on your computer. When an applet is loaded from
the local file system rather than over the Internet, Web browsers and applet viewers may
relax some of their security restrictions. The reason for this is that local applets are
assumed to be more trustworthy than anonymous applets from the network.

Page 230 Go To INDEX


Web browsers, such as HotJava 1.0, may also allow the user the option of relaxing
security restrictions for trusted applets which have been digitally signed and whose
certificates have been verified by the user. The way an applet enters the system affects
what it is allowed to do. If an applet is loaded over the Internet, then it is loaded by the
applet class loader, and is subject to the restrictions enforced by the applet security
manager. If an applet resides on a client's local system, and is in a directory on the client's
classpath, then it is loaded by the file system loader. A local applet is subject to a more
relaxed security regime. Applets loaded via the file system are not passed through the
bytecode verifier. They can read and write files, and load libraries on the client. They are
also allowed to execute local processes and exit the virtual machine. Intermediate applet
security policies are also possible.
For example, an applet viewer could be written that would place fewer restrictions
on applets loaded from an internal corporate intranet than on those loaded from the
Internet. JDK 1.1 now provides the basic technology for loading and authenticating signed
classes. This enables browsers to run trusted applets in a trusted environment. Strict
security is still needed to run untrusted applets. In the release following JDK 1.1, JavaSoft
promise to provide more tools for finer-grained control of flexible security policies. Java
security doesn't try to solve every security problem.
At present, there are some potential attacks that Java doesn't prevent. These
problems involve the abuse of resources such as CPU cycles, memory, and windows. The
current Java security model makes no provision for letting an untrusted class use only a
certain amount of a system's resource. Java doesn't keep track of resource usage, so a
Java application cannot enforce resource quotas.
Rogue applets can exploit this fact to mount denial-of-service attacks that render
your computer useless by allocating all your memory or some other finite resource. For
example, a rogue applet could be set to monopolize your system resources using number-
crunching. This would cause your system to grind to a halt.

• Extending Java security


One of the key security capabilities missing from the initial Java implementations
was the ability to establish trust relationships. With Java 1.1 and the formation of the Java
Security API, you can now create trust relationships. Using digital signatures, you can
verify that code from specific sources has not been altered by a third party.
The latest features of the Java Security API are based on computer cryptography
designs and algorithms. The oldest and most familiar cryptographic system is private key
encryption. Under this system, both the sender and the receiver use the same secret key
to encrypt and decrypt a message. The private key encryption scheme has serious
limitations. Since both the sender and the receiver use the same key, either of them can
encrypt a message and claim the other person sent it. This underlying ambiguity about
who created a message makes it impossible to establish a message's origin.
A number of cryptographic systems use private key encryption. Data Encryption
Standard (DES) is a widely used system. However, cracking DES is quite possible with
today's technology. Some of the problems associated with private key encryption can be

Page 231 Go To INDEX


addressed by public key cryptography. This system is based on the idea of a pair of
private and public keys. One key can encrypt a message while the other decrypts it.
The private key is known only by the owner, while the public key is advertised
widely. It doesn't really matter whether you use the private or public key to encrypt a
message. The receiver just uses the other key to decrypt it. The combined use of private
and public keys can be used to guarantee message confidentiality and confirm the identity
of the sender. To create a confidential message to John, for example, you would use his
public key to encrypt the message.
Since the message was encrypted with John's public key, only John can decrypt it
with his own private key. Another advantage of public key cryptography is that it allows
you to confirm who sent a message. John is the only person who can encrypt a message
with his private key. If John's public key succeeds in decrypting that message, then the
message must have come from John.
Using public key cryptographic algorithms to encrypt entire messages is very time-
consuming. So cryptographers have devised a way to generate a short, unique
representation of a message called a message digest. To create a digital signature, you
encrypt the message digest with your private key. You can then transmit the unencoded
message along with the digital signature. If the message is altered in any way en route,
the receiver will not be able to decrypt the signature.
One of the limitations in the public key system is verifying that a public key truly
belongs to a trustworthy individual. It is quite possible that a hostile individual could claim
to be someone else and send you a message signed with a secret key. This attacker then
advertises the public key as belonging to another person.
When you obtain the public key and decrypt the signature, you may believe you
have verified the author. You can then end up trusting information that was actually written
by a hostile source.
To overcome this limitation, secure transmission systems on the Web have turned
to a system known as Certification Authorities (CA). Basically, a CA is a highly respected
organization that goes to great lengths to ensure that its public key is properly advertised.
These Certification Authorities include GTE Cybertrust, Nortel Entrust, and
VeriSign. The CA signs the key of other agencies that conclusively proves their identity.
When you receive the public key of an agency, you can use the CA's public key to verify it.
If successful, you know that the CA believes this agency is what it claims to be. Digital
signatures, based on public key cryptography, can extend the capabilities of applets. In
general, applets downloaded from the Net are assumed to be potentially hostile to your
system.
However, if an applet is digitally signed using public key cryptography, you can then
identify the source. This increases your confidence that a cracker has not somehow
altered what was written. You can then move on to establish trust relationships, assigning
specific roles to applets from known sources. If you have a relationship with a company
and trust the information it provides, you can then feel comfortable in allowing its applets
greater access to your system. It's important to remember that other parts of the Java
security system still remain in place, even after a trust relationship has been established.
So it isn't an all-or-nothing proposition.

Page 232 Go To INDEX


Applets from trusted sources may be given incrementally greater access to your
system. In JDK 1.1 Beta 1, signature checking always failed, and so all applets were
untrusted, with minimal permissions enabled. This made the code signing feature
unusable. This problem was fixed on December 13, 1996. Unsigned applets are still
untrusted and are subject to the same limitations that were in place prior to the release of
the Java Security API. As of February 18 1997, JavaSoft has included the digital signature
capability with JDK 1.1. JavaSoft promises to provide more tools for finely-grained control
of security policies in the release following JDK 1.1.

• The Javakey Tool


Java supports a special type of file called an archive file. Using Java archive (JAR)
files, you can package class files, images, sounds, and other digital data in a single file.
This simplifies and speeds up file distribution. To secure the distribution of JAR files
across the Internet, a digital signature is assigned to each file. Java provides a command-
line security tool called javakey to apply and maintain these signatures. Both JAR files and
javakey are new features for JDK 1.1.
By assigning digital signatures to JAR files, it becomes possible to verify that a
given file came from a specified entity. Two types of entity are managed by javakey:
Identities
Signers
Identities are people or organizations that have public keys associated with them.
Signers are people or organizations that have private keys in addition to public keys. In
order to sign a file, an entity must have both public and private keys.
A public key used for signing must be authenticated by one or more digitally signed
statements called "certificates". Information about private and public keys, certificates, and
their associated entities is grouped together in an entity database. And this database is
maintained by javakey. To generate a signature for JAR files, you must first create a
signer with an associated key pair and at least one certificate. Every signer (or identity)
that you add to the javakey database requires a username. To create a signer called
rVelasquez, you use the option -cs.
javakey –cs rVelasquez true
You can create an identity using the option -c.
From now on, any javakey commands acting on this entity must use the defined
username. The presence of the true clause in this statement indicates that rVelasquez is a
trusted signer. If you don't explicitly declare a trust level of true or false, then by default,
entities are untrusted. JAR file applets that are signed by a trusted entity have many more
rights than untrusted applets.
In fact, they are able to run with the same rights as local applications. Once you've
created a signer, you need to assign its public and private keys. In this example, a Digital
Signature Algorithm (DSA) public and private key pair has been generated for rVelasquez.
javakey –gk rVelasquez DSA 512
If a signer's public and private keys are DSA keys, then javakey will sign the JAR
file using DSA.

Page 233 Go To INDEX


If the signer's keys are RSA keys, then javakey will sign the JAR file using the
MD5/RSA algorithm. As you can see, the DSA has a key size of 512 bits. Now you need
to generate a certificate. Remember, every public key requires an associated certificate for
authentication. To do this, you must first specify a certificate directive file. The certificate
directive file must specify:
The entity whose publickey is authenticated byte certificate
Information about the certificate itself
The name of the signer signing and issuing the certificate

The person or organization signing the certificate should be publicly recognized as


being trustworthy. You can optionally include information about the signature algorithm to
be used.

This is only required where the algorithm is not DSA. The name of a file that stores
the certificate is also optional. Once the directive file is specified, you can generate the
certificate.
The -gc option instructs javakey to create a certificate using the information
specified in the directive file rVelasquezDirectiveFile.
javakey –gc rVelasquezDirectiveFile
You've seen how to create a signer in the javakey database, generate public and
private keys for this signer, and generate a certificate using this signer. Now you need to

Page 234 Go To INDEX


create a digital signature for that signer. Generating a digital signature, like certificate
generation, is directive-based. Each directive file contains a signer profile. So in order to
create a digital signature you must first create a signer profile. The signer referenced in
the signer profile must exist in the javakey database.

And the signer must have a certificate number. This specifies which of the signer's
certificates is used to sign the certificate file, and authenticates the subject's public key.
The chain parameter indicates the chain depth of the chain of certificates to be included.
This parameter is not currently supported. The signature filename can be eight characters
or less. You can also specify the name of the signed JAR file in the profile, but this
information isn't mandatory.
Once the JAR file and the directive file have been created, you can use the -gs
javakey option to sign the JAR file.
javakey –gs directiveFile jarFile
The directiveFile variable represents the name and path of the directive file. And
jarFile represents the name and path of the JAR file. The output of this command is a
signed and secure JAR file.

8.2. The applet execution environment

• Implementing the security manager


If you wish to tighten or otherwise change the security of your Java application, you
must implement your own security manager. To do this, your first step is to create a
subclass of the SecurityManager class. The Security Manager subclass will then have to
override various methods from the SecurityManager class in order to customize your
security policy. Let's assume you want a class CustomSecurityMgr to implement a security
manager that places further restrictions on reading your files.
To get permission from CustomSecurityMgr, you need to invoke one of
SecurityManager's checkRead methods. If CustomSecurityMgr approves access, then the
checkRead method returns. Otherwise, it throws a SecurityException. Our sample
program prompts the user for a password. If the password is correct, then permission to
read local files is allowed. In this example, the CustomSecurityMgr class extends
SecurityManager.

Page 235 Go To INDEX


The checkPassword method is invoked before a file is read. It prompts the user for
a password and then verifies it. If a user enters a valid password, then checkPassword()
returns true. If the password is invalid, it returns false. Let's now refine the applet's security
by first overriding the SecurityManager constructor to initialize the private instance variable
"password".

This will hold the password that the user must enter in order to read files. This
method calls the super function to initialize the base class. Let's now override the three
checkRead methods, to ensure that files can't be read without entering the correct
password.

Page 236 Go To INDEX


Each of these methods calls checkPassword() to prompt the user for a password. If
the password is invalid, checkRead() throws a SecurityException and the message
"Access Denied" is displayed. SecurityException is a run-time exception, and as such
does not need to be declared in the throws clause of the checkRead method. Write access
to the local files is still forbidden since no checkWrite methods have been overridden in
this program. Once you've completed your SecurityManager subclass, you can then install
it as the current security manager.

You do this with the setSecurityManager method. The main method starts installing
the new custom security manager. The highlighted code creates a new instance of the
CustomSecurityMgr class with the password "jumbo". This instance is passed to System's
setSecurityManager method. The setSecurityManager method installs the object as the
current security manager. This security policy will remain in effect while the application is
being executed. To verify that your customized security manager is working properly, you
open a "test.txt" file for reading.
If the file's contents are displayed, then your CustomSecurityMgr has been installed
correctly. When you run the CustomSecurityMgrTest application, you are prompted for a
password. If you type in the correct password, access is granted. If you type an incorrect
password, a SecurityException is thrown. The application terminates and the "Failed Test"
error message is displayed.

• Applet context
Applets are often viewed as incomplete applications. Yet applets have considerable
capabilities because they are supported by the code of the application they run in. Applets
have access to this support through the java.applet package. All of an applet's basic
functionality can be found in the java.applet package.
This package contains the Applet class, and the AppletContext, AudioClip, and
AppletStub interfaces. The AppletContext is a public interface that lets you get at
information in the applet's execution environment. Applets run inside browsers such as
HotJava and Netscape or the applet viewer. An applet can ask the browser to:

Page 237 Go To INDEX


Show a message in the status line
Fetch an audio clip
Show a different web page
The browser can carry out an applet's requests or ignore them. For example, if an
applet asks an applet viewer to show a web page, nothing happens because the applet
viewer isn't able to do it. When an applet wants to communicate with a browser, it calls the
getAppletContext method. This method returns an object of type AppletContext. An applet
can access only two areas of the browser:
The status line
The web page display area
Both use methods of the AppletContext class. Using the getAppletContext method
in conjunction with showStatus() lets you display a string in the status bar of a browser.

You can use this for error, link, or help messages. In practice, showStatus() is of
limited use as the browser uses the status line at the same time. More often than not, the
browser will overwrite your applet's message with its own, such as "Applet running ... ".
For that reason, you should avoid using the status line for important information.
The showStatus method may not be supported in all browsers. It should only be used to
provide optional information to the user. The showDocument method tells the browser to
show a different web page. The simplest way to do this is to call showDocument() with one
argument or string - the URL you wish to display.

The one-argument form of showDocument() means that the new web page opens
in the same window as your current page and so displaces your applet. To return to your
applet, the user must select Back. You can get the browser to show the document in
another window by using a second parameter in the call to showDocument().
showDocument(URL, string)
The two-argument form of showDocument() lets you specify the window or frame
where you want the document displayed.
The term frame refers to an HTML frame within a browser window and not to AWT's
Frame class. The second argument of showDocument() can have a number of optional
values. Using "_self" is the same as using one argument - the document is displayed in
the current frame.
showDocument(myURL, “_self”)
If you wish to display a document in a new unnamed top-level window, append
"_blank".
showDocument(myURL, “_blank”)
Using "_top" displays the document in the top-level frame of the applet's window.

Page 238 Go To INDEX


showDocument(myURL, “_top”)
The "_parent" argument uses the parent frame of the applet's window for display
purposes.
showDocument(myURL, “_parent”)
When you use any other string as your second argument, the document will be
displayed in the frame of that name.

• Handling Parameters
With Java applications, you can pass parameters to your main() routine by using
arguments on the command line. Applets, however, don't use the command line. Instead,
they use parameters from a HTML file containing the <APPLET> tag. To set up and
handle parameters in an applet, you need:
A special parameter tag in the HTML file
Code in your applet to handle parameters
Applet parameters come in two parts, a name and a value. For example, you can
set the color of text in an applet by using a parameter with the name color, and the value
blue. In the case of animation speed, for example, you can use a parameter with the name
speed and the value 5. Once you've decided on the names and values you want, you can
then mark each parameter with the <PARAM> tag in the HTML file containing the
embedded applet. The <PARAM> tag goes inside the opening and closing <APPLET>
tags. Let's look at some HTML code for handling parameters.

This example defines two parameters for the MyApplet applet. Here, the name of
the first parameter is title and its value is the text string "Cool Site". The next parameter
specifies the font as Times Roman. Parameters are passed to an applet when it is first
loaded. Parameters are generally accessed by using getParameter() in the init method of
the applet. The init method is used for whatever initializations are needed for your applet.

It is called by the system when the applet is first launched. The getParameter
method takes only one argument - a string containing the name of the parameter you're
looking for. This method will return a string containing the corresponding value of the
parameter. Suppose you want to get a font parameter's value from your HTML file. To
access this value, you need to include the following code in your init method:

Page 239 Go To INDEX


string thisFontName=getParameter("font");
Parameter names specified in the HTML file and parameter names used in the
getParameter method must match exactly. If, for example, a HTML file contains <PARAM
NAME="font"> but your applet code contains getParameter("FONT"), then the font
parameter won't be passed on.
If an applet's parameter has not been specified in the corresponding HTML file, the
getParameter method returns null. To handle such cases, you should test for a null
parameter. If a parameter is missing, you can then add a reasonable default:
string thisFontName=getParameter("font");
if (thisFontName==null)thisFontName = "Courier";
The getParameter method always returns strings. So if you want a parameter to be
some other object, you have to convert it yourself. For example, if you specify an integer
parameter such as size in your HTML file, you will need to parse it, and assign it to an
integer variable in your applet. Here you assign the size parameter to an integer variable
called rightSize.

If no size is specified in the HTML file, then a default size of 10-point type is set. In
this line you parse the parameter size, converting it from a string to an integer. Supplying
applet parameters makes it easy for users to modify your applet's functionality and
appearance to use it in their own home pages. Adding a few lines to a HTML document is
much simpler than having to change and recompile source code.

• System properties
Java stores information about your system in a Properties object that is part of the
System class. Applications would normally have complete access to this information.
Applets have only restricted access to it. The level of access to the System properties is
controlled by the checkPropertyAccess method in the SecurityManager class.
There are fifteen standard properties in the system properties list. Certain sensitive
values are hidden from "untrusted" applets. Using Netscape Navigator or the applet
viewer, you can read ten system properties from within an applet. You simply call
System.getProperty(key) on the property you are interested in.

This code, for example, would allow an applet to discover the operating system's
architecture.
Using os.name and os.version keys enable applets to read the name and version of
the operating system.
os.arch x-86
os.name – Windows 98

Page 240 Go To INDEX


os.version – 4.0
Other system properties that an applet can access include java.version,
java.class.version, java.vendor, and java.vendor.url.
java.class.version – 45.3
Less sensitive properties such as platform-dependent file, path, and line separators
can also be read by applets.
file separators: / or \
path separators: : or ;
line separators: \n or \r\n
With most browsers, applets cannot access sensitive information such as a
username, a user's home directory, or current working directory.

Applets are also denied access to java.home, the directory Java is installed in, and
to java.class.path.

You cannot hide the ten system properties from applets loaded into Netscape
Navigator. For security reasons, Netscape Navigator doesn't read or write to any files,
including the ~/.hotjava/properties file.
The tilde ~ symbol is used on UNIX systems to refer to your home directory. If you
install a web browser on your E: drive and create a top-level directory named .hotjava,
then your properties file is found in E:/.hotjava/properties.
You can prevent applets loaded into the applet viewer accessing your system, by
redefining properties in your ~/.hotjava/properties file. If you add os.name=null to this
properties file, for example, the name of the operating system will be hidden from applets.
Applets loaded into Netscape Navigator can't read system properties other than
those that can be read by default.
However, if you add user.name.applet=true to your ~/.hotjava/properties file,
applets loaded into the applet viewer will be able to read the username. Applets loaded
into Netscape Navigator cannot read or write files. However, Sun's applet viewer allows
applets to read and write files that are named on the access control list for reading or
writing. The access control list is empty by default. You can allow applets to read or write
to a file by setting the relevant properties in your ~/.hotjava/properties file.
For example, if you wish to allow an applet to write to myfile in mydir, you name it
explicitly:

Page 241 Go To INDEX


acl.write=/mydir/myfile

• Applet-to-applet communication
If multiple applets are contained in a web page, applets can communicate with each
other. Inter-applet communication is possible using static variables of a shared class.
There are a number of possible solutions for inter-applet communication, including
JavaScript-assisted solutions and server-based solutions.
However, you can invoke inter-applet communication completely within Java using
the AppletContext and static variables. If you want to have several different applets on a
web page, all you have to do is include several applet tags in the HTML file. The browser
will then create an instance of each applet for each corresponding applet tag. Some
browsers may not allow multiple applets on the same web page.
When a security hole was discovered, Netscape Navigator 3.0 deactivated this
feature. Netscape Navigator 4.0 will restore this feature. How do you communicate
between applets appearing on the same web page? What if you want a change in one
applet to affect another applet in some way?
Using the applet context is the best way to access different applets on the same
page. Let's say you want to get information about all the applets on your web page. The
getApplets method returns an Enumeration object with a list of the applets on the page.

Iterating over the Enumeration object enables you to access each element or applet
in turn. Calling a method in a specific applet is slightly more involved. To do this, you give
all your applets a name, and then refer to them by that name inside the body of code for
that applet. To give an applet a name, you simply use the NAME parameter in your HTML
file.

To get a reference to another applet on the same page, you use the getApplet
method from the applet context with the name of the applet. You can then refer to that
applet as if it were just another object - set its instance variables, call methods, and so on.
In this code sample, you use the getApplet method to get a reference to the recipient
applet.

Page 242 Go To INDEX


Once you have that reference, you can then call methods in that applet as if it were
just another object in your environment. Assuming the MyApplet class has an updateData
method, you can, for example, tell the recipient applet to update itself using information
available to the current applet.
Naming applets in a HTML file and then referring to them by using
getAppletContext() and getApplet(), facilitates applet-to-applet communication. This helps
provide uniform behavior for all the applets on your web page.

8.3. Networking

• URL Objects
A Uniform Resource Locator (URL) is a reference to, or the address of, a resource
on the Internet. An example of a URL is as follows:
http://java.sun.com/
This particular URL addresses the home page hosted by Sun Microsystems. All
URLs have two main components:
The protocol identifier
The resource name
In the example quoted, http is the protocol identifier (Hyper Text Transfer Protocol),
and //java.sun.com/ is the resource name. The colon (:) separates the two components
and the trailing slash (/) is a shorthand for a default file depending on the host (it may be
/index.html). In the context of our discussion of the Java language, the term URL may
refer to one of two concepts.
A URL address is the location where a web resource resides. A URL object is an
instance of the URL class in a Java program.
HTTP is not the only protocol used to access resources on the Internet.
Other protocols include FTP (File Transfer Protocol), Gopher, and News.
The URL address provides the complete location of the resource on the Web. While
the format of the resource name varies with the protocol used, generally the resource
name contains one or more parts. The URL parts are
Host name (name of host machine)
Information field
Port number (to connect to)
Anchor indicated by a hash# character (reference to a specific location within
a file)

Page 243 Go To INDEX


For some protocols, the host name and the file information are required, but the
port number and anchor reference are usually optional. The exact content of the
information field is both protocol- and host-dependent. For example, the information field
may indicate the path name to a file. The default port number for the protocol is supplied if
none is specified (HTTP is 80).
The anchor reference is not technically part of the URL. Resources other than
hypertext documents can be accessed with URLs. A resource can be something as simple
as a file or directory. It can also be a reference to a more complicated object such as a
query to a database or search engine.
The class named URL is contained in the java.net package. Your Java program can
construct a URL object, open a connection to it, and read to and write from it. Let's look at
how to create a URL object. The easiest way to do this is to create it from the string that
forms the URL address. Here is an example of this in a Java program.

This is creating an absolute address which gives you all the information necessary
to reach a resource (in this case, to reach the Java web site hosted by Sun
Microsystems). While a URL object always refers to an absolute URL, it can be
constructed from an absolute URL, a relative URL, or from URL components.
A relative URL contains only enough information to reach the resource relative to
(or in the context of) another URL. Suppose that you have already created a URL for
http://www.gamelan.com and you know the name of a file at that site, namely network.html. You
can create a URL for that file by specifying the filename in the context of the original
Gamelan URL. The code for this is now shown in the graphical area.

Additional constructors allow you to specify a URL from its components, which is
useful if you do not have a complete string. An example of this would be when you are
letting users use the mouse to select the protocol, hostname, port number, and filename.
This is now shown in the graphical area.

The URL class provides several accessor methods that parse the URL for you.
The getProtocol method returns the protocol identifier component of the URL.
The getHost method returns the hostname.
The getPort method returns the integer port number.
The getFile method returns the information field of the URL.
The getRef method returns the anchor or reference field of the URL.
Not all URL addresses contain all these components. This is particularly true of
HTTP addresses, which are probably the most commonly used URLs. The accessor

Page 244 Go To INDEX


methods can be used to get information about the URL regardless of the constructor used
to create it. Having successfully created a URL, you can call the URL's openStream
method to get a stream.
This enables you to read from that connection. The openStream method returns a
java.io.InputStream object. If you need to do more than just read from a URL, you can
connect to it by calling openConnection() on the URL. Connecting to a URL means you
are opening a connection to the remote object referred to by the URL. In the following
example, shown in the graphical area, a connection is opened to the search engine site
named site.

The openConnection method tries to create a new URLConnection, initializes it,


explicitly connects to the URL, and returns the URLConnection object. A
MalformedURLException occurs if the new URL fails. If the site search engine is down,
then the openConnection method throws an IOException error. The URLConnection class
contains a number of methods that let you communicate with the URL over the network. It
is most useful with HTTP addresses.
Most URL protocols allow you to read from and write to a URL through a
URLConnection object. You may find that reading from a URLConnection, rather than
reading directly from a URL, is more useful to you. This is because you can use the
URLConnection object for other tasks at the same time, such as writing to the URL. The
URLConnection class also provides methods to get information such as the content type
of the resource, or HTTP header information sent with the resource.
Let's now look at writing to a URL, often known as posting to a URL. Many HTML
pages contain forms. These are buttons, fields, listboxes, and other GUI objects that allow
you to enter data and use your web browser to write the data to the URL over the network.
At the server end a Common Gateway Interface (CGI) script reads the data, processes it,
and sends you back a response, usually in the form of a new HTML page. Many CGI
scripts use the POST method for reading data from the client, often reading from their
standard input.
Some server-side CGI scripts use the GET method to read your data. However, the
POST method is rapidly making the GET method obsolete because it's more versatile and
has no limitations on the amount of data that can be sent through the connection. Both
POST and GET are HTML form methods, not Java methods. Your Java programs can be
designed to interact with CGI scripts on the server side. They just need to be able to write
to a URL, to provide data to the server. Writing involves several steps:
Creating a URL
Opening a connection to the URL

Page 245 Go To INDEX


Getting an output stream from theconnection - this is connected to the
standard input stream of the server's CGI script
Writing to the output stream
Closing the output stream
One of the most important uses for writing to a URL is searching. A URL may
require detailed query data to be supplied. Your Java program can interact with the server
CGI script to carry out a long series of searches.

• Opening streams to the server


Input and output are an integral part of computer programming. Every computer
language must have a way of dealing with I/O. Data can be described as flowing from the
input through the computer to the output. A stream is nothing more than a flow of data.
Input streams direct data from the outside world (for instance, the keyboard) to the
computer.
Output streams direct data towards output devices, such as a computer screen, file,
or printer. The java.io package defines over twenty stream classes that you can use to
control the flow of data in your programs. Apart from basic I/O, these classes provide a
whole range of functionality. Bytes are not the only data types you can send with Java.
You can send whole objects across a stream. Java also allows you to parse data from a
stream. You can create and manipulate disk files and directories. You can communicate
between threads using pipe streams. The java.io classes that provide basic stream input
are:
InputStream
BufferedInputStream
DataInputStream
FileInputStream
InputStream is the class that provides the basic functionality for all input streams.
The basic method for getting data from any InputStream object is the read method.
public abstract int read () throws IOException
The code shown reads a single byte from the input stream and returns it. A blocking
read is executed using this method, which means that the program waits for the next byte
of data to arrive. When the stream reaches the end of stream, the method returns -1. The
advantage of buffered streams is that they help speed up your programs by reducing the
number of system reads and writes. The BufferedInputStream class reads data in blocks
into a buffer. Subsequent reads can access the data directly from the buffer. You provide
the buffer size when you create the class. The DataInputStream class is a stream filter for
the DataInput interface. It reads primitive Java data types from an input stream in a
machine-independent manner. The constructor is now shown.
public DataInputStream (InputStream in)
The last basic input class currently available is FileInputStream. This class allows
you to read files. You can create file streams from a filename string, a file instance, or a
special file descriptor. The java.io classes that provide basic stream output are

Page 246 Go To INDEX


OutputStream
BufferedOutputStream
DataOutputStream
FileOutputStream
PrintStream
An output stream is a recipient of data. OutputStream is the class that provides the
basic functionality for all output streams. The most basic method of an OutputStream
object is the write method. The code shown writes a single byte of data to an output
stream.
public abstract void write (int b) throws IOException
The BufferedOutputStream class writes data into a memory buffer. The contents of
the buffer are written to disk when the buffer is full, the buffered output stream is closed, or
when flush is called. You provide the buffer size when you create the class.
The DataOutputStream class is a stream filter for the DataOutput interface. It writes
simple data types. The constructor is now shown.
public DataOutputStream (OutputStream out)
The fourth basic output class is FileOutputStream, which allows you to write data to
files. As with FileInputStream, you can create file streams from a filename string, a file
instance, or a special file descriptor. The fifth basic output class is PrintStream.
PrintStream provides for printing values and objects as text output. PrintStream uses:

Write() to write data tothe stream


Flush() to flush data from the stream
CheckError() to flush the stream and flag errors
Print() to print data in text form
Println() to print a line of data (and a line separator)in text form
Close() to close the stream
Let's briefly look at some of the more advanced features available in the Java
stream classes. One major aspect of streams is that you can chain one stream to the end
of another. You can achieve this using the FilterInputStream and FilterOutputStream
classes. You can read from and write to arrays of bytes using the ByteArrayInputStream
and ByteArrayOutputStream classes.
A ByteArrayOutputStream is an array of bytes that continually grows to fit the data
that is stored in it. The ability to stream arbitrary objects became available with Java's
Remote Method Invocation. The ObjectInput and ObjectOutput interfaces define methods
for reading and writing any object.
The ObjectInputStream class implements a stream filter for the ObjectInput
interface. Similarly, the ObjectOutputStream class sets up a stream filter that allows you to
write any object to a stream, as well as any primitive type. The StreamTokenizer class
allows you to treat a stream like a group of words and parse the data. It works in a similar

Page 247 Go To INDEX


way to the StringTokenizer class for strings. StreamTokenizer implements a simple
dictionary scanner that breaks up a stream of characters into a stream of tokens.
The File class lets you manipulate files and directories on the local system. With the
PipedInputStream and the PipedOutputStream classes, you can link an input stream to an
output stream directly. A piped input stream is the receiving end of a communications
pipe. Two threads can communicate by having one thread send data through a piped
output stream, and having the other thread read the data through a piped input stream.
Let's examine a Java application (as opposed to an applet) that reads a file from a remote
server.
It first connects to the server using the server's URL. It then opens an input stream
to read the contents of the file and display them.

A number of points are worth making about this ReadFile program. A URL object
called url is created and this is set to an absolute address. The absolute address refers to
file test.txt on the remote host javaworld.com on the World Wide Web, running protocol
HTTP.
On the next line in the example program, a BufferedReader named is defined. This
is setting up the input stream. BufferedReader is a class in the java.io package. It reads
text from a character-input stream, buffering characters so as to provide for the efficient
reading of characters, arrays, and lines. You will notice the use of the openStream method
on the same line of code. This gets an InputStream to the object referenced by the URL.
The reader is InputStreamReader. InputStreamReader is a class in java.io. It acts as a
bridge from byte streams to character streams, reading bytes and translating them into
characters according to a specified character encoding.

Page 248 Go To INDEX


Without buffering, each read request made of the reader would cause a
corresponding read request to be made of the underlying byte stream. To avoid this
inefficiency, BufferedReader is wrapped around the InputStreamReader so that the input
is buffered.

• Socket Programming with Java


You can communicate over the network at a relatively high level using URLs and
URLConnections to access resources. However at times you may require a lower level
network communication, especially when you want to develop a client/server application.
In client/server applications, the server does back-end processing such as stock control or
processing database queries.
The client displays the database query results or stock prices to the user.
Communication between client and server normally needs to be very reliable. No data can
be dropped in transit. Data must arrive on the client side in the same order that it was sent
by the server. A protocol must provide a reliable point-to-point communication channel for
client/server communications.
A socket is one end of a two-way communication link between two programs
running on a network. A socket uniquely identifies a communications link. No two
applications can bind to the same port on the same machine simultaneously. Many clients
can connect to a single server through separate sockets. Two protocols are used in socket
programming - UDP (User Datagram Protocol) and TCP (Transmission Control Protocol).
Technical information is available on the UDP protocol in RFC 768 and on the TCP
protocol in RFC 793. You can download these RFCs from ftp://ds.internic.net. A server
application usually listens to a specific port, waiting for connection requests from a client.
When such a request arrives, the client and the server make a dedicated connection over
which they can talk. During the connection process, the client is assigned a local port
number, and binds a socket to it.
The client can now write to the server and get information from the server by
reading from it. The server needs to get a new local port number so that it can continue to
listen for connection requests on the original port. A socket is bound to the server's new
local port. The client and the server must be agreed on the protocol for transferring
information. Let's look at socket programming using the UDP protocol. UDP is sometimes
compared to communicating with postcards, because messages are usually restricted in
size and replies are not guaranteed. UDP is generally branded as unreliable. Making
allowances for unreliability is the responsibility of the programmer.
This can mean programming clients to retransmit requests and to display error
messages. UDP is connectionless and message-oriented. UDP does not have the
overheads associated with reliability, such as datagram acknowledgment. So UDP is a
good choice for applications in which discrete messages (datagrams) are sent. A discrete
message could mean a single query from a client invoking a single response from a
server.
Time-dependent data is particularly suited to UDP. UDP programming can be
broken into a number of tasks:
Creating a properly addressed datagram to send

Page 249 Go To INDEX


Setting up a socket to send and receive datagrams
Inserting datagrams into a socket for transmission
Waiting to receive datagrams from a socket
Decoding information from the datagram
Creation and decoding of a datagram is achieved by means of the DatagramPacket
class in the java.net package. You use the following constructor (shown graphically) to
create a datagram to send to a remote system.

In the code, you need to replace ibuff with the name of the buffer for the array of
data. You replace length with the exact number of bytes you want to send. In the code,
iadd takes the IP address of the intended recipient. You fill the destination port number
where iport is indicated. Next, a UDP socket is created making use of the DatagramSocket
class. Two constructors are available.
One allows the system to assign an unused port dynamically. The other allows you
to specify a known port to be the socket. The two constructors are shown in the graphical
area.

For both UDP and TCP protocols, superuser privileges are required to bind ports
below 1024. Well-known ports such as FTP, Telnet, and HTTP are assigned to ports
below 1024. A named datagram can now be inserted into the socket port for transmission
using a DatagramSocket method.

You receive a datagram packet using the function shown in the graphical area.

Because UDP datagram delivery is unreliable, the receive method may never return
anything. The receive method of the class DatagramSocket blocks until a datagram is
received, so the program can hang. This dilemma can be addressed using threads in the
program. The TimeCompare class uses different threads of execution, and the application
can make it interrupt the program after a certain length of time.
Once communication through the UDP socket is finished, that socket should be
closed.
public synchronized void close ()
After a datagram has been received, you can read the data. Other information
regarding the message itself is also available through DatagramPacket accessor
functions.

Page 250 Go To INDEX


The getLength method obtains the number of bytes occupied by the data portion of
the datagram. The getData method obtains a byte array containing the data received. The
InetAddress object identifying the sender is provided by the getAddress method. The
getPort method indicates the UDP port used.
Let's now look at socket programming with the TCP protocol. TCP sockets are a
powerful programming facility and enable you to develop quickly your own custom
client/server applications. As a protocol, TCP is very reliable and is much more often used
than UDP for socket programming. In client/server applications, a centralized service waits
for various remote machines to request specific resources.
This service handles each request as it arrives. For many application protocols, you
can use the Telnet application to connect to the service port and then manually emulate a
client. As with UDP, client applications must obtain or bind to a port to establish a socket
connection. Four items of data are needed to set up a TCP connection:
The local system's IP address
The local application’s TCP port number
The remote system's IP address
The remote application's TCP port number
The java.net package contains two main classes used for TCP socket
programming. These are Socket for the client side and ServerSocket for the server side.
The Socket class is used for ordinary two-way communications. It has four constructors,
which are now illustrated graphically.

Page 251 Go To INDEX


In the constructors, host or address is replaced with the address of the remote host.
Port refers to the remote port number.
The boolean parameter is used to negate the default protocol, which is stream-
based like TCP. In other words, stream set to false means that a protocol such as UDP is
used instead. A socket connection (named conn) can be opened as follows.

The hostname and port number are specified. The Socket class has methods that
allow you to read and write through the socket connection. These are the getInputStream
and getOutputStream methods. Examples of creating buffered input and output streams
for reading from and writing to the socket are now shown in the graphical area.

Once you have finished with the socket connection, it is necessary to close it.
Continuing with the example variable names, the code for closing the input and output
streams and the socket is now shown.

The ServerSocket class listens for connections incoming to the server. It creates a
Socket object for each new connection. The server socket must have a port number to
listen on. Here are the two constructors, shown graphically.

If you pass a port number of zero, the system will assign the port number for you.
The second constructor shows a connection backlog implementation. If many clients
connect to a server at once, the number of connections yet to be accepted is the backlog.
A limit can be set for this backlog. The accept method is used to accept incoming socket
connections. Here is a simple way of creating a server socket called sconn bound to port
5555, listening for connections, and accepting any connections.

If no connections are pending, the accept method blocks until there is a connection.
Performing accept() in a separate thread is a way of preventing your program from

Page 252 Go To INDEX


blocking completely while waiting. The methods for finding out the address and port
number for your server socket are now shown.

This is the method for closing a connection.


Public void close() throws IOException;
This is how it is achieved in the case of connection sconn.
sconn.close();

• A simple client/server application


A Java client/server application has a program running on the client side, which
communicates with a program on the server side. Let's look at an example of TCP socket
programming, beginning with Client.java, which implements a client application. Then we
deal with Server.java, which implements a server application. The code for Client.java is
shown in the graphical area.

A number of points are worth noting about this code. A socket connection is
established using the Socket class and it is called conn.

Page 253 Go To INDEX


The constructor arguments describe the machine on which the server is located
and the port number on which the service is provided. In this case, we are connecting to a
server on the local machine using InetAddress.getLocalHost(). After connecting to the
server, an input stream is opened using the getInputStream method. InputStreamReader
is a class that reads bytes and translates them into characters. BufferedReader is
wrapped around the InputStreamReader so that the input is buffered. The constructor for
the InputStreamReader object takes the feeder InputStream object as an argument and
establishes the connection automatically.
In the same way, the constructor for the BufferedReader object takes the
InputStreamReader object as an argument. Input is read and buffered until the end of
stream is reached. The output of the server is read using the is.readLine method of the
BufferedReader class.

Finally, the conn connection is closed by conn.close(). Now, let's present the code
for Server.java. The most relevant parts of Server.java are now described.

Page 254 Go To INDEX


Using the ServerSocket class, a Socket object called server is set up to listen for
incoming connections on port number 4000.
The server then waits for a connection from clients by issuing the accept method
call. This method blocks the current thread until a client has made a connection. When the
connection has been made on port 4000, accept() returns a new Socket object. Then an
output stream is opened, using the getOutputStream method, for sending a message to
the client. This in turn is wrapped in the OutputStreamWriter, and the writer is given the
name os.
"Server says 'Hello'." is sent to the client using the write method. To make sure that
the message has been written out of internal buffers to the connected stream, the flush
method is invoked. Finally, the conn connection is closed by conn.close().

8.4. Server Issues

• Java server product family


The Java Server product family is an emerging suite of Sun Java products specially
designed for the server side of client-server applications. The applications are designed to
reside on the Internet, corporate intranets and extranets, and new Network Computing
environments. Four products have been announced:
Java Server Toolkit
Java Web Server
Java Servlet Developers Kit (JSDK)
Java NC Server
These products are all based on the Java Server application program interface
(API). The Java Server API defines a cross-platform, extensible framework for the creation
of network-centric server solutions, such as web servers and proxy servers. The Java
Server product suite also contains the Java Servlet API. The code that services a request

Page 255 Go To INDEX


is known as a servlet. A servlet is the server side equivalent of an applet, but it does not
have a graphical interface.
Java Server has been shipped in an alpha, beta, and now JDK 1.1 version. To use
Java Server, you need to have a server environment as well as a client environment from
which to run administrative tools. You can download a version of the Java run-time
environment from Sun's web site to suit most platforms.
On UNIX, it is possible that you will want some special support to run Java Server
automatically as the default web server. Java Server is not currently supported on the
Macintosh, but this will be rectified with JDK 1.1. The client environment for Java Server
needs the administrative applet. The currently released versions of Netscape Navigator
(3.0), Microsoft Internet Explorer (3.0) and AppletViewer, all of which are JDK 1.0.2
compatible, support the administrative tools. Older web browsers do not.
The Java Server Toolkit consists of the Java Server API, a core set of servers,
tutorials, and examples. The Java Server Toolkit can be used to create web servers, mail
servers, print servers, proxy servers, and boot servers. JavaSoft has developed a web
server written completely in the Java programming language, using the Java Server
Toolkit. This is Java Web Server. Web site developers can use the Java Web Server to
bring dynamic content to their pages.
Java Web Server supports the Java Servlet API. With the help of the Java Servlet
Developers Kit (JSDK), you can create Java servlets to enhance web sites. JSDK includes
a servlet engine for running and testing servlets. It also contains the java.servlet.* sources
and all the API documentation for java.servlet.* and sun.servlet.*.
The Java NC Server will be used for developing network computing environments.
Java NC Server will support JavaOS and the recently introduced HotJava Views user
productivity environment to provide solutions for deploying network computers across the
enterprise. Let's take a closer look at the Java Server generic framework, and how a
HTTP server is built using it. The architectural framework provides a generic set of classes
for implementing connection-oriented servers. These servers manage multiple threads for
handling client connections. A HTTP server acceptor thread uses the framework to listen
to the incoming HTTP requests. In this way, a HTTP request is dispatched by the acceptor
to the HTTP server handler thread.
The handler thread then carries out authorization and name translation, based on
server administration settings. The handler finds out which servlet, if any, will be able to
handle the request. Servlets are object bytecodes that can be dynamically loaded off the
Internet. However, servlets do not have a graphical interface of their own, and are termed
faceless objects. Servlets have to conform to a specific interface.
Like applets, they can be identified by a URL address. Sun is still developing Java
Server. It is planned to integrate Java Server with existing operating system facilities as
much as possible. Integration with standard network management and security tools is
foreseen. Network management tools such as JMAPI, SNMP, and CMIP are candidates
for integration. It is not anticipated that administrators will need to modify administration
files, which are properties format name-value pairs.
Servers and servlets make use of an EventLog log file for messages of arbitrary
format. Access to files is controlled using access control lists (ACLs) and these are in
common log file format.

Page 256 Go To INDEX


• Java server security
Web site services shared by many people need to be defended against a variety of
security problems. Java Server allows you to defend your web site against two general
forms of threat or attack:
Alteration or theft of data
Malicious code
Theft can occur when data is in transit to or from the server. This is generally the
work of eavesdroppers. Another aspect is theft within the organization, and the principal
guard against this is access controls. Code received from outside is potentially malicious
in intent. The servlet "sandbox" provides a safe environment in which servlets can be
checked out. Every web site has a security policy that defines, however vaguely, "how
secure this site needs to be". Some risks are inevitable and acceptable in every
enterprise, but other risks are not.
A "risk versus reward" tradeoff needs to be made. Web site security policy is
administered by your web site administrator. You can never trust software security
mechanisms on their own, since they can be overwritten. The bottom line is that your staff
also need to be trustworthy. They need to be trusted not to violate your security or that of
your customers. Java Server supports a variety of security mechanisms, and these can be
grouped as:
HTTP protocol features
UNIX-specific server features
Java-specific server features
Let's view the various HTTP-oriented features. In these features, the concept of
authentication occurs. This generally refers to verification, but it has a particular meaning
in Secure Sockets Layer. Secure Sockets Layer (SSL) server authentication means that a
server authenticates (validates) itself. It can also mean a client authenticating itself on
request from a server. The browser users are guaranteed that the server they are
addressing is, in fact, the one they think they are addressing.
This is achieved through a third party Certificate Authority. SSL privacy protection is
a protocol feature that allows for encryption of data sent to or received from the server.
Encryption has to be approved by both the web site administrator and the user. It is most
useful for protecting financial information and credit card numbers. Basic authentication
refers to the basic verification of a username and password after they are entered into a
login prompt or dialog box. Access control lists (ACLs) are part of the access control.
Passwords in transit are susceptible to eavesdropping. Passwords stored in plain
text on a server are also vulnerable. Digest authentication resolves the problem of
passwords in transit. However, the server still needs to store the passwords in plain text.
SSL Client authentication protects against attacks on the server's stored passwords but it
is not yet supported.
Realms consist of groups of users using a virtual host, application, or part of a
given web site. Different realms can be given different sets of access privileges. So, two or
more users named "Marie" can be different people with different sets of privileges,

Page 257 Go To INDEX


depending on the realm. Groups within a realm can be a way of efficiently distributing
privileges.
For instance, you might want to define a group "accounts", all of whose members
can access accounting web pages. ACLs allow your web site administrator to limit user
access to individual web pages or trees of web pages. ACLs assign permissions to users
and groups.
Users, groups, and ACLs are all within the scope of a realm. Now, let's describe the
UNIX-specific server features. These are provided through an optional native code
module. Java Server can be set up so that the "root" account is needed only when initially
binding to the default HTTP server TCP port (80).
All normal administrative tasks after that can be done without needing "root"
privileges. Java Server supports a "UNIX" realm. This allows the existing UNIX user
accounts to be used for access control, removing the need for double administration. Web
pages belonging to UNIX users can be automatically exported through the Java Server.
The remaining security features are those, which are Java-specific. Java Server
provides administrative tools, which help avoid manual error-prone editing of text files.
Administration pages are controlled by digest authentication, by default. Additionally,
HTTP over SSL (HTTPS) is available to protect administrative operations from certain
"active wiretapper" attacks.
The servlet sandbox protects the system from the potential danger posed by new
servlets, whether supplied by third parties or developed on-site. By default, all servlets are
untrusted. The Security Manager does not allow servlets to access network services or
local files. A servlet which has been delivered in a signed Java Archive (JAR) file may be
trusted and granted more privileges by the Security Manager. A digital signature on
executable code means that the source organization "vouches for it" to some extent. It is
no longer expected that servlets will be delivered unsigned, and if unsigned servlets are
installed the system may grant them arbitrary privileges.
Extension APIs in scripting languages or other languages like C can't support low
level access controls even if they do allow digital signatures. Extensions built with 100
percent Pure Java can be prevented from maliciously altering data. So Java has a
competitive advantage. An administrator needs to manage the security features for:
Realms
Access control lists
Servlet sandbox
Secure Sockets Layer
The Users web page gives the administrator a choice of realms, each with different
security privileges. The page allows users to be added, edited, or deleted from the realms.
The users in a particular realm, for example adminRealm, can be listed. Once you have
created a list of users, you can control their access using the Access Control web page.
Access control lists allow control on access to particular web pages. ACLs may also be
used by servlets. Users may be granted permission to GET a web page, or to POST from
data to a servlet. The servlet sandbox is analogous to the applet sandbox used by web
browsers.

Page 258 Go To INDEX


Server administrative tools are set up to recognize digitally signed JAR files. The
Secure Sockets Layer provides three services:
Integrity protection
Authentication
Confidentiality
Integrity protection is the prevention of undetected changes to data as it is
exchanged between clients and servers. The normal situation in SSL is that servers
authenticate themselves, and clients do not need to do so. When a peer at the other end
of a socket connection authenticates, its chain of X.509 public key certificates is presented
to an object implementing the TrustDecider API. The object is placed in the
AuthenticationContext. Some classes support secure storage of private keys, using
encryption to ensure confidentiality. The most basic class is KeyStore, which defines the
format of the storage.

• Java servlets
JavaSoft has made available for immediate download the Java Servlet Developers
Kit (JSDK). The Servlet API provides a simple flexible platform for writing the server side
of a web-based application. This API is consistent across web servers. The Java Servlet
API is officially a Standard Java Extension API. This means that while it is not currently
part of the core Java framework, it will be made available as an add-on package.
Implementations are available for other popular web servers, such as Apache, Stronghold,
Netscape servers and Microsoft's IIS.
One of the major performance features of servlets is that they do not require the
creation of a new process for each request. Many servlets run in parallel within the same
process as the server. Java servlets offer the best performance, better than C, regular CGI
(Common Gateway Interface), and Fast-CGI. Servlets require only light-weight thread
context switches.
In other words, servlets can handle many client requests each time they are
initialized, and spread the costs of that initialization over many methods. The client
requests to that service can share data and communications resources, benefiting more
from system caches. Servlets used with HTTP have a significant performance advantage
over the C language and over both the regular Common Gateway Interface (CGI) and
Fast-CGI approaches. Regular CGI requires heavy weight process startup and
initialization on each request. Fast-CGI still involves heavy duty process context switching
on each request. Taking advantage of the flexible Java Server architecture, the server
divides up its work among several specialized core servlets:
File Servlet
Invoker Servlet
Server Side Include Servlet
Admin Servlet
CGI Servlet
Imagemap Servlet

Page 259 Go To INDEX


The File servlet makes available the standard document serving capabilities of Java
Server. It includes a caching mechanism to speed up accessing of frequently-used files. It
also recognizes files destined for the Server Side Include servlet and passes them on. The
Invoker servlet invokes other servlets that are specifically requested in a URL. The Server
Side Include (SSInclude) servlet handles the embedding of servlets within HTML
documents. A file with an .shtml extension is parsed for a servlet tag when the server
writes it out to the client.
The servlet tag identifies the servlet and supplies name value pairs. The server
loads the servlet, invokes it, and sends the output to the client at the point where the
servlet tag was embedded. The Admin servlet allows administration of the Java Server
through a GUI front end. The CGI servlet permits any program that utilizes the CGI 1.1
standard to operate under Java Server. Hence it is a gateway for the CGI 1.1 interface.
The Imagemap servlet facilitates server-side imagemaps, using an extension of standard
NCSA mapfiles. Text-only browsers are presented with a menu of links when an
imagemap is presented. An optional double-quoted string can be added to the end of each
line in the imagemap file.
This string is used as a descriptive string in the menu generated for text-only
browsers. Let's briefly look at the life cycle of a servlet, from loading to shutdown. Servlets
may be loaded from remote directories as easily as from the local file system. While
servlets are always dynamically loaded, an administrative option is usually provided by the
server to force sharing or particular mappings. The server administrator could decide
always to map certain kinds of client request to one servlet, for instance one which talks to
a particular database.
The administrator could specify that part of the client request must be the name of
the servlet's as found in a servlets directory shared between servers. Servlets can be
configured to filter the output of other servlets. Properly authorized clients can just specify
which servlet is to be invoked, without administrative intervention. Servlets are activated
by the server through an init call. Servlet writers may wish to implement their own init calls,
to remove initialization from later requests, and ensure access to files and network
services. After initialization, servlets can handle many requests if asked.
Each client request generates one service call to the servlet, using service(). The
service method has two arguments, the request to the servlet and the response from the
servlet. A ServletException and IOException can be trapped. Servlet requests can be
concurrent, allowing servlets to coordinate activities among many clients. Finally, the
servlet is explicitly shut down by the web server, by calling the destroy method. The
servlet's class may then become eligible for garbage collection. Now let's review typical
applications of servlets. Two important groupings are:
HTML-aware servlets
HTTP-specific servlets
Many servlets will directly generate HTML-formatted text. A scripting language is
not needed for servlets to generate HTML. It is easy to do with standard internationalized
Java formatted classes such as java.io.PrintWriter.
Web pages can be preprocessed using SSInclude core servlet functionality and
.shtml files. The servlet tag in an shtml file can be used to insert formatted data. Examples
of this could include survey data, customer responses to an online magazine, or the output

Page 260 Go To INDEX


of a web or database search. HTTP-specific servlets may support any HTTP method, such
as GET, POST, and HEAD. These servlets can redirect requests to other locations and
pass on HTTP error messages. They can get access to parameters passed through
standard HTML forms, including the HTTP method to be performed and the URL.
Applications can include processing purchase orders with credit card data as part of an
order entry and inventory database system.
It is possible to exploit the power of servlets to handle multiple requests
concurrently in collaborative applications such as online conferencing. By defining a
community of active agents, it is feasible to share work by passing data. Servlets can
forward requests to other servers, to partition a service by type of task or customer. Java
servlets are a vital part of web-based applications. Many organizations use multi-tier
applications. Three-tier applications include many servers (the standard client/server
model is two tier), where the servers exchange data between each other. The first tier
could include any number of Java-enabled browsers. The second tier of the model
consists of servlets, which incorporate the particular business rules and logic of the
application.
The third tier is comprised of data repositories and is accessed using relational
database interfaces. A final example of a servlet application could be a web publishing
system. An enterprise could possess a large collection of historical and current data,
perhaps sales figures covering a wide geographical area. The data needs to be presented
in easily understood formats, in response to current applications for the data.

• Mainframe issues
Java offers solutions that fit into an environment where mainframes and machines
from different vendors still perform vital functions. The features of Java that offer
significant advantages are:
Thin-client functionality
Network-centric focus
Central server upgrade
Platform independence
Security and reliability
The thin-client approach is the opposite of full desktop functionality. In place of a
platform-specific client requiring many megabytes of hard disk memory, a thin client
requires connection to a server for its functionality. The network-centric concept means
that Java applications, which are developed in modules, can be delivered over the network
as functions are required. This is economical and efficient for the user. With network-
centric computing, you can simply upgrade the software on the server. This saves having
to upgrade every single user client.
In a sense, this represents a return to the centralized model of the mainframe era.
As you know, Java is inherently a multi-platform programming language. The Java Virtual
Machine (JVM) converts byte code, on-the-fly, to the correct binary for whatever machine
it is running on. Java's security features and reliability are important advantages. Software
protection mechanisms, including encryption and authentication, build confidence for

Page 261 Go To INDEX


future applications. The reliability of Java in maintaining connections is a great
improvement over static HTML, which requires constant reconnection.
To permit Java to connect with the range of different vendors' naming services, it
was necessary to create a special Java interface. Let's now look at JNDI, the Java Naming
and Directory Interface. JNDI enables seamless connectivity to heterogeneous company
naming and directory services. With JNDI, Java applications can store and retrieve named
Java objects of any kind. JNDI provides methods for performing standard directory
operations, such as searching for objects using their attributes, and associating attributes
with objects.
Different naming and directory service providers can be plugged in seamlessly
behind the common API of JNDI. Java applications can thus take advantage of information
in a variety of legacy applications and systems. Examples of other directory and naming
services that can coexist with JNDI include LDAP, NIS (YP), NDS, and DNS. One
application of Java is to make available real-time business data such as stock prices and
company results.
Raw data can be gathered from many data sources, sent across the Internet, and
viewed using appropriate graphics. An example is being able to locate numerical rows and
columns, manipulate them in a familiar spreadsheet format, and then model various
business scenarios. Applix, Inc. has produced the Anyware product, which does just that.
Many banking and insurance companies are actively considering Java to implement future
online customer transactions.
Corel Corporation has launched its Corel Office for Java product. This offers a word
processor, spreadsheet, and extensive business graphics. Corel developers have
exploited Java's cross-platform capabilities and portability. Users of Corel Office for Java
can pick and choose the features they wish to download. The accessing of databases via
multi-megabyte, platform-specific clients has now been recognized as problematic in
terms of ease and flexibility, and costly for the organization in terms of software
maintenance.
There is a need to integrate database access into the expanding Internet and
corporate intranets. One company addressing the database access issue with Java is
Infospace, Inc. Infospace came up with a 3D business graphics package based on Java-
named WebCharts. Their SpaceSQL product became the first thin-client database access
tool for the Web, written entirely in Java.
Once downloaded, the SpaceSQL client runs inside the browser, independently of
the server. The idea of being able to make travel reservations from any desktop or laptop
computer is no longer a dream. Via World Network is launching a Java-based product
offering desktop travel planning and booking.
Via cites Java's overall reliability, platform-independence, and object-oriented
design as major factors in choosing Java. Mainframes, particularly those reliant on IBM's
Systems Network Architecture (SNA), have played an important role in corporate
computing for many years. Core business data, including a wide range of data
warehousing, database, and related data-intensive applications, often reside on
mainframe and midrange SNA systems. The issue is how to incorporate these critical
legacy systems into web-based client/servers.

Page 262 Go To INDEX


OpenConnect Systems, Inc. is leading the way in giving legacy systems a whole
new lease of life. Their product OC://WebConnect became the first Java-based SNA host
access solution on the market. The product gives web-connected users access to the
wealth of mission-critical data generally handled by mainframes.
An advanced product OC://WebConnect Gold was also introduced to tackle
security issues. The Gold product ensures a secure mainframe-to-desktop connection at
the key levels in the protocol architecture. The competitive advantages of secure
mainframe access are obvious. The focus is shifting away from both the mainframe and
the desktop. Transparent information access via the network is the way forward. This is
expected to yield large savings in software distribution and help-desk costs.
The integration of the Web with existing legacy systems offers exciting new
applications.

Page 263 Go To INDEX


9
JavaBeans
9.1. Components

• Overview of JavaBeans
An important aim of any modern programming language is to have the ability to
reuse previously developed software components. If you reuse software, it reduces
development time and cost while increasing flexibility. You can more easily standardize
the user interface by using common, reused components. You can purchase software
from third-party vendors, in forms such as tool kits, and integrate it with your own software.
A component architecture model for a language specifies how components are
built, customized, and used. JavaBeans is Java's component architecture model. The
software components are called "Java beans", or simply "beans", while the model is called
"JavaBeans". The emphasis during the design of JavaBeans was on the smaller software
components likely to be distributed over networks.
But JavaBeans also supports much larger software applications. Java beans can
be GUI widgets, non-visual functions or services, or larger applications. While you will find
small, lightweight beans easy to build and use, larger beans are also possible. JavaBeans
was designed to be simple to use, so you can develop and use beans manually, although
you will probably use a visual builder tool instead.
Many new features introduced in JDK 1.1 are used by JavaBeans, such as event
handling, JAR files, remote method invocation (RMI), reflection, and serialization. You only
need to understand the Java language and the JavaBeans API before being able to
develop beans. In keeping with the Java philosophy, JavaBeans is a platform-independent
component architecture model.
Java beans are portable across multiple platforms, just like complete Java
applications. An important feature of beans is that you can manipulate them using
sophisticated, visual programming tools. This is because the JavaBeans API specification
was developed in tandem with many leading builder tool vendors. Individual beans can be
built, customized, and integrated with other beans and Java applications using these tools.
JavaBeans is compatible with existing component architectures, like:
IBM and Apple's OpenDoc
Microsoft'sActiveX/OLE/COM
Netscape's LiveConnect
OMG's (Object ManagementGroup's) CORBA
JavaBeans' APIs link to these platform-specific component architectures through
bridges developed and supported by JavaSoft's industry partners. Java beans are subject
to the same sandbox security model as normal Java applets or applications. This means
that beans that are part of untrusted applets cannot access files on the user's hard disk or
arbitrary network hosts. However, beans that are a part of a trusted applet, or a stand-

Page 264 Go To INDEX


alone application, will have access to files and other network hosts in the usual way. Java
beans were designed to run well in a network environment. Java's Remote Method
Invocation API will allow distributed Java applications, including beans, to communicate
over a network.
Java beans can utilize Java IDL and IIOP, which is an implementation of the Object
Management Group's (OMG's) industry standard CORBA distributed object model. And
beans can use Java's Database Connectivity API (JDBC) to access remote SQL
databases. Although you write a Java bean like any other Java program, it will have
several unique features. These features allow beans to:
Be customized by you at design time
Maintain their customized state, using serialization
Interact with other beans, using events
Be manipulated visually by builder tools
Every Java bean has properties that determine its appearance, state, and behavior.
Properties can include a bean's color, size, or labels, and various internal states too. You
can customize a bean through the modification of its properties in a variety of ways:
Through a scripting language, such as JavaScript
Through get and set methods defined in the bean
Using property sheets provided by a builder tool
Using specially written customization code that is runt design time
Bean developers can provide specialized customization code that is run at design
time inside a visual tool. In some cases, the customization code for a bean may even be
larger than the bean itself. Java separates the customization code from the bean code to
improve download efficiency at run time. Java beans fire events to interact with other
beans or Java code. The JDK 1.1 delegation event model is used for defining event
handling in JavaBeans.
When a bean fires events, it results in method invocations in registered event
listeners. Beans that implement event listener interfaces can be registered to receive
events from other Java program elements. Beans must make their events, methods, and
properties available at design and run times to builder tools and other Java components.
The process of revealing the methods, events, and properties of a bean is called
introspection (or reflection).
There is a default introspection mechanism available using standard design
patterns, or naming conventions. Alternatively, beans can publicize their behavior explicitly
using a special BeanInfo class. Java beans need to be able to save their edited states
across different platforms. The automatic Java serialization mechanism allows beans to
persist over time. Beans can, alternatively, use an external stream mechanism that allows
them to have full control over the resulting data layout.

• Persistence and Packaging

Page 265 Go To INDEX


If you customize a Java bean's appearance and behavior, you will want to have
those changed properties stored in a non-volatile location for later retrieval. Persistence is
the storing of a bean's internal, customized state for later retrieval. The stored state is said
to be a bean prototype. Bean prototypes are also platform-independent in the same way
that beans are platform-independent. Java beans can be stored across a wide range of
data formats, including existing industry standard formats such as OLE or OpenDoc.
The state of a stored bean is relative to its container type, so Java beans are often
stored as a component of a larger non-Java parent container. For example, a bean could
be stored as an Excel document embedded in a Word document. Java beans can choose
to use the automatic Java serialization mechanism, which provides a method of storing out
and restoring Java objects.
Java uses a hash algorithm that produces a 20-byte serial number of the data fields
and methods. The serial number is like a "fingerprint" that uniquely identifies the stored
object. Objects to be saved automatically must implement the java.io.Serializable
interface. You do not have to do anything else in order to save the bean after
implementing this interface. In general, a Java bean will save all its public properties and
the internal states necessary to retain its customized appearance and behavior.
You must mark the object fields that are not persistent with the "transient" keyword.
Fields that should be marked transient will include any references to other beans within a
container or event listeners. It is the responsibility of the container itself to track and
restore these transient references and connections. Static variables will also not be saved.
You can implement a writeObject method in the bean to control what information is
saved, or to append additional information to the stream. Then you can write a readObject
method to read the information written by the corresponding writeObject method.
Serialized objects are saved as ser files.
When you alter or recode the bean, the stored prototype may or may not persist,
depending on the type of change you initiate. You do not affect a prototype when you:
Add new fields to the bean
Add references to classes
Remove references to classes
Change a field's access modifiers
You will change the bean prototype if you:
Delete fields from the bean
Change a variable's position in the class hierarchy
Change a field's transient or static status
Change a field's data type
You package a Java bean into a single, compressed file together with its related
images, help files, .ser prototypes, and classes. The packaged bean is then ready for use
by builder tools, containers, and applications. Packaging is based both on the object
serialization API and Java archiving (JAR) files, both introduced with JDK 1.1. JAR files
collect together groups of related Java files in a compressed, zipped format. The

Page 266 Go To INDEX


compressed JAR file is much smaller, so has the advantage of optimizing transmission
over networks.
JAR files also simplify the packaging and unpackaging of beans because all related
files are kept in one place. Several beans can be collected into a single JAR file if
required. A JAR file usually contains a manifest file that describes the contents of the JAR
file, in such a way that all the beans can be listed and individual beans can be retrieved.
Beans should follow the standard naming conventions for packages and classes. If no
manifest file is present, then all class and ser files are assumed to be beans.
The JAR file has a set of class files that define the bean's or beans' behavior, and
optional ser files that provide customized state information. Additionally, each bean has:
An optional help file in HTML format
Optional internationalization information
Other related files, such as images and sound

• Event Handling
Beans use events to communicate with other components or beans. For visual
beans, events occur when a user interacts with the bean by, for example, clicking a mouse
button, entering text, or pressing a key. But non-visual beans can also use events to
interact with other software components in an application or applet. JavaBeans uses the
JDK 1.1 delegation event handling model.
Event sources fire events at registered listeners. The system invokes methods in
the listeners that match the event types being fired. Events and their relevant information
are represented as Java objects, and are all descended from java.util.EventObject. You
can create new event types by extending java.util.EventObject, or one of its descendants.
Each Java event has a corresponding listener method defined for it. Groups of
logically related listener methods are gathered into listener interfaces. For example,
mouse-generated event methods are collected into the MouseEventListener interface.
Listeners implement a listener interface and are then registered on a bean to receive
event notifications. Multiple listeners may be registered to listen for the same event from
the same source - called multicast delivery.
How a particular Java VM handles multicasting is implementation-dependent, so
you cannot make any assumptions about the order that event listeners handle events.
Beans can be both a source and the recipient of events. The events that a bean fires or
listens to must be discoverable by external builder tools.
The tool, at design time, must be able to modify events and the relationships
defined between event sources and event listeners. You can use adapters to interpose
between a source and a listener or set of listeners. Adapters are extremely useful in
JavaBeans because they:
Add greatly to the flexibility of the model
Can help separate a GUI from application logic
Can simplify event handling tasks
Adapters can queue events for delivery to multiple listeners in a non-standard way.
Adapters, for example, might queue event handling by multiple listeners in a strictly

Page 267 Go To INDEX


ordered fashion, rather than relying on the particular Java implementation. Alternatively,
adapters can de-multiplex multiple event sources onto a single listener. De-multiplexing
means to channel many sources onto a single listener, with each source causing a
different method call on the target listener. Adapters can be designed to augment the
information about an event, or the behavior of an event. Unwanted events can be
selectively filtered by adapters for efficiency reasons. Also, adapters can be used to
choose an appropriate listener from among a larger set to handle the event.
A standard event handling method will receive only a single parameter - an object
of the event type. However, you may construct events to suit the requirements of an
external, non-Java target environment. In this case, the event handling method may
contain an arbitrary parameter list. Visual builder tools should be flexible enough to handle
such exceptional situations.

9.2. Working with Components

• Properties
Reusable components, or beans, do not have all their behavior and appearance
determined once and for all when they are created. Beans are flexible enough to allow
their basic behavior and appearance to be modifiable by a bean user. The attributes of a
bean that determine its modifiable behavior or appearance are called properties.
Properties are discrete, named attributes. Properties can be modified by a user in a variety
of ways. They might be modified through a scripting language. Or they might be presented
in a builder tool's property editor.
In fact, regardless of the medium through which a property is edited, it is eventually
changed through calls to its accessor methods. Accessor methods are responsible for
getting or setting the value of a property. All readable properties have a getter method of
the form:
public PropertyType getPropertyName ();
This form is the standard design pattern for properties. Design patterns are
standard naming conventions used to declare properties, methods, or events for automatic
discovery. All writable properties, or modifiable properties, have a setter method of the
form:
public void setPropertyName (PropertyType p);
Any property which has both a getter and a setter accessor method is a read-write
property. Accessor methods defined according to a design pattern enable automatic
introspection of a bean's properties. Properties do not just have to be simple values. Since
the properties are changed by the bean itself, the property can be quite complex.
Properties can be any Java primitive type, Java class, or array. Java supports indexed
properties, where the value is specified by using an int integer value.
Indexed properties have different design patterns to the other property types. Getter
accessor methods for indexed properties are of the form:
public PropertyItem getPropertyName (int i);
Setter accessor methods for indexed properties are of the form:
public void setPropertyName (int i, PropertyItem p);

Page 268 Go To INDEX


Boolean properties support a different getter accessor method, in addition to the
normal form. This additional design pattern is of the form:
public boolean isPropertyName ();
Alternatively, boolean properties may just have the normal getter method form.
Let's see an example of a simple property and how it is accessed and modified. Imagine
you have bought a bean that displays personnel details in an attractive format. You may
want to use the bean to speed up the writing of an application that allows managers to
browse through employee records. Let's imagine that the bean will display an image file of
each employee if the bean's Displayable property is set to true.
The way to set the Displayable property to true is to call the bean's setter accessor
method for the Displayable property. This call will be:
PersonBean.setDisplayable (true);
And to prevent images being displayed you would use:
PersonBean.setDisplayable (false);
You can test the status of the property using this sample method invocation:
boolean viewable = isDisplayable ();
There are more complex property types available for the advanced beans user.
Firstly, bound properties notify other components of any changes that they undergo. They
are said to be bound to that other component. If you modify a bound property, then that
change is notified to other registered listener components using PropertyChangeEvent
events. PropertyChangeEvent events contain the property name, along with its old and
new values. Bound property listeners implement the PropertyChangeListener interface.
The bean notifies the property's registered listeners after the change has been made by
invoking their propertyChange method and passing a PropertyChangeEvent. The Java
API contains a PropertyChangeSupport class for convenient programming of bound
properties.
Constrained properties are properties that undergo validation by another software
component when changed. The attempted change may be vetoed by the listener, so the
property should notify the listener of the change before modifying the property value. This
veto is notified to the property's bean through a PropertyVetoException exception. Setter
methods for constrained properties must allow a PropertyVetoException exception to be
thrown.
Components listening for changes to constrained properties must implement the
VetoableChangeListener interface.
The listener throws a PropertyVetoException exception if it disapproves of the
property change. The setter accessor method, when it receives a veto from a listener, may
take some appropriate action to change the value and renotify the listener. A handy
VetoableChangeSupport class will track constrained properties, listeners, and exceptions.
Some properties may be both bound and constrained. In this case, the bean should
have the change validated by the constrained listener before notifying any bound listeners.
But when a property's new value is equal to its old value, you should not call any listeners
for that change.

Page 269 Go To INDEX


• Introspection
You must be able to discover a reusable software component's behavior and
appearance. For example, builder tools at design time will need to be able to discover a
bean's properties, events, and methods automatically. This process of automatic discovery
is called introspection. JavaBeans provides a low-level reflection mechanism for
discovering all of a bean's, variables, methods, and interfaces.
This low-level reflection is, in turn, used by a higher-level introspection mechanism.
Both the reflection and introspection facilities are written as Java APIs, so a beans
developer needs no additional scripting language or specification mechanism in order to
publicize a bean's behavior. JavaBeans supports a simple specification mechanism for
smaller beans, using design patterns. Design patterns are naming conventions that
declare a property, method, or event to an introspector.
All properties, events, and methods that a bean developer wants to expose are
declared according to a standard design pattern. An introspecting program can reconstruct
all of a bean's important elements by extracting information supplied with declarations. A
property's type is discovered through the return type of its getter accessor method. For
example, the property called listLength is of type int and this can be discovered by
examining the return type of its getter method.

Properties are discovered when an introspector finds get and set accessor
methods.An introspector might find a write-only property with just a set method, a read-
only property with a get method, or a read-write property with a pair of get and set
methods. Events can be introspected successfully when pairs of "add listener" and
"remove listener" methods are found.

All public methods in beans are assumed to be accessible to external software


components. There is another, more complex, option for providing information about a
bean. You can provide explicit information using a special BeanInfo class provided with
the bean.
A BeanInfo class does not necessarily have to supply all relevant information about
a bean. It may provide some explicit information, and then allow the rest to be introspected
using design patterns. Java has an Introspector class that can analyze a bean, even if it
has mixed BeanInfo and design patterns.
The java.beans.Introspector class analyzes a bean class in a rigorous fashion.
Firstly, it checks the bean for a matching BeanInfo class, which will be of the form
BeanNameBeanInfo and which implements the java.beans.BeanInfo interface. If one is
found, then all its information is extracted. If one is not found, then low-level reflection is
used to introspect elements written according to the design patterns.
Once a bean's class has been introspected successfully, the Introspector proceeds
to introspecting its base class, and so on up the hierarchy. This mechanism ensures that
beans that are subclassed from other beans will still inherit explicit information from the

Page 270 Go To INDEX


original class. Bean users can extend beans from an independent software vendor (ISV),
and assume that the Introspector will retrieve all relevant properties, methods, and events.
Property and event names will follow the standard Java conventions. The Introspector will
automatically apply these naming conventions to event and property names extracted by
the reflection API.

• Customization
When you buy a bean from an independent software vendor (ISV), that bean will
probably not do exactly as you want. The ISV will have given the bean default, generic
behavior and appearance. But the bean will be flexible enough for you to adapt it to your
precise requirements. The process of modifying a bean's default behavior is called
customization. You have seen how beans have properties, and how those properties can
be introspected by external software, especially builder tools. Properties and introspection
allow beans to be customized. That customized state of a bean can then be stored using
serialization or some other persistence mechanism.
You can modify bean properties in a variety of ways, depending on the builder tool
you use and the bean itself. Normally, the bean will export a set of properties which your
builder tool will present as a user-friendly property sheet and editor. You will use the
property sheet to examine the bean's properties and then open the editor to modify
property values. Another way you may change property values is through a scripting
language environment. The scripting environment may be executing the bean alongside
other software components, perhaps in a browser.
You will adjust a bean's property values by assigning new values in explicit
statements in the scripting language. Whether you customize the bean in a builder tool at
design time or through a scripting language at run time, it will result in calls to the
property's getter and setter methods. Property editors are classes that allow the editing of
properties, and can range from very simple to quite sophisticated. The simplest property
editors might only allow the reading and writing of a string value representing the value of
a property.
More sophisticated editors may be GUI AWT components. Property editors can
come from a variety of sources:
With the standard JavaBeans API
As part of a larger JavaBeans toolkit
From the ISV supplying the bean
With an application builder tool
Each property must be linked to a property editor that matches its data type. All the
primitive Java types are supplied with default property editors as part of the JavaBeans
API. Additionally, the JavaBeans API also supplies property editors for the classes:
java.lang.String
java.awt.Color
java.awt.Font
Property sheets and scripts will work best for smaller beans. If you want to
customize larger beans, then Java allows the ISV to provide a specialized customization

Page 271 Go To INDEX


class along with the bean. This specialized customization class, or customizer, will be an
AWT component that guides you through bean customization. All customizers will inherit
from java.awt.Component, so will have a Java GUI interface. Normally, a customizer will
constantly update a bean's appearance as you select customization options.
Customizers give bean developers great flexibility in choosing how to let users edit
beans. Invisible beans are beans that have no GUI appearance of their own when run.
They may form a smaller section of a larger application, or be a server-side program. But
invisible beans may still have customizable properties. These properties can be
customized in the standard way, using a GUI customizer or property editor.

9.3. Creating and using beans

• Using the BeanBox


Java beans are intended to be manipulated at design time. So, you will need to
customize and integrate them with other beans, before they are serialized for later use.
You will typically test, customize, and integrate beans in a visual tool environment. The
JavaBeans Development Kit (BDK), which you will use with JDK 1.1, contains a test
container called BeanBox. The BeanBox is a simple, Java-written, test environment for
beans. It allows you to manipulate your beans visually, edit properties, connect beans
together, and save their customized states. The BeanBox consists of:
A ToolBox area for displaying the names of available beans
A BeanBox area for displaying and testing sample beans
A PropertySheet for editing selected bean properties

Page 272 Go To INDEX


The PropertySheet window presents the selected item's properties for editing. In
this case, the name of the panel in the BeanBox is panel1, which you will want to change.
Here you see the name changed to "Test Bean".

The BeanBox window contains a File option for:


Saving beans
Serializing customized beans
Loading beans
Loading JAR files
Clearing the window
Exiting
The Edit menu contains options for:
Deleting beans
Copying beans
Pasting beans
Producing an introspection report
Attaching events to another component
The View menu contains switches that:
Switch between design mode and execute mode
Hide or show invisible beans
Let's see how to use the BeanBox, toolbox, and property sheet with a sample bean.
This bean is called TestBean and consists of a movable blob, either a square or a circle,
within a larger rectangle. Its properties are the shape of the inner blob, the background
and foreground colors, and the size of step taken by the blob in pixels. The TestBean
bean appears in the ToolBox window, with other available beans. The beans have been
loaded from JAR files in a default directory, when the BeanBox was started.

Page 273 Go To INDEX


You click the bean name with the mouse pointer, and drag it to the desired position
on the BeanBox window. Then you click the mouse button to place the bean. Here, you
have placed the bean onto the BeanBox window for testing.

And the bean is highlighted with a black-and-white border in the BeanBox window
to show that it is selected. The property sheet automatically shows the new bean's
properties. Let's edit some of the bean's properties now.

You can change the stepSize of the blob, in pixels. This stepSize property dictates
how many pixels up, down, or sideways that the blob will shift each time it is requested to
move. The stepSize has been set to 5. Colors are represented in the property sheet by a
colored block.

Page 274 Go To INDEX


You click inside this block to call up the color editor. In this case, the editor is the
standard editor for colors, sun.beans.editors.ColorEditor. Colors can be chosen by
entering a triple-value color code, or by choosing from a preset list of colors. You click the
down-point arrow to reveal the drop-down list of default colors. You then choose a new
color, in this case green, and click the Done button to select it.

You can see that the foreground color of our bean has been changed dynamically
in the BeanBox to green.

The shape displayed, or blobType, can be either a square or a circle. Let's choose
to use a circle.

Page 275 Go To INDEX


Again, the change to a property has been dynamically reflected in the BeanBox
display of the TestBean. All of the properties of TestBean are defined as bound properties.
This means that any changes to their values can be signaled to another component. The
listener component is a bean called TestWatcher, and you simply add this property
change listener bean to the BeanBox below our TestBean.

The TestWatcher bean, labeled "Watcher Bean", is represented by a yellow colored


box at the bottom of the screen. Now you must connect property change events to the
TestWatcher bean. You start by clicking it with the mouse pointer. Then select the:
Edit menu
Events submenu
propertyChange submenu
propertyChange option
Choosing an event produces a red line running from the event source to the mouse
pointer. You simply place the pointer over the target bean and click to select it. This
displays an EventTargetDialog box, which lists all the available methods in the target
bean. In this example, you choose the flipColor method and click OK. You will see a
message for a few seconds saying that the BeanBox is generating and compiling an
adaptor class. The EventTargetDialog box has constructed an adaptor class for the
TestBean to TestWatcher connection, which will operate immediately. If you now change
stepSize from 5 to 6, for example, the TestWatcher bean flips color from yellow to blue to
signal that it has received a property change event. Now let's add buttons to the BeanBox
window that will be used to control the movements of the blob inside the TestBean. You

Page 276 Go To INDEX


select a bean from the ToolBox window in the normal way and drop it into position on the
BeanBox window.
In this case, you have selected an OurButton bean and placed it above your
TestBean. It has the default label of "press", which you will want to change to "Up". You
need to add a further three buttons to the BeanBox window, labeled "Left", "Right", and
"Down". You need to connect each button to the appropriate method in TestBean, using
the event handling mechanism.
The central box is moved by four different methods, which can be activated by
external beans firing events. You start by selecting the button that you want to connect. In
this case, it is the "Right" button.

You then select the:


Edit menu
Events submenu
Action submenu
ActionPerformedoption
You then place the mouse pointer over the TestBean and click. You will see the
EventTargetDialog box appear again, this time listing the methods of TestBean.

Page 277 Go To INDEX


To move the blob to the right, you must select the incrementXPosition method and
click OK. This method will be invoked whenever an action event occurs in the button
labeled "Right". The BeanBox generates and compiles the adaptor class to handle the
new event. Clicking the "Right" button during design time results in the TestBean moving
the blob to the right, so you can immediately see the effect of any changes you make.

You go through the same procedure for each of the other buttons, except that a
different method in TestBean is called depending on where you want the blob to move. If
you want to prevent the stepSize from being changed to an invalid value, one way to do it
is to use constrained properties.
The TestWatcher bean has been designed to veto changes to the stepSize value of
less than 1 or greater than 10. You select vetoableChange from the Events menu, and
connect the event to the TestWatcher bean in the normal way. The TestWatcher bean
contains a method called vetoableChange for handling attempted value changes to
stepSize. If you attempt to alter the stepSize value to 65, for example, the TestWatcher
bean displays a warning message and the change is vetoed.
The stepSize will remain at its original value until it is changed to a value within the
range 1-10. Finally, you have a set of running beans, which are connected together
through events. You can disable design mode to more easily view the running beans. The
ToolBox and PropertySheet windows disappear, as do the highlighting surrounds around
beans.

You also have the option to hide any invisible beans you may have been editing.

Page 278 Go To INDEX


• Creating a simple bean
Let's look at the Java code that produced our TestBean demonstration. The main
class is the TestBean class itself. It contains all the getter and setter accessor methods for
its properties, a paint method for drawing itself, code for moving the blob around the
rectangle, and code for adding and removing event listeners. The TestWatcher is the bean
that monitors the property changes occurring in TestBean during design time.
The other classes are BlobTypeEditor for providing the property sheet with the
means to edit the blob shape, and TestBeanInfo which provides standard property
information. The first thing to notice is that you must place the TestBean class inside a
package beginning sunw.demo, in order for it to run in the BeanBox.

In this case, it is placed in sunw.demo.TestBeans. Secondly, you must import the


java.beans package, because it contains the beans API's that you will require to write the
bean. Your bean is a normal extension to an AWT component, in this case Canvas. You
implement the java.io.Serializable interface to allow the customized state of your bean to
be saved away. That is all you need to do in order for a standard bean to be saved away
in a serialized form. Static and transient variables will not be serialized. Here, the
coordinates determining the position of the blob, and the size of the blob, will always be
the same for all instances of the bean.
In effect, the position of the blob is always going to be set to (0,0), and the size of
the block will always be 20x20 pixels. These variables, for the step size and the type of
blob, will be serializable. If your bean supports bound properties, then you should add this
class as a member, passing the bean itself as a parameter to the constructor. When
signaling changes later, you delegate this class the responsibility of doing the work. It
maintains a Vector of property change listeners for the bean. This is TestBean's
constructor.

Page 279 Go To INDEX


It initializes its property values when first instantiated in the design environment.
However, the constructor is not run when reading in serialized beans, since they will have
changed property values. The TestBean bean is limited to a size of 100x100 pixels. This is
the paint method for the bean, which is called by the repaint method for all changes.

A rectangle, a horizontal, and a vertical line, are all drawn first. Then a blob of the
right type, size, and position is drawn. These are the methods for moving the blob inside
the rectangle.

Page 280 Go To INDEX


Each is written in essentially the same way:
Adding (or subtracting) the stepSize
Checking for boundaries
Invoking the repaintmethod
Here are the getter and setter accessor methods for the stepSize property.

This pair of methods, conforming to the design pattern for properties, informs the
introspector that the property exists and is of type int. The getter accessor method simply
returns the value of the stepSize variable, but the setter method is much more
complicated. The stepSize property is both a bound property and a constrained property.
This means that you must
Signal the event to any vetoable changelisteners

Page 281 Go To INDEX


Change the value, but only if there is move to exception
Signal the event to any property changelisteners
The vetoable change listeners will throw an exception, which interrupts the
method's execution before reaching the point in the code where it changes the value.
These are the setter and getter accessor methods for the blob type.

The remaining code provides support for handling lists of property change and
vetoable change listeners.

There are pairs of addChangeListener and removeChangeListener methods for


both PropertyChange and VetoableChange events.
Each add method simply hands on the new listener for recording by the
propChanges and propVetos objects defined earlier. And each remove method simply
hands on the listener for the propChanges and propVetos objects to delete. The
TestWatcher bean is a simple example of how to implement a property change or vetoable
change listener.

Page 282 Go To INDEX


In reality, the kind of vetoes you will implement are likely to be much more complex,
but the principles remain the same.
Firstly, the bean must implement the VetoableChangeListener interface. Bound
properties in TestBean will invoke the flipColor method as a means of signaling a property
change. Constrained properties will invoke the vetoableChange method.

This method checks that any changes to the stepSize value are in the range 1 to
10. It throws a PropertyVetoException when the range is exceeded. This simple class is
the user-provided class to support property changes to the blobType.

Page 283 Go To INDEX


It is an extension to the PropertyEditorSupport class in java.beans. The getTags
method returns an array of strings that the property editor then assumes are to be
displayed as a list of options.
To provide an icon for your bean, you override the getIcon method, load your
chosen image file, and return it.

You have to provide property descriptors for each property. You must instantiate a
new PropertyDescriptor object, passing the property name as a string, and the bean object
to which it belongs.
In this example, there are property descriptors for background, foreground, font,
stepsize, and blobtype. The blobType property has its own editor, BlobTypeEditor, so we
assign that editor to it explicitly using the setPropertyEditorClass method in
SimpleBeanInfo.

Page 284 Go To INDEX


To declare a property as bound, you use the setBound method from the
PropertyDescriptor class.
The stepSize property is both bound and constrained, so you must signal that with
a setConstrained method too. The property sheet in your visual tool can use these flags to
handle properties in different ways, depending on whether they are bound, constrained,
both bound and constrained, or neither bound or constrained. All the PropertyDescriptor
objects are then returned from the getPropertyDescriptors method as an array.
Finally, the catch block records an error message if an IntrospectionException
occurred while building the PropertyDescriptors.

• Adding new beans to the BeanBox


To add your new bean to the BeanBox window you must first package it into a Java
archive (JAR) file. You can place this JAR file into the default jars directory for automatic
loading by the BeanBox utility at startup. You can, alternatively, explicitly load the JAR file
into BeanBox using the File, LoadJar command.
A JAR file is a standard ZIP archive file. It contains an optional manifest file
describing its contents. The contents will include the class files, optional HTML help files,
and any other data files associated with the bean. Serialized beans, with the .ser
extension, will also be packaged into JAR files. You create a makefile file describing the
contents and then use an appropriate utility to generate the JAR file.
For a Win32 system, the makefiles have the .mk extension and you use the
Microsoft nmake utility. For a Unix system, the makefiles have the .gmk extension and you

Page 285 Go To INDEX


can use the gnumake utility. The BDK demo directory, created when you install the BDK,
contains several examples of .mk and .gmk makefiles that you can edit for your own
purposes. Let's see what a typical makefile looks like.

This is the TestBean makefile, for packaging the TestBean, TestBeanInfo, and
BlobTypeEditor classes together with the .PNG icon file.

The TestBeanWatcher bean is packaged into another JAR file of its own.
First, you must specify the names of the Java classes to be included in the JAR.
Next, you specify the additional data files to be included. The only datafile for TestBean is
the icon image file, which appears beside the bean name in the ToolBox listing. You
specify the creation of a manifest file describing the contents of the JAR file. And then you
can specify explicitly the name of the bean contained in the JAR file using the Java-Bean:
True command.

You should be careful to follow this layout for your makefile in order for it to be
processed correctly. You are advised to use one of the existing makefiles that come with
the BDK, and to edit it for your own beans.

Page 286 Go To INDEX


10
Java Database Connectivity
10.1. Overview of JDBC

• Introduction to JDBC
JDBC (Java Database Connectivity) is a Java API for accessing databases. JDBC
is included in JDK 1.1. It consists of a number of classes and interfaces that make it easy
to connect to and query a relational database. Java is ideally suited to this purpose and
the introduction of the JDBC has enhanced its capability. JDBC is an attempt to define a
generic SQL database access framework. The framework provides a uniform interface on
top of a variety of different database connectivity modules.
JDBC allows you to write to a single database interface. It enables DBMS-
independent Java application development tools and products. It also allows database
connectivity vendors to provide a variety of different connectivity solutions. JDBC is a low-
level API that supports basic SQL functionality. It was designed to let you create higher-
level database access tools and APIs. A popular choice for accessing relational databases
is Microsoft's Open Database Connectivity (ODBC). ODBC is based on the X/Open SQL
Call Level Interface specification. The JDBC API is also based on this specification. The
designers of JDBC took this decision because they could build on knowledge gained using
ODBC and make it more worthwhile for developers to adopt. ODBC is a good basis for
design but is not appropriate for direct use from Java. This is because essentially it is a C
interface. Native method calls from Java to C code affect
Security
Implementation
Portability
Robustness
ODBC offers the ability to talk with most databases on many different platforms. So
why was the ODBC model not adopted instead and the JDBC model shelved?
JDBC is not as difficult to learn as ODBC is. Java has many simple and intuitive
methods as opposed to few, complex commands. Many features such as pointers are
found in C, and correspondingly in ODBC, but are not natural in Java. JDBC implements
the "write once, run anywhere" approach. It doesn't matter what type of database you are
trying to access. JDBC allows you to write one program that will access many major
databases, such as Informix, Sybase, and Oracle.
JDBC is an API that lets you write code that is not dependent on the DBMS or
database connectivity mechanism being used. Of course, your program will also run on
different platforms. So it will not matter if a company has UNIX workstations, PCs, and
Apple Macintoshes all trying to access the same database.
Also with JDBC, installation and version control are greatly simplified. Another
advantage is that the time taken to develop new applications is relatively short. One very

Page 287 Go To INDEX


important use of JDBC is the development of standalone applications. JDBC applications
can provide strong database querying, updating, and managing facilities. This is because
they have total access to file systems and remote servers and can open network
connections. Using Java JDBC applications in this way is particularly useful in the context
of corporate intranet communication. You can use JDBC for developing applets as well as
applications.
For instance, applets could be designed as database access applets which use
JDBC to link to databases. Let's look at the basic series of operations that occur when a
database is accessed and queried using JDBC. First the Java program opens a
connection to the relevant database. Next it makes a statement object. Then it passes
SQL statements to the underlying DBMS through a Statement object, a
PreparedStatement object, or a CallableStatement object.
Finally it retrieves the results as well as the information about the result set. The
classes that allow it to perform these operations are in the java.sql package. However, a
program using JDBC will also need a driver for the data source with which it wants to
interface. Implementations of the following abstract classes provided by the JDBC API
must be also provided by the database driver:
java.sql.Connection
java.sql.Statement
java.sql.CallableStatement
java.sql.PreparedStatement
java.sql.ResultSet
The Java SQL framework allows multiple database drivers. Each driver should
supply a class that implements the interface java.sql.Driver. Upon initialization, the
DriverManager class will try to load as many drivers as it detects.
Then for any given request for connection, it asks each driver to try to connect to
the specific URL. The JDBC driver manager locates drivers and establishes connections.
Programs developed with JDBC communicate with the JDBC driver manager, which in
turn uses the currently active drivers to communicate with the actual database.
When the connection is established, the driver manager steps out of the way. In
general terms, it is better to think of dealing with a data source rather than an actual
database. This is because the form, content, and even location of the data does not matter
to Java once there is a driver for that data. The JDBC management layer needs to know
which database drivers are available for use.
So when a Driver class is loaded, it should create an instance of itself. This
instance will then be registered with the DriverManager. The Class.forName method
allows you to explicitly load a driver class.
Class.forName(“some.db.driver”);
The JDBC driver manager will try to locate a driver that can use the protocol
specified in the database URL.
In this case, the newly loaded driver class must also register itself with the
DriverManager. You do this by calling the registerDriver method in the DriverManager
class. JDBC drivers can be written in Java so they can be downloaded as part of an

Page 288 Go To INDEX


applet. They can also be implemented using native method calls which link up with
existing database access libraries.
However, these types of drivers are limited to applications that exist on the same
host as the database. This is because most browsers won't allow native methods to be
called from within a remotely loaded applet.

• Two-tier JDBC architecture


JDBC supports a two-tier model for accessing databases. The majority of
client/server systems today have been implemented using the two-tier approach. The two-
tier model has gained acceptance because the popular tools that implement it are very
easy to adopt and utilize. A two-tier architecture implemented using JDBC can have a
Java applet or application on a client machine talk directly to a server. There is no
intermediary server. The two-tier model is typically used in small environments (less than
50 users).
In terms of JDBC, the two-tiered approach means that the user interface and
business logic reside on the client workstation. However, the database resides on a
central server. Because there is no intermediary server, a JDBC driver is needed. The
JDBC driver communicates with the particular database management system that is being
accessed. When you query the database, SQL statements are passed to the database via
an underlying JDBC driver and these queries are processed.
The results of your queries are then passed back to you. The query could also take
the form of a specialized SQL extension or derivative. All JDBC drivers should support at
least the entry level version of SQL-2. The databases that you query may be located on
another machine to which you are connected via a network. For instance, you could
access and query a database over the Internet.
And corporate enterprises are increasingly using intranet-based solutions for their
database access requirements. With database connectivity there will often be
performance considerations. For example, network response times are affected when the
database you connect to is on the other side of the planet. Response times will obviously
be quicker over a LAN. JDBC was designed to cope with these problems.
Database technology in all its forms relies on strong security measures being
implemented. Data integrity is of the utmost importance. You must also give serious
consideration to network security when using JDBC. Remember JDBC is an API for
database connection and not a network protocol. Any network protocol you do use should
be thoroughly examined to ensure it provides sufficient security to cater for your database
connectivity system. DBMS vendors and database connectivity vendors have in many
cases identified and fixed a number of network protocols suitable for accessing databases.
Drivers themselves also have security responsibilities. You can write drivers that are
secure and will not allow applets to connect to a database illegally. A driver which
performs well under certain conditions could be installed on a user's hard drive.
It could then be a trusted part of that Java environment. So it is vital that such a
driver has no problems that could allow applets to compromise the security and integrity of
the user's system.
The JDBC extensions to the Java security model allow you to download a JDBC
driver and register it with the driver manager. If the applet is not trusted, that driver can

Page 289 Go To INDEX


only be used for connections from the server that holds the applet. Information specific to
the local system can not be accessed. This is a basic security measure. You can connect
to databases with both Java applets and applications. Database access applets are often
used across untrusted boundaries. For instance, you could download an applet from a
company that is based on the other side of the world. You might also download an applet
from another machine on an intranet.
In either case, the security of your machine is an important issue. Untrusted applets
are restricted as far as accessing certain resources belonging to the client. They can't
access the files on your system. Nor are they able to open network connections to
unnamed arbitrary hosts. As a rule, JDBC should follow the guidelines of the standard
Java applet security model. Normal unsigned applets should be untrusted. Java database
access applications are becoming more widespread. The code for Java applications is
considered trusted. It can read and write files and open network connections in the normal
manner. There is also no restriction placed on loading drivers from the local classpath.
While Java applications are useful for accessing databases over the Internet, they
can be used extensively in intranet solutions also. The centralized computing model
reduces the problem of managing code on the client. Changes to user interface and
functionality can be done simply by changing code on the server. This is obviously
preferable to the cost and disruption to services that would occur if code on perhaps
thousands of client desktops had to be updated individually. Java aims at being a
universal language.
JDBC aims to take care of the database access side of this aim. It is hoped that
Java and JDBC will eventually replace the many proprietary database languages that are
used. It is also hoped that they will replace the many incompatible basic derivatives that
are used. Many of the software vendors endorse JDBC. There are many JDBC drivers for
the top DBMSs currently provided by them.

• Three-tier JDBC architecture


A three-tier model of JDBC architecture is becoming increasingly popular. The
model inserts a middle tier of services into a two-tier architecture. This middle tier is also
known as middleware. The three-tier model moves some of the application logic from the
client workstation onto an application server.
So an advantage of three-tier architecture is that the application logic is made
independent from the user interface or the database access. The structure for three-tier
architecture is as follows:
Tier 1 - user interface
Tier 2 - application logic
Tier 3 - database access

JDBC database applications for a three-tier architecture are:


Better designed
Easier to maintain
Faster as the number of users grows large

Page 290 Go To INDEX


In the three-tier model, you send queries and commands to the middle tier. The
services implemented in the middle tier then send SQL statements to the database. The
database processes the SQL statements. Finally the middle tier sends the results back to
you. There are performance considerations associated with the choice of a programming
language you use to implement the middle tier. Typically, C and C++ have been used for
this purpose.
This is because they offer fast performance. It is becoming more practical and
popular to use Java to implement a middleware layer. The introduction of optimizing
compilers has aided this. Optimizing compilers translate Java bytecode into efficient
machine-specific code. There are certain inherent qualities in Java, which make it a good
choice for implementing a middle tier. These are its:
Security features
Robustness
Multithreading capabilities
Three-tier JDBC architecture offers an advantage over two-tier with regard to
scaling. Often a new application is developed and prototyped for a small two-tier
environment. When use of the application expands, the system administrators scale up by
simply adding more users to the server. However, this approach often results in an
ineffective system. This is because the server becomes overwhelmed. To properly scale
to hundreds or even thousands of users, it is usually advisable to migrate to a three-tier
architecture.
Projects for implementing three-tier architectures require much more planning and
management. Also, the tools designed to support three-tier applications are typically more
difficult to learn and use. However, using JDBC three-tier architecture can provide
performance advantages over two-tier implementations. Developing solutions with a JDBC
implemented three-tier model is beneficial because you can employ a higher level API,
which is easy to use. The higher level API is translated into the appropriate low-level calls.
Calls from your database access application to the middle tier can be made using
an object request broker (ORB) or through remote method invocation (RMI). In Java, an
object paradigm might be the best way to define the middle tier in either of these
scenarios. Three-tier JDBC access to databases is also desirable because it provides
additional security measures. It allows you to explicitly define the legal and permitted
operations on corporate data. This is preferable to a situation where direct unrestricted
updates to the DBMS servers are allowed.

10.2. JDBC Configuration

• JDBC drivers
Java Database Connectivity (JDBC) is a low-level API that supports basic SQL
functionality. Using the classes and interfaces defined in the JDBC package, Java
applications and applets can access, query, and update a wide range of relational
database servers. To make a connection between a Java application (or applet) and a
database, your system requires at least one JDBC driver. Drivers translate Java
application-level calls into calls that can be understood by an associated database. Each
database driver is specific to the type of database server used.

Page 291 Go To INDEX


This means that a single application can connect to different databases simply by
moving between various drivers. Four main interfaces are included in the JDBC API
package:
java.sql.Driver
java.sql.Connection
java.sql.Statement
java.sql.ResultSet
These interfaces must be implemented by each database driver. The Driver
interface is used to send queries to a database and returns results to the querying
application. And the Connection, Statement, and ResultSet interfaces provide methods
that allow the programmers to create statements and retrieve results. You can test the
functionality of a JDBC driver using the JDBC driver test suite. Most current databases
connect to applications using ODBC. ODBC incorporates a driver and, in some cases, a
client-side library that is specific to the client's operating system.
Both ODBC and JDBC drivers are based on the X/Open SQL Call Level Interface
(CLI). So translating between them is relatively straightforward. To make a connection
between a Java application and an ODBC driver, you need to install a special JDBC driver
called a JDBC-ODBC bridge. The JDBC-ODBC bridge driver is a standard component of
the JDBC package. This bridge implements JDBC method calls by translating them into
ODBC function calls on a platform-specific basis.

In effect, the bridge sits on top of ODBC and implements JDBC for any database
that has an available ODBC driver.
Using the JDBC-ODBC bridge, JDBC can make use of the database connectivity
provided by the existing array of ODBC drivers. However, there are some limitations
associated with this type of database driver. Whenever ODBC is used, ODBC drivers
components must be manually installed on every client machine. In addition, calls from
Java to C code tend to diminish database security and limit the portability of applications.
This makes the JDBC-ODBC bridge impractical for Web-based applications.
The bridge driver is most appropriate on a corporate network where client
installations are not a major problem. And it works well for Java applications that use a
three-tier database access model. Other JDBC drivers can be divided into three
categories depending on their construction and the type of database they are designed to
support. For example, early JDBC drivers were implemented using native methods that
bridged existing database access libraries. The native-API partly-Java driver uses C
language libraries to convert JDBC method calls into calls on the client API.
This type of driver is used for accessing client library-based database systems such
as DB2, Informix, Oracle, and Sybase. Like the bridge driver, this style of driver requires
that some binary code be loaded on each client machine. Many major database vendors

Page 292 Go To INDEX


are currently developing drivers that are written entirely in Java. All-Java drivers offer a
significant advantage since they're capable of being downloaded as part of an applet. The
JDBC-net all-Java driver translates JDBC calls into a network protocol that is independent
of any specific database.
The translated calls are then sent to a middle-tier server. A middle tier can connect
to a variety of databases on behalf of the client application. Once the calls reach the
middle tier, they are converted to a specific database protocol. In general, the JDBC-net
all-Java driver is the most flexible JDBC alternative. And it can deal specifically with the
security requirements of web applications, such as passing data through firewalls.
The native-protocol all-Java driver converts JDBC calls into the network protocol
used by the DBMS (database management system) server. That means that this type of
JDBC driver can communicate directly with the DBMS server. It offers a practical solution
for intranet use. It's likely that the JDBC-net all-Java driver and the native-protocol all-Java
driver will become the preferred way to access databases from Java applications. In the
meantime, the JDBC-ODBC bridge and the native-API partly-Java drivers offer reliable
interim solutions.

• The DriverManager Class


The DriverManager class is a utility class that comes as part of the java.sql
package. This class is responsible for passing connection requests and loading database
drivers. It also provides methods to manage and support the connection between Java
applications and JDBC drivers. In effect, the DriverManager acts as a point of
communication between the application and the driver. Using the methods defined in the
DriverManager class, Java applications can:
Obtain a connectionthrough a driver
Register
De-register
Set up logging
Set login timeouts for database access
All of the methods in the DriverManager class are static. And they can be
referenced through this class name.
public class java.sql.DriverManager
Let's look at an example of a DriverManager method. This method tries to return a
reference to an object implementing the Connection interface.

The first Driver class that returns a connection is used. Before they can be used by
the JDBC management layer, drivers must first be loaded.
Some drivers are loaded by default when the DriverManager initializes. During
initialization, the DriverManager class will attempt to load each of the Driver classes that
are defined in a system property called sql.drivers. Remember, each of the named classes
must implement the Driver interface.

Page 293 Go To INDEX


Drivers that are not loaded at initialization can be explicitly loaded by programmers
using the standard Class.forName method.
Class.forName(“main.db.driver”);
For example, this code lets you load the Main.db.Driver class. Once a driver has
been loaded, its name must be registered with the DriverManager class. Drivers cannot
connect to applications until their names have been registered. Each driver name is a
class filename that includes the package name.

Newly loaded drivers are automatically registered with the DriverManager as soon
as an instance of the driver is created.

• Creating a middle tier


As you know, the JDBC API supports both two-tier and three-tier database access
models. In the two-tier model, a Java application communicates directly with a database
server. In the three-tier model, Java applications send calls to a middle tier of services on
a server.
The services implemented in the middle tier are also known as "middleware". Let's
examine how the middle tier affects the interaction between a client application and a
database. You can see that this database supports two tables called Student and
Workgroup.

Let's suppose a new student called Joe is joining workgroup 1. In a two-tier


structure, the client application would send an "add student" SQL request directly to the
database. But in three-tier models, client applications work at a higher level. In this
example, the client application sends its request to the middle tier using a protocol such as
RMI, CORBA, or TCP/IP.
When the middle tier receives a request from the client application, it maps that
request to a piece of middleware code. Parameters included in the client request, such as
student name and workgroup number, are used to generate specific SQL statements that
will carry out the client request. In this example, an SQL statement requests that a new
student record is added to the Student table, with an associated workgroup value of 1.

Page 294 Go To INDEX


Another SQL statement might request that the Workgroup table be updated by
adding 1 to the No. of students field for workgroup 1.
The middle tier will access the database using JDBC, and execute these SQL
queries. If any results are generated by a query, they are sent from the database to the
middle tier. The middle tier then passes the results back to the client applications. In the
past, middleware services were typically written in languages such as C or C++ because
these languages offered fast performance.
But with the introduction of optimizing compilers, Java bytecode can be translated
into efficient machine-specific code. So it has become practical to implement middleware
in Java. This means that three-tier architectures can now take advantage of Java's
multithreading and security features. A multithreaded middle tier is capable of handling
multiple client connections to one or more database servers. And it can accept
connections from clients using a variety of protocols, such as HTTP and TCP/IP.
Three-tier database access models offer several advantages over the traditional
two-tier design. For example, the middle tier can be programmed with a set of business
rules that manage the manipulation of data. This makes it possible to explicitly define the
operations that can take place on data.
And it lets you restrict access to corporate databases. By using a middle tier, users
can employ an easy-to-use higher-level API which is translated by the middleware into the
appropriate low-level calls. So, in many cases, the three-tier architecture can provide
performance advantages.

10.3. Connections

• Establishing a Connection
To query a database, you must first establish a connection through the Connection
object by calling the DriverManager.getConnection method. One application can make
several connections to a database. It can also make more than one connection to a
number of different databases. As the argument for the DriverManager.getConnection
method is a URL string, let's first look at some URL syntax. URL means Uniform Resource
Locator. URLs are a way of identifying resources stored over the Internet. Here are two
examples of URLs.

Page 295 Go To INDEX


The protocol part of the address is always followed by a colon. URLs containing
Internet references use a double forward slash "//" following the protocol name. A single
forward slash "/" follows the protocol name for local resource files. This part of the URL
contains host information. It can include port numbers, and paths to files and directories.
Here's an example of a URL that specifies the port number, 80, for the hostname
java.sun.com.

This URL specifies the file tutorial.html in the doc directory. A JDBC URL is a
means of providing a driver with the appropriate information for establishing a connection
with a database. From the URL, drivers must be able to recognize the subprotocol of the
database being accessed. The address must be as complete as possible, providing the
application with sufficient details to run without the need to perform additional
administrative tasks. For some connections, the name of the database is all that's required
by the driver. But for accessing databases over the Internet, you may need to specify port
numbers.
JDBC names must be compatible with network naming systems like DNS or NIS.
When a user specifies a database or hostname, a network name resolution system can be
used to locate the resource. This way of locating a database is referred to as network
indirection. The JDBC URL naming system has many of the features of the Internet URL
naming standard with some additional syntax options.

This is the syntax for a JDBC URL contained in a string. The protocol name for
JDBC URLs is always jdbc. The subprotocol refers to the name of the database
connectivity mechanism. A subprotocol name can be reserved for a particular driver by
registering it informally at JavaSoft. You register subprotocol names by sending an email
to jdbc@wombat.eng.sun.com
A list of registered driver classes is maintained by the DriverManager class. One
example of a reserved subprotocol is odbc, which is reserved for the JDBC-ODBC bridge.
The special syntax for this subprotocol allows application writers to include attribute
names and values in the subprotocol name. This is an example of a URL where the odbc
protocol is used to connect to host sambat.

The attributes CacheSize and ExtensionCase are defined with appropriate values.
The third part of the JDBC URL is the subname. This is used to identify the location of the
database.
jdbc:subprotocol:subname
Here's an example of a URL for a locally stored database called datab.
jdbc:odbc:datab

Page 296 Go To INDEX


If you want to access the same database over the Internet, you need a more
specific URL.
jdbc:odbc://java.sun.com:401/datab
Here the odbc protocol is used to connect to the database datab on port 401 at the
java.sun company site. Let's look at an application, which connects to a remote database.
The public class, Dbclient2, is responsible for loading the driver, drivers.databases.qDriver
and for connecting to the remote database, dataB.

Here's the URL string that specifies the location of the dataB database. The
subprotocol for this string is called quickD. The database dataB is located at
home.sun.com on port 401. This code initializes the Connection object, dbCon.

The code states that to connect to the database, the DriverManager.getConnection


method must use the username "Jones" and password "Pencil". The closing lines of this

Page 297 Go To INDEX


application contain the error message to appear in the event of an unsuccessful attempt to
connect to the database or to close the connection. When a connection to a database is
initiated by the getConnection method, the DriverManager class checks the list of
registered drivers.
It searches the driver list until it finds a driver that supports the subprotocol
specified in the URL. When the appropriate driver is found, the connection is made to the
database. An instance of a Connection object is then returned and allows a user to send
SQL statements.

• Using threads to monitor connections


Java is unusual among programming languages because it has a built-in
multithreading capability. This means that the threads in Java programs can execute
concurrently. This important capability has been taken account of in the design of JDBC.
SQL statements can execute asynchronously under some database APIs. Java allows you
to create a separate thread if you wish to execute statements asynchronously with respect
to the main thread of execution. Because Java provides a multithreaded environment,
JDBC drivers don't have to specifically provide support for asynchronous statement
execution. The processing that is carried out by JDBC is synchronous. The database
application program must wait for the SQL statements to be completed. But because Java
is a multithreaded platform, using threads to simulate asynchronous processing is
recommended.
The degree of concurrency available may depend on the particular driver that you
are using. Also the driver will provide any synchronization, which may be necessary.
However, you can assume that fully concurrent execution is supported when programming
using JDBC. You can execute two statements that are on the same Connection
concurrently. You can also process their ResultsSets concurrently. Some drivers will not
send a statement until a previous one completes. Other drivers will provide full
concurrency. When accessing a database using JDBC, there are often situations when
several threads will simultaneously access the same object.
The JDBC driver must ensure that any operation on a java.sql object must be able
to handle such situations. These operations must be multithread-safe. Multithreading is
very useful in terms of connecting to and querying a remote database. For instance,
suppose you send a query statement to a database and find that you are waiting an
inordinate amount of time for a reply. You need some mechanism that can cancel the
thread that is executing the statement. If one thread is being used to execute a statement,
another thread can be used to kill it.
The Statement class contains a cancel method for doing this. The cancel method is
declared like this.
public abstract void cancel () throws SQLException
It throws an SQLException if a database-access error occurs.

Page 298 Go To INDEX


10.4. Querying the Database

• Sending SQL Statements


When a connection is established to a database, statement objects can then be
used to send SQL statements. Statement objects are defined based on what's contained
in SQL statements. The methods used to create Statement objects are part of the
Connection interface. And the methods involved in executing statements and returning
results are part of the Statement interface. In this example of code, an instance of the
Statement object, myStatement, is created using the createStatement method.

This is the simplest Statement object and is used for passing SQL statements
where no parameters are specified. The PreparedStatement object is responsible for
passing pre-compiled SQL statements containing parameters with input arguments.

Input arguments are the same as IN parameters. The prepareStatement method is


used to create an instance of the PreparedStatement object, which in this example is the
object stat. Here the prepareStatement method of the Connection object someConnection
is called. The locations of the IN parameters in the statement are marked question marks.
The PreparedStatement object provides a number of additional methods to supply values
for these parameters.
And as this object extends the Statement object, it inherits the Statement methods.
As PreparedStatement objects are pre-compiled, they can be used to decrease the
execution time associated with simple SQL statements. This is particularly useful where a
simple statement is executed many times throughout an application. Before the
PreparedStatement object stat is executed, the value of each parameter has to be set.
There are many different set methods defined by PreparedStatement which are
sometimes referred to as the "setXXX" methods. The one you choose depends on the
type of the relevant parameter. The setXXX methods for setting IN parameter values must
specify types that are compatible with the defined SQL type of the input parameter. For
instance, if the IN parameter has SQL type Double, then setDouble() should be used. If
arbitrary parameter type conversions are required, then the setObject method should be
used in conjunction with a target SQL type. Lets look at an example using one of the
setXXX methods. This statement will set the first parameter to 1010101010.
Stat.setLong(1, 1010101010)
The first argument is the ordinal position of the parameter to be set. The value it is
to be set to is the second parameter. Generally, parameter values remain set for repeated
use of a statement. However, it is often wise to immediately release the resources used by
the current parameter values.

Page 299 Go To INDEX


They can be cleared by a call to the clearParameters method of the
PreparedStatement class. This is the declaration for clearParameters().

The setXXX methods do not perform any general data type conversions. Instead
the driver maps the Java type to a corresponding SQL type. This SQL type is what
eventually is sent to the database. You have to be sure that the Java type of each IN
parameter is compatible with the SQL type that the database is expecting. A failure to take
adequate care here could affect the portability of your database access program. You can
also explicitly convert an IN parameter to a particular SQL type. You do this by calling the
setObject method of the PreparedStatement class. This is the declaration for setObject().

The setObject method can accept any Java object. This allows an application to be
generic. It also allows it to accept input for a parameter at run time. Once the application
has been compiled, the type of the input is not discernible. If a SQL type is not given, the
driver will simply map the Java object to its default SQL type before sending it to the
database. It is also possible to send an SQL null value as the IN parameter to the
database. To do this, you use the setNull method. This is the declaration for setNull().

You must specify the SQL type of the relevant parameter. Java and JDBC allow
you to use an input stream as an IN parameter. This makes it convenient for you if you
want to send large amounts of data. You simply send it in smaller pieces along a stream
instead of one large piece. There are three different methods provided by JDBC for
dealing with setting IN parameters to input streams:
setUnicodeStream
setBinaryStream
setAsciiStream
The three methods for dealing with streams as IN parameters take one more
argument than the other setXXX methods. This is because you are required to specify the
length of the stream. Before data is sent, some databases need to know what quantity is
involved so specifying the stream length is important. Another type of statement object is
the CallableStatement. This is used to send SQL statements to procedures stored in
databases. The Connection method prepareCall creates the CallableStatement object.

The question marks denote the place for the IN, OUT, and INOUT parameters
appropriate for the getSampleData stored procedure. The CallableStatement object
extends the PreparedStatement object and inherits the methods for setting IN parameters.
Additional methods are then added to handle OUT and INOUT parameters. Suppose you
had a stored procedure called getNumber in a database. You prepare a call to it by
passing the call as a parameter to the prepareCall method.

Page 300 Go To INDEX


The prepareCall method of the Connection class is optimized for handling stored
procedure call statements.
Parameter placeholders must be used for the return values if there are any. They
must also be used for any output arguments because the parameter marker is bound to a
program variable in the stored procedure. The CallableStatement class should be used if
you are executing a stored procedure call.
If your stored procedure returns OUT parameters, you must use the
registerOutParameter method. This registers the SQL type of the OUT parameter prior to
the execution of the statement. After the statement has executed, you must use the
corresponding getXXX method. This is used to retrieve the parameter value.
The correct one to use is again the Java type that corresponds to the SQL type
registered for that parameter. After the stored procedure is executed, the DBMS returns
the result value to the JDBC driver. CallableStatement does not provide a special
mechanism for retrieving large OUT values incrementally.
A given OUT parameter could have the SQL value NULL. To determine if this is so,
you first read the parameter. Next you call the CallableStatement.wasNull method to
discover if SQL NULL was returned by the read. JDBC also has a parameter that supplies
input and accepts output. This parameter is the INOUT parameter. An INOUT parameter
requires a call to the appropriate setXXX method before sending the statement to the
database.
A call to the registerOutParameter is also required to register the relevant SQL type
as an output parameter. The parameter's value is set as an input parameter by the setXXX
method. The JDBC driver converts a Java value, which the setXXX method provides into a
SQL value. The SQL type of this IN value should be the same as the SQL type supplied to
the method registerOutParameter.
The SQL value is the one sent to the database. A call must be made to the
corresponding getXXX method in order to retrieve the OUT value. Let's look at an
example. Suppose you have a parameter whose Java type is short. You would then use
the setShort method from PreparedStatement to assign an input value. The driver
converts this to an SQL SMALLINT value when it sends it to the database. You should
then use the getShort method to retrieve the value from the database.
When a Statement object is created, it can then be executed by specifying the
appropriate method. These methods are provided by the Statement interface. Three
execute methods that form part of the Statement interface include:
executeQuery
executeUpdate
execute
These methods are used to access data contained in database tables. When
executed, they produce the return value while the SQL statement produces the result.
Let's look at some code that illustrates the executeQuery method.

Page 301 Go To INDEX


This method is used for statements that return a single result set in the form of a
ResultSet object. In this example, the ResultSet object provides the result of executing
myStatement. The executeUpdate method is used for statements containing the
constructs:
INSERT
UPDATE
DELETE
SQL statements that contain these constructs cause changes to rows or columns in
a table. Executing the executeUpdate method returns an update count. This is an integer
value indicating the number of rows of a table affected by executing the statement. The
executeUpdate method is also used for SQL Data Definition Language (DDL) statements.
These contain parameters such as CREATE TABLE or DROP TABLE. When a statement
containing CREATE TABLE is executed, it returns a new table. This new table is the
result, but the return value for the executeUpdate method is zero. A return value of zero
for the executeUpdate method indicates that there was no change to the rows of a table,
or that a DDL statement was executed. Before a statement can be executed again, the
ResultSet object must finish processing the current result set. The execute method is used
for more advanced applications. It's useful where the result of executing a SQL statement
is unknown but could be a combination of ResultSet objects and update counts.
As the execute method is more complex than the executeQuery or executeUpdate
methods, it requires additional methods to identify the type of results returned by the
statement. A method called getResultSet is called to determine the first ResultSet object.
If this method returns a null value, this indicates that there are no additional results but
that there may be update counts.
The getUpdateCount method is then called and returns an integer indicating the
number of rows of a table changed by executing the statement. If the integer -1 is
returned, this indicates that there are no further update counts but that there could be a
result set. You'll already know if there is a result set from the results when the
getResultSet method was first called. If the getResultSet method returns a value other
than null, the getMoreResults method is called. The results of this method can be true or
false.
A true result indicates that there is a result set which is then retrieved by running
the getResultSet method again.
A null result for this method indicates that there could be an update count result,
which is then retrieved by running the getUpdateCount method.
A false result from the getMoreResults method indicates one of the following:
An update count result
No further result sets

Page 302 Go To INDEX


To identify which, the getUpdateCount method is then called. A completed
statement is one where all the results are returned. Usually this occurs after one of the
execute SQL statements methods is run. The execute method requires that all results sets
or update counts are completely returned before the statement is considered complete. As
the PreparedStatement interface extends the Statement interface, it can override the
executeQuery, executeUpdate, and execute methods.
These execute methods are all part of the Statement interface. You have seen the
syntax used by the Statement object, CallableStatement, to send SQL statements.

The syntax within the brackets "{}" is referred to as escape syntax. This syntax is an
indication to the driver that the code needs additional translating before it is passed to a
database. JDBC supports the same syntax as ODBC for:
Stored procedures
Dates
Times
Scalar functions
This is an example of escape syntax used to call the stored procedure called
getSampleData.

In this example, values are required for the parameters in the statement indicated
with question marks. If the procedure call returns a result parameter, the escape syntax for
calling the database would look like this. The escape syntax provides a variety of
additional features to a programmer and is independent of database server. Database
servers use different types of syntax to represent dates and times. Here's the escape
syntax for specifying a date in a JDBC SQL statement where yyyy is the year, mm is the
month, and dd is the date.
{ d ‘yyyy-mm-dd’ }
The driver will format this date according to the underlying database and the result
could be 09-July-98 or September-07-98. Here's the escape syntax for TIME and
TIMESTAMP where hh represents hour, mm is minutes, ss is seconds, and f is a fraction
of a second.

Page 303 Go To INDEX


The keyword escape can be used for special escape characters used in strings.
Here's an example of using the escape character '+' in a statement used to find product
names where the sales field is a '2' followed by another character, followed by a '%'.

String, numeric, date, and system functions are supported by DBMSs on scalar
values. DBMS is Database Management System. JDBC allows the use of these functions.
The keyword "fn" is specified and is followed by the function name and arguments.

• Handling Transactions
A transaction is one or more statements that have been executed and completed.
They will also have been either committed or rolled back. Transactions are supported by
most JDBC drivers on the market today. If a Connection is in autocommit mode, then all
its SQL statements will be executed and committed as individual transactions. Otherwise,
its SQL statements are grouped into transactions that are terminated by either the commit
or rollback methods of the Connection interface.
When either commit or rollback is called, the current transaction ends and another
one begins. By default, a new Connection is in autocommit mode. In other words, each
statement is executed as a separate transaction in a database. When the statement is
completed, commit() will be automatically called for that statement.
The transaction consists of only one statement because each statement is
committed individually. You must disable autocommit mode if you want to execute several
statements in a transaction. You do this by calling the setAutoCommit method of the
Connection interface. You must pass it a boolean value of false.
You can, for example, disable autocommit and then group two updates into one
transaction. For instance, you might not want a particular change to occur unless another
change does also. The rollback method will be called if one or both fail. This means that
the values that existed prior to executing the updates are restored. The commit method is
called if both updates are successful. The effects of both updates are then made
permanent. An implicit transaction is always associated with a Connection when
autocommit is disabled. Also a transaction will not terminate until the commit method or
the rollback method is called.
In this case, all the statements in the transaction are committed or rolled back as a
group. If a SQL statement changes a database, the commit method will make these
changes permanent. Any locks that the transaction holds will also be released. On the
other hand, the rollback method will discard those changes. Problems can often occur
when two users try to access a database at once. For instance, one user may read a
value from one place a short time after another has written or changed that value in
another place. The information is no longer up to date, consistent, or reliable.
Two transactions operating on the same database at the same time must be
prevented from having this effect. The DBMS can process transactions so as to minimize
error and disruption. You can specify a transaction isolation level that helps it to do this. A
dirty read is where a value is read before it is committed. You can instruct the DBMS to

Page 304 Go To INDEX


allow dirty reads by calling the setTransactionIsolation method of the Connection instance.
This is the declaration for the setTransactionIsolation method.

The setTransactionIsolation method should not be called while in the middle of a


transaction. The argument "level" refers to the five transaction levels which you can
specify. These are:
Connection.TRANSACTION_NONE
Connection.TRANSACTION_READ_COMMITTED
Connection.TRANSACTION_READ_UNCOMMITTED
Connection.TRANSACTION_REPEATABLE_READ
Connection.TRANSACTION_SERIALIZABLE
Your application will generally perform faster if a lower level of transaction isolation
is used. This is because of increased concurrency between users of the databases. It is
also affected by the decrease in locking overhead that occurs. With the first level,
TRANSACTION_NONE, transactions are not supported.
public static final int TRANSACTION_NONE
The second level, TRANSACTION_READ_UNCOMMITTED, allows dirty reads,
non-repeatable reads, and phantom reads to occur.
public static final int TRANSACTION_READ_UNCOMMITTED
Here's an example of a phantom read. Suppose a user wishes to perform two read
operations on a database and after performing the first read operation, another user alters
the database. When the first user performs the second read operation, the two sets of
data don't match. If a lock is not in place to ensure the integrity of the object, a phantom
read will occur. The third level is TRANSACTION_READ_COMMITTED.
public static final int TRANSACTION_READ_COMMITTED
Dirty reads are prevented but non-repeatable reads and phantom reads can occur.
The fourth level is TRANSACTION_REPEATABLE_READ.
public static final int TRANSACTION_REPEATABLE_READ
It prevents dirty reads and non-repeatable reads but phantom reads can occur. The
fifth and final level is TRANSACTION_SERIALIZABLE.
public static final int TRANSACTION_SERIALIZABLE
Dirty reads, non-repeatable reads and phantom reads are all prevented with this
field. TRANSACTION_NONE is the lowest transaction isolation level.
TRANSACTION_SERIALIZABLE is the highest transaction isolation level. At this, the
highest level, more consideration is given to the avoidance of conflicts. No transaction can
make changes to the data read by another transaction that is operating on a database.
When you are choosing which transaction isolation level to use, you must consider:
Data integrity and consistency

Page 305 Go To INDEX


Performance rates
You should also ensure that the level you choose is supported by the underlying
DBMS. The driver that is being used often determines the transaction isolation level for a
new Connection object. However, usually the underlying database provides a default level.
If you change the level by calling SetIsolationLevel, the new level will remain active until
the end of the Connection session. You might also want to change the transaction
isolation level for a single transaction. In order to do this, you need to set it before the
transaction begins and after it ends. If you try to modify the transaction level during a
transaction, a call to commit() will be immediately made. This will cause any changes at
that point to be made permanent. For this reason, it is recommended that you avoid
modifying the transaction isolation level during a transaction.

• Processing ResultSet Objects


When a SQL statement is executed, the ResultSet interface defines methods that
allow you to retrieve data returned as a result. The ResultSetMetaData interface provides
methods for retrieving the type of data returned after a statement is executed. Metadata
includes statement parameters, row results, and database properties. Here's an example
of code used to execute a SQL statement.

The result set returned by executing a query statement generally takes the form of
a table as shown here.

This code specifies that the executed statement should return columns called
name, id, and parttime from the EMPLOYEETABLE. The data contained in the name
column takes the form of a string. The data in the id column takes the form of an integer
and the data in the parttime column is a boolean. The ResultSet object provides a number
of methods to access the data contained in columns of the ResultSet. These are known as
getXXX methods.
The first step in retrieving a value from a ResultSet is to point to a row by calling the
ResultSet.next method. The location of the current row is indicated by a cursor. When the
ResultSet.next method is first called, the cursor moves from before the first row to point to

Page 306 Go To INDEX


the first row as the current row. With JDBC, the name of the cursor can be obtained by the
ResultSet.getCursorName method.
The cursor name can be used in positioned updates or partitioned deletes of data.
When the correct row is located, getXXX methods are then used to obtain specific column
values. A column value can be retrieved by referring to its name or number.

Both these lines of code refer to the same column called modelname, which is the
third column of the ResultSet object res. A SQL query can be executed for data contained
in tables where more than one column has the same name. When this happens, the
getXXX method returns the first column name that's matched in the search. Column
numbers are a more efficient way of referring to tables that contain columns with identical
names or where no names are specified. Numbering of columns starts from left to right
with the first column on the left numbered 1. To determine the type of data contained in a
table, the resultSet.getMetaData method is called which returns the ResultSetMetaData
object. Let's look at what happens when a getXXX method is called to retrieve data values
stored in a ResultSet.

The SQL data types are mapped to Java objects and values returned by the driver.
Examples of SQL type mappings to Java objects are shown in this table. Methods used to
retrieve these as objects include:
ResultSet.getObject
CallableStatement.getObject
Here's an example of code that demonstrates the ResultSet.getObject method and
how it maps SQL types to Java objects.

The getObject method returns an integer for the values in column a, and a string for
the values in column b. The CallableStatement.getObject method is similar to the
ResultSet.getObject method. But the SQL data type must first be specified using a method
called Callablestatement.registerOutParameter. Using the PreparedStatement.setObject,
the object is first mapped to a default SQL type.

Page 307 Go To INDEX


It is then converted to a specific SQL type before being sent to the database for
processing. Large amounts of data can be retrieved by the ResultSet in the form of
streams using methods like:
getBinaryStream
getAsciiStream
getUnicodeStream
This is useful for SQL data types like LONGVARBINARY or LONGVARCHAR. The
ResultSet.getBytes and ResultSet.getString methods are also used to retrieve
LONGVARBINARY or LONGVARCHAR SQL data types. But there is an upper limit on the
amount of data they can read. java.io.Input streams are returned by the
ResultSet.getXXXStream methods. The data is broken into smaller sets that must be
immediately accessed. The method ResultSet.getBinaryStream returns a stream of
unconverted bytes from the database.
To return a stream of one-byte ASCII characters, you use the
ResultSet.getAsciiStream method. And to return streams of two-byte Unicode characters,
you use the ResultSet.getUnicodeStream method.

Page 308 Go To INDEX


11
Java and Distributed Objects
11.1. Overview of distributed objects

• Introduction to Distributed Objects


Distributed systems are composed of a set of software components running on a
number of networked computers. Interaction between the components is complicated
because of the differences between the underlying computing environments and networks.
Distributed systems are designed to provide a communications infrastructure that
abstracts the low-level communication layers.
They can also take advantage of object-oriented programming (OOP) to provide a
framework for encapsulation and reuse of code. This combination of distributed
technology and OOP speeds up application development and facilitates the integration of
diverse applications. In today's model of OOP, there is tight binary coupling between an
application and the classes of objects that it uses. Often, an application implements
everything in a single language running in a single process on a single machine.
An "interprocess object model" allows a process in one address space to request
the services of an object in another address space. And in an object-oriented distributed
system, an object on one host can invoke a method across a network on an object located
on a remote host. There are several conditions that must be met before objects in different
address spaces, and on different hosts, can communicate. For example, an application
that is making a request must be able to locate the processing capability that it requires.
A requesting application must be able to send parameters and data to the process
it is calling, and must be able to receive results from that process. The parameters and
results of the process must be meaningful on various machine architectures within the
network environment. And the process may need to be usable in different implementation
environments and languages. Java has always had networking capabilities through the
classes in the java.net package.
These classes support sockets, which provide a basic level of general
communication. However, using sockets means that the client and server both need to
use applications-level protocols to encode and decode messages for exchange. And
creating these protocols is a tedious and error-prone process. Remote Procedure Call
(RPC) is another method of network communication. It abstracts the communication
interface to the level of a procedure call. This allows programmers to work as if they're
calling a local procedure, although in reality the arguments of the call are packaged and
sent to a remote procedure.
RPC systems encode arguments and return values using an external data
representation (XDR). RPC does not work well in distributed systems as they feature
communication between program-level objects that reside in different address spaces.
Objects provide an enabling technology for distributed systems. Their high level of
abstraction shields the programmer from the complexity of the underlying communication
mechanism. As you know, they inherently combine data and methods, and separate

Page 309 Go To INDEX


interface from implementation. So they are ideally suited to distributing data and methods
to applications across a network.
Distributed object systems extend the capabilities of object-oriented programming.
Objects can be located on different computers across a network, residing in their own
dynamic libraries. So although they are not part of an application, the application can use
them in the same way as it would if they were local to it. And software and hardware
resources on several platforms can be utilized in a single application. Clients in a
distributed object system are not aware whether objects are local or remote. In fact, they
do not need to know what kind of machine an object resides on. So migrating
implementation objects from platform to platform becomes easier as it does not affect the
clients. Both local and remote objects communicate in the same way.
This means that the components of an application can be distributed to computers
that are most suited to the task of each object. For example, objects that require intensive
processing can be located on computers that are more powerful than standard PCs.
Distributed objects are most often deployed in a client/server configuration. Distributed
objects that provide services or resources in response to message requests are often
called Server objects.
Client objects, on the other hand, are those that request services and resources.
Both types of object operate on the basis that the requester and provider may live on
different machines across a network. Distributed object systems can be made compatible
with existing systems using object wrappers. An object wrapper is an object-oriented
interface to legacy code. So existing systems that are not object-oriented can be
encapsulated with multiple object wrappers that will allow them to function within new
systems. In fact, a single object can represent information derived from several existing
systems.
In the Java distributed object model, a distributed object is one with methods that
can be invoked from another JVM. A distributed object is described by one or more remote
interfaces. These are Java interfaces that declare the methods of the distributed object.
There are several similarities between the Java distributed object model and the Java
local object model. For example, a reference to a distributed object can be passed as an
argument or returned as a result in any method invocation. A distributed object can be
cast to any of the set of remote interfaces supported by the implementation using the built-
in Java syntax for casting.
And the built-in Java instanceof operator can be used to test the remote interfaces
of a distributed object. The Java distributed object model differs from the Java object
model in several areas. For example, clients of distributed objects interact with remote
interfaces, and never with the implementation classes of those interfaces. Non-remote
arguments to a remote method invocation and results from it are passed by copy instead
of by reference.
This is due to the fact that references to objects are useful only within a single JVM.
A distributed object, on the other hand, is passed by reference instead of by copying the
actual remote implementation.
For distributed objects, the semantics of some of the methods defined by the class
Object are specialized. The failure modes of invoking distributed objects are considerably
more complicated than the failure modes of invoking local objects. Clients must deal with
the additional exceptions that can occur during a remote method invocation.

Page 310 Go To INDEX


• Two-tier and Three-tier platforms
Distributed systems can be characterized as either two-tier or three-tier
architectures. A two-tier architecture consists of multiple client computers that provide the
application logic for accessing a shared server. In a two-tier system, the business logic
and information may be contained in either the client tier or the server tier, or it may be
shared across both tiers. Business logic is the functionality required to complete a specific
business task. In a two-tier system, each client operates using a separate database
transaction that must fulfil certain conditions.
For example, if a transaction fails before it completes, all of its results must be
undone. And the results of a transaction must preserve the invariant properties of its
objects. Further conditions that transactions in two-tier systems must fulfil are:
The intermediate states of a transaction must not be visible to other users or
transactions
The intermediate states of a transaction must appear to execute serially
The results of a completed transaction must be persistent
Scalable two-tier client/server systems can be difficult both to create and to
maintain, and do not have the flexibility that large organizations require. In response to
these limitations, there is a movement towards three-tier distributed application systems.
In a three-tier architecture, business logic and information are moved out of the client and
server tiers, and placed in a middle tier. This structure frees the client from having to
process business operations. So processing is offloaded from the client and the choice of
platforms that can be used for the client is increased.
This middle component of a three-tier system consists of a further server that may
be located in a more powerful and better administered computing environment. In a
distributed object system, the middle component is called an "object server". An object
server is a distributed system component that stores persistent objects that are accessed
through a communications protocol. The persistent objects reside on disk and are brought
into memory as requested by applications. And the activation of the objects is transparent
to programmers.
When objects are activated in memory, they are capable of the direct execution of
their methods. And they send execution requests to the object server through an Object
Request Broker (ORB) or equivalent mechanism. Object servers must be able to store
large numbers of objects, although all objects will not be active at any particular time. They
must be able to handle hundreds of simultaneous requests for object method execution.
These requests can come from different clients, each operating in a separate transaction
environment.
Object servers must also prevent unauthorized access to objects. Transactions
between object servers and clients must fulfil the same conditions as do those between
clients and servers in a two-tier system. This can be complicated if business object models
contain relationships that cross object server boundaries.
In this case, multiple servers must be coordinated for each transaction. Business
objects can be used to describe real-life concepts such as customer, product, and order.
These objects can be seen as being independent of applications, tools, databases, and

Page 311 Go To INDEX


systems. A consortium called the Object Management Group (OMG) has set up a
Business Object Task Force to provide concrete definitions for them.
In fact, applications will merely provide the environment to execute groups of
business objects. Business objects are ideal for creating scalable three-tier client/server
systems because they are not single unbroken pieces of code. They can be broken down
into components and reassembled into a three-tier client/server structure. The breakdown
of business objects into components followed here is that of the Common Object Request
Broker Architecture (CORBA) model.
The first tier consists of visual objects that each provide different views of the
business object. These objects define user interfaces and usually reside on the client. The
middle tier contains the persistent server objects, which represent the persistent data and
business logic functions. And the third tier contains legacy servers and databases. The
middle-tier server objects communicate with the client view objects and implement the
logic of the overall business object.
These server objects provide an integrated model of the different data sources and
legacy servers. So the clients do not need to be aware of the various functions, stored
procedures, and databases that reside in the third tier. Clients should never directly
interact with the third-tier components. These components should be completely
encapsulated and abstracted by the middle-tier server objects. For example, the clients
should not be affected if one third-tier server is swapped with another.

• Distributed Object Models


There are several distributed object models currently available. The main
competitors are the Object Management Group's Common Object Request Broker
Architecture (CORBA) and Microsoft's Common Object Model (COM). The Object
Management Group (OMG) is an non-profit consortium formed in 1989 to devise
standards for object-oriented technology. Its membership consists of over 700 software
companies, and includes many of the leading software providers. The OMG's aim is to
simplify distributed object systems and reduce their cost, making it possible for greater
numbers of companies to use them.
To achieve this, it has created standards that allow interoperability and portability of
distributed object applications. The OMG have created an Object Management
Architecture (OMA) which is made up of four main standards. The Common Object
Request Broker Architecture (CORBA) standard specifies the architecture of an Object
Request Broker (ORB). An ORB lets objects transparently make requests to and receive
responses from other objects located either locally or remotely. The Common Object
Services Specification (COSS) provides a standard interface for system-level services.
These include tasks such as creating and relocating objects. The Common
Facilities standard specifies common application functions such as document
management, printing, and e-mail. And standard objects, known as Applications Objects,
have been developed to provide common business functions. The OMG's Business
Objects provide a natural way to describe application-independent concepts. One of the
ultimate aims of object-oriented technology is to provide components such as these that
more accurately mirror objects and behavior in the real world. CORBA defines a system
that allows objects to communicate in a heterogeneous, distributed environment.

Page 312 Go To INDEX


It specifies an architecture and an interface that allow applications to make
requests from objects in a transparent, independent manner. So it is designed to be both
platform and language independent. CORBA's design is derived from the OMG Object
Model. The OMG Object Model defines common object semantics for specifying the
external traits of objects.
It strictly separates interface from implementation, and defines an object's class by
its interface. In the OMG Object Model, clients request services from objects through an
interface. The interface is specified in the OMG's Interface Definition Language (IDL). An
IDL is designed to allow language-independent expression of interfaces, including the
complete signatures of methods.
This is achieved by mapping the IDL syntax to whatever language is used to
implement client and server objects. A client request is an event containing information
such as:
An operation
Parameters (if any)
The object reference of the service provider
The object reference is an implementation-defined type that reliably identifies an
object. CORBA's most important component is the ORB. The ORB allows objects to
interact in a heterogeneous, distributed environment, regardless of the techniques used to
implement the objects. When it receives an invocation request, it determines which object
can handle the request, and passes the request and any parameters to that object. The
part of the ORB that is responsible for communicating of requests is called the ORB Core.
Requesting clients communicate with the ORB Core through an IDL stub. Clients can also
communicate with the ORB Core through the Dynamic Invocation Interface (DII).
An IDL stub represents a mapping between the language of implementation of the
client and the ORB Core. So the client can be written in any language as long as the
implementation of the ORB supports this mapping. When the ORB Core receives a
request, it transfers it to the object implementation. This receives the request as an up-call
through either an IDL skeleton or a dynamic skeleton. A skeleton is a server-side entity for
a remote object that contains a method that calls the remote object implementation. If an
object that is the target of a request is not currently active, the ORB Core loads it and
passes the request to it.
Clients do need to inform an object when they are finished using it - so CORBA
does not define exactly when an object stops running. There are many implementations of
CORBA currently available. These vary according to:
Compliance with CORBA
Quality of support
Portability
Availability of additional features
Orbix from Iona is fully compliant with CORBA version 2.0 and offers
comprehensive support. There is also a version of Orbix called OrbixWeb that supports
Java. VisiBroker from VISIGENIC is also compliant with CORBA 2.0 and it provides
interoperability with Java. There are many other ORBs currently available. These include:

Page 313 Go To INDEX


IBM's System Object Model (SOM)
Digital's ObjectBroker
Sun's NEO/Joe
CORBA-compliant ORBs from the various vendors can interoperate. OMG has
defined a General Inter-ORB Protocol (GIOP) to specify a standard transfer syntax
between ORBs. It defines seven message formats that cover all ORB request/reply
semantics - so no format negotiations are necessary. GIOP is designed to work over any
transport protocol that meets a minimal set of conditions.
And although versions of GIOP implemented using different transports are not
directly compatible, their interaction is much more efficient. OMG have specified how
GIOP will be implemented using TCP/IP - the most popular vendor-independent transport
protocol. This protocol is known as Internet Inter-ORB Protocol (IIOP).
It makes it possible to use the Internet as a backbone ORB through which ORBs
from different vendors can communicate. GIOP provides for a set of Environment-Specific
Inter-ORB Protocols (ESIOPs), which would be used wherever implementations using
their transport are popular. GIOP also defines a format for Interoperable ORB References
(IORs), which describe how to contact a remote object using a specific ORB's mechanism.
There are several products that perform similar functions to CORBA, but are not
based on it in any way. Microsoft's Object Linking and Embedding (OLE) aims to provide
standards for language-independent, distributed object systems. However, Microsoft's
conception of distributed object technology is different to CORBA's. OLE's many functions,
such as embedding, dragging and dropping, and in-place activation, are based on
Microsoft's Component Object Model (COM).
COM specifies a binary standard for object interaction. The basic components of
COM are known as "Windows Objects". These objects provide functionality for COM and
obey the object-oriented principle of encapsulation. When a client accesses a Windows
Object, it cannot directly manipulate it - however, it is allowed to see the object's
interfaces. An interface acts as a pointer to a table of function pointers, and an object may
support several interfaces. So a client may hold several interface pointers to a single
object. COM differs from CORBA, where an object presents only one interface to a client,
and each client holds only one object reference to the object.
However, COM is similar to Java, which also allows one object to present many
distinctly identifiable interfaces to its clients. All Windows Objects must support the most
basic interface - "IUnknown". It supports three methods that give all Windows Objects their
basic functionality. The QueryInterface method allows a client to ask which interfaces an
object supports. And the AddRef and Release methods manage reference counting for
objects.
Reference counting allows a system to track the number of clients holding a pointer
to any of an object's interfaces. Once the system detects that no clients have any pointers
to the interfaces of an object, it can delete the object and recover its resources. As you
know, CORBA does not define exactly when an object stops running. Microsoft has
specified a set of more than 60 interfaces that make up the OLE architecture. These
interfaces enable OLE's functions such as linking, embedding, and in-place activation.

Page 314 Go To INDEX


COM has a different way of identifying objects to that of CORBA. Making object
names globally compatible across distributed systems can cause problems for CORBA. In
a dynamic environment, name clashes can result in applications linking up with the wrong
object, with potentially serious results. Microsoft has created Globally Unique Identifiers
(GUIDs) to avert the problem of name collision.
These are 128-bit integers that are guaranteed to be unique. Run-time support for
COM is provided by a library of API functions (compobj.dll) for object creation and
marshaling. Marshaling refers to both:
Translating parameters and delivering them to a method invocation across
address spaces
Returning results from method invocations across address spaces
When compobj.dll creates an object, it returns a pointer for the first interface of the
object to the requesting client. This type of implementation creates a barrier between
users of the object and its implementation language. When a client requests that an object
be created, it specifies the class identifier (CLSID) of the kind of object that it wants to
create. This maps to a particular file to load, and controls which code runs for the created
object.
However, it does not necessarily indicate all the interfaces that the object supports.
If the name of the file that the CLSID maps to is changed, the interfaces that an object
supports may also be changed. So in this respect, COM does not conform to the generally
accepted object-oriented conception of class. Implementation inheritance is the ability of
one object to inherit code from another.
COM does not support implementation inheritance as Microsoft believes that it is
not suitable to interprocess object models. Instead, it offers "aggregation", which allows an
object to be constructed from subobjects, as an alternative model of code reuse.
Aggregation is not a complete substitute for implementation inheritance. While inheritance
is a syntactic mechanism enforced automatically by the language, aggregation is a
convention that can be implemented in many ways. And while inheritance requires little or
no code to support it, programmers must support aggregation completely.
CORBA does not support implementation inheritance either. IBM's version of
CORBA - System Object Model (SOM) - does support implementation inheritance in some
cases. However, both CORBA and COM support interface inheritance - the ability of one
interface definition to inherit from another.
So in this respect both COM and CORBA are equally object-oriented. Recently,
Microsoft has upgraded OLE version 2.0 to ActiveX, and created a distributed version of
COM called DCOM. IIOP allows limited interoperability between OLE and CORBA. And
CORBA developers have also built point-to-point gateways between OLE and the various
ORBs.
These bridges can be used as gateways to link OLE desktop front ends to CORBA
servers. However, the differences between the models make interoperability complex and
difficult.

Page 315 Go To INDEX


• RMI and IDL
Java has the potential to end the era of competitive, incompatible object models.
JDK 1.1 has addressed the needs of distributed object computing directly by adding
distributed extensions to Java. It provides two separate new solutions for allowing objects
to communicate over a network. Remote Method Invocation (RMI) allows an object to
invoke another object that is running on a remote JVM. It is a Java-specific mechanism
that works seamlessly with the existing Java environment. In fact, it can be seen as the
Java version of a remote procedure call.
Using RMI, once a reference is obtained for a remote object, it is treated just like a
local object. The code accessing the remote object may not be aware that the object
resides on a different machine. But obviously RMI can be used only to interface with
servers written in Java. RMI uses Java interfaces and a stub compiler to provide access to
remote objects. The interface specifies the methods contained by the remote object and a
Server class is defined to implement the interface. The stub compiler is invoked to create
classes that form the link between local and remote objects.
RMI contains a naming feature that allows servers to bind object references to
URLs. And a Naming class allows Server classes to make remote objects visible to
clients. JavaIDL provides a Java interface into CORBA, so it goes beyond simple remote
method invocations. As CORBA is language-independent, JavaIDL can allow a Java client
to make a remote method call on a C++ object for example.
And it can also allow a C++ client to make a remote method call on a Java object.
The CORBA functionality in Java 1.1 provides a standard mapping from CORBA data
formats to Java. The current Alpha 2 release of JavaIDL is not yet compliant with CORBA
version 2.0, so it is not yet IIOP-compliant. However, it is intended that this functionality
will be built into its next release. An IDL compiler is used to map the Java code to IDL. The
IDL compiler provides stub classes, which call an ORB Core that determines the transport
mechanism and marshaling parameters. An application that uses the IDL compiler can
connect to any object server that is CORBA-compliant and uses a compatible transport
mechanism. Java objects must be specified using the IDL, and access must be through
library routines that translate the calls into the appropriate CORBA messages.
The introduction of RMI and IDL have raised the level of abstraction from RPC, as
each provides a way to access data and methods in the form of objects over a network.
In fact, distributed object systems require remote object invocation to match the
semantics of object invocation. As you know, Java can be used to provide interoperability
between IIOP and COM. This is also true for DCOM - the new distributed version of COM.
CORBA-compliant Java objects can be created and located on web servers, and Java
applets can call them back using IIOP. Microsoft's implementation of the JVM relies
completely on COM, and is treated as an ActiveX component.
This means that for a Java programmer, there is no difference on Windows
platforms between Java methods operating on COM objects or native Java objects. And
ActiveX components written in a non-Java language, such as C++, can operate
seamlessly with native Java objects in the JVM. Netscape's open network environment
(ONE) is a network-centric application development environment that is supported by
Netscape's Navigator and Suitespot products. It incorporates Java and IIOP, and will also
include some ActiveX compatibility. So there is a growing Java-driven convergence of

Page 316 Go To INDEX


distributed object technologies. This convergence overcomes the limitations of traditional
two-tier and three-tier client/server models.
However, due to the scale and complexity of the Internet and intranets when
compared with LANs and WANs, the new generation of environments will be difficult to
design. Java ORBs that are CORBA compliant are currently being created. These are
CORBA IIOP ORBs that are written entirely in Java for portability. The ORB must be able
to generate Java bindings from CORBA IDL.
Any code generated by the IDL compiler must be pure Java and therefore able to
run on a JVM. A Java ORB allows an ordinary Java applet to invoke methods directly on
CORBA objects using IIOP over the Internet. The client and server establish a direct
communication link using the ORB. So the currently used HyperText Transfer Protocol
(HTTP) and Common Gateway Interface (CGI) are totally bypassed.
Sun has created two separate new products that enhance Java's ability to support
distributed object computing. NEO is a distributed object environment, and a new release
of Sun's previous product Distributed Objects Everywhere (DOE). The name NEO is not
an acronym for anything. It is a three-tier client/server architecture that brings together
Java, CORBA, and the Web. It also supports IIOP. NEO is comprised of several
components including:
Solaris NEO - the operating system component
Workshop NEO - the software development environment
NEO Administration Tools -converted versions of Sun applications
NEO focuses on networked objects and shared applications. NEO Workshop tools
can convert an application into a networked object if some new code is added. It is also
hoped that NEO will provide version control at the application level, rather than at the
programming level. The NEO system includes a Java ORB called Joe (Java Objects
Everywhere). It interfaces Java programs to a distributed computing environment. By
adding a little code, it allows Java programmers to declare a remote object, locate it with
respect to a NEO name server, and then execute any of its methods. And it includes an
IDL-compiler that generates Java client class stubs automatically from standard CORBA
IDL files.
Joe is primarily a client-side Java ORB. However, Joe clients can receive
asynchronous calls from a server using a callback service. A callback is a call from a
server to a client - allowing the server to become a client. CORBA ORBs are typically both
clients and servers. Three steps are required to create a Joe client application. The first is
to compile the IDL interface of the remote object using the IDL-to-Java compiler. Next the
Java application that will access the remote object should be created. Finally, everything
should be compiled with the Java compiler.
With the common format provided by Joe, it is possible to communicate with non-
Java applications, and non-Sun platforms. This is comparable to the way TCP makes it
possible for UNIX, Windows, and other platforms to communicate, and may be as
significant for distributed object computing.

Page 317 Go To INDEX


11.2. An overview of Java RMI

• RMI architecture
Java Remote Method Invocation (RMI) is a distributed object model for the Java
language. It defines a set of remote interfaces that can be used to create remote objects.
It uses the semantics of the Java object model, making it easy to implement and use
distributed objects. In fact, in order to match the semantics of local object invocation,
distributed object systems require remote method invocation. Java RMI is designed
specifically to function in a Java environment.
It works seamlessly with the homogeneous Java Virtual Machine (JVM)
environment so it can take advantage of the Java object model whenever possible.
However, it can only work with objects that are written in Java. Java RMI is included as
part of JDK 1.1. And RMI applets that are created with JDK 1.1 can be run with the applet
viewer. Other distributed object systems, such as CORBA, can be configured to work with
Java objects.
However, they cannot achieve as much integration with Java as Java RMI because
they must also interoperate with other languages. Java uses RMI to support distributed
objects in order to facilitate:
Integrating the distributed object model into Java
Allowing seamless remote calls on objects in different JVMs
Supporting callbacks from servers to applets
Simplifying writing distributed applications
Maintaining the security of the Java run-time environment
In order to fulfil its goals the RMI model must be simple, easy to use, and must fit
naturally into the Java language. RMI must also allow extensions such as garbage
collection of remote objects, server replication, and activating persistent objects to service
a call. These extensions should create as little extra work as possible for the servers that
use them, and should be transparent to the client. In order to support extensions, the RMI
system needs to provide several invocation mechanisms and it should be extensible to
other invocation models.
It also needs to support different types of reference semantics for remote objects,
such as live references, persistent references, and lazy activation. And it should support
multiple transports and the distributed garbage collection of active objects. RMI can be
defined as the action of invoking a method of a remote interface on a remote object.
Invoking a method on a remote object uses the same syntax as invoking a method
on a local object. A Java program can invoke a remote object once it obtains a reference
to the remote object. When a client object makes a remote call, method parameters must
be sent to the server object, and a return value must be sent back to the client. This is
made possible through two new Java features - object persistence and serialization. A
Java object does not usually last after the program that created it is finished running.
However, a "persistent" object has the ability to record its state so that it can be
reproduced at a later time. And a file can be used to store the state of a persistent object.
An object records itself by writing out the values that describe its state. This process is

Page 318 Go To INDEX


known as serialization because the object is represented by a stream of bytes. Object
serialization is available as part of JDK 1.1. The main task of serialization is to record the
instance variables of an object. If a variable is a reference to another object, the other
object must also be serialized. In fact, all referenced objects in an object's ownership
hierarchy - or graph - must be serialized.
Java contains classes that write objects to streams and restore objects from
streams. However, only objects that implement the Serializable interface or the
Externalizable interface can be serialized. RMI uses serialization to transmit parameters
and return values across address spaces. In this way, a Server object can access a
Parameter object's entire graph of referenced objects. And if a remote method constructs
and returns a complicated object that includes references to other objects, its entire graph
can be returned. The Java RMI system consists of three layers. The stub/skeleton layer
contains client-side stubs and server-side skeletons.
The remote reference layer carries out the semantics of the invocation. And the
transport layer sets up and manages connections, and tracks remote objects residing in its
address space. The boundary at each layer is defined by a specific interface and protocol,
making each layer independent of the others. This means any layer can be replaced with
a different implementation without affecting the other layers. The application layer sits on
top of the three layers that make up the RMI system. It consists of client and server
objects. A method call from a Client object to a remote Server object travels down through
each layer of the RMI architecture to the client-side transport.
It then travels up from the server-side transport through each of the other server-
side layers to the target object. The stub/skeleton layer is the interface between the
application layer and the rest of the RMI system. It does not deal with the specifics of any
transport. It is responsible for transmitting data to the remote reference layer by serializing
the data and marshaling it to the marshal stream. A stub resides locally on a client's
machine, and acts as a proxy for a remote object. It implements exactly the same set of
interfaces that are supported by a remote object.
When a client invokes a method on a remote object, it uses the stub to connect to
the object. So the reference that a client holds to a remote object is in fact a reference to a
local stub. A stub initiates an invocation on a remote object by calling the remote reference
layer. It obtains a marshal stream from the remote reference layer and it serializes the
call's parameters and passes them to the stream. It then tells the remote reference layer
that the call should be invoked. When a stub receives return values or exceptions (if any)
from a call, it deserializes them and informs the remote reference layer that the call is
complete.
Serializing and deserializing can be referred to as marshaling and unmarshaling. A
skeleton for a remote object is a server-side construct that contains a method that
dispatches calls to the remote object implementation. The skeleton unmarshals arguments
from the marshal stream and makes the up-call to the remote object implementation. It
then marshals the return value of the call (or the exception) on to the marshal stream and
passes it back to the remote reference layer. So objects themselves are not passed
across distributed systems - instead references are passed using stubs and skeletons.
The appropriate stub and skeleton classes for a call are determined at run time and
are dynamically loaded as needed. Stubs and skeletons are created using the rmic
compiler. The remote reference layer maintains a specific remote reference protocol that

Page 319 Go To INDEX


is independent of any stub or skeleton models. This provides the flexibility to change this
layer without affecting the other two layers.
The remote reference layer handles the reference semantics for the server. For
example, it abstracts the ways that objects are referred to, taking into account whether
they are implemented on:
Servers that are always running
Servers that run only when they receive a method call
So the layers above the remote reference layer do not need to be aware of these
differences. The remote reference layer consists of a client-side component and a server-
side component. During each method call, the two components carry out specific remote
reference semantics. And they communicate with the lower-level transport layer. The
client-side component contains information about the Remote Server objects. It
communicates through the transport layer to the server-side component. And the server-
side component delivers the remote method invocation to the skeleton. The transport layer
carries out the implementation details of connections between Client and Server objects.
It consists of several abstractions that are used to denote transport processes. It
also maintains a table of remote objects that reside in its address space. When the
transport layer receives a call from the client-side component of the remote reference
layer, it locates the RMI server for the requested remote object. It then establishes a
socket connection to that server and passes the connection to the client-side component.
It also adds a reference for the remote object to its table of remote objects. And the client
is then connected to the remote server. The transport layer monitors the activity level of
the connection. It will shut connections down if the designated period of ten minutes
elapses without activity.
Once the connection is established, the transport layer forwards that remote call up
to the remote reference layer. As you know, this handles any necessary server-side
requirements and hands the call over to the skeleton. And the skeleton makes an up-call
to the remote object implementation, which carries out the actual method call. The return
value of the call is sent back through each of the three layers on the server-side. And then
it is sent up through the transport, remote reference layer, and stub on the client-side until
it reaches the requesting client.

• Remote classes and Interfaces


The RMI system consists of several different interfaces and classes. These are
defined in the java.rmi and java.rmi.server packages. There are certain rules that remote
interfaces must follow. All remote interfaces must be declared to extend the
java.rmi.remote interface. And a remote object that is passed as an argument or return
value must be declared as the remote interface, not the implementation class. This is true
regardless of whether the remote object is passed directly or embedded in a local object.
The methods of remote interfaces must follow certain rules. The RMI Compiler (rmic)
requires that each method is public.
And each method must declare the java.rmi.RemoteException exception in its
throws clause, as well as any application-specific exceptions. RemoteException is the
superclass of all RMI exceptions that can be thrown by RMI at run time. It is used to
indicate that a problem occurred during a remote invocation - for example, an interruption

Page 320 Go To INDEX


of the physical network connection. RemoteException enables interfaces to distinguish
local or method-specific exceptions from exceptions that are thrown by the distributed
object mechanisms. And it allows the application making the invocation to determine how
to handle the remote exception.
RMI server functions are provided by the java.rmi.RemoteObject class and its
subclasses:
java.rmi.RemoteServer
java.rmi.UnicastRemoteObject
The RemoteObject class implements the Object class behavior for remote objects.
It implements the Remote interface and the Serializable interface. And it provides the
remote semantics of the Object class by implementing methods for hashCode, equals,
and toString. Implementing the hashCode methods allows remote object references to be
stored in hashtables. And implementing the equals method allows the references to be
compared. This method returns true if two Remote class objects refer to the same remote
object. Implementing the toString method returns a string describing a remote object. The
syntax and contents of this string may vary as they are specific to the implementation. All
other Object class methods retain their original implementations.
The RemoteServer class abstractly provides the functions needed to create objects
and make them available remotely. It is the superclass of all servers that provide remote
access to objects. And it provides the framework that supports a wide range of remote
reference semantics. The getClientHost method allows an active method to determine the
host that initiated the remote method active in the current thread.
The ServerNotActiveException is thrown if no remote method is active on the
current thread. The setLog method logs RMI invocations to the output stream that is
specified. If this field is left empty, call logging is switched off. And the getLog method
returns the stream for the RMI call log so that information on the application can be written
to the log in a coordinated manner. The subclasses of the RemoteServer class concretely
provide the functions needed to create remote objects and identify the semantics of
remote references. The UnicastRemoteObject class is currently the only subclass
supported by RemoteServer.
It defines a remote object as a unicast (singleton) object, which means that it can
only handle one client reference at a time. If several clients try to access a remote object,
they will be queued and each will gain access only when the last reference is given up.
The UnicastRemoteObject class provides support for point-to-point active object
references using TCP-based streams. However, references are valid only while the server
process is running.
The java.rmi.Naming class allows server classes to make remote objects visible to
clients. All the methods of the Naming class are static and do not need to use an object
instance. When a server wants to make an object available, it calls the bind or rebind
method with the name of the object. It also includes a reference to an object that
implements an interface that extends Remote. A program called the RMI Registry provides
a simple naming look-up service and maintains the binding when an object is called.
The Naming class allows remote objects to be defined using the URL syntax. So
clients can call the lookup method with a string representation of the URL for the object
they want to access. The URLs are of the form rmi://host[:port]/name. Here, rmi is the

Page 321 Go To INDEX


protocol, and host is the name of the host that the object's server resides on, and port
gives the option to include its port number. And name is the name of the object.

11.3. Creating an RMI application

• Creating interfaces for remote objects


There are several steps that you need to follow to create, compile, and run an RMI
application. First, you need to define interfaces for the remote classes. Next, you create
and compile implementation classes for the remote classes. And then you use the rmic
utility to generate the stub and skeleton classes from the implementation classes. Your
next step is to create and compile your server application. Then you start the RMI Registry
and the server application you have just created. Next, you create and compile a client
program to access the remote objects on the server application. And finally, you test the
client. The following example describes how to create a simple banking application. This
application allows a remote client, such as an automatic teller machine (ATM), to access
bank account data on a server. The server allows transactions to be performed against
bank accounts, and allows new accounts to be created. The application uses two remote
classes:
Account
AccountManager
The Account class allows the balance of an account to be displayed, and money to
be deposited in and withdrawn from an account. It also sets the personal identification
number (PIN) for an account. The AccountManager class keeps a list of Account objects,
and allows new Accounts to be created. This is the interface for the Account class.

You can see that it belongs to the atm package. The rmic requires that the stub and
implementation code resides in a package. And you can see that it imports the java.rmi
package. As you can see, the Account interface is a public interface and, like all remote
interfaces, it extends the Remote interface. The first method retrieves the current balance

Page 322 Go To INDEX


of an account. The next two methods allow money to be deposited in and withdrawn from
an account. And the last method allows the ATM card's personal ID number to be set. You
can also see that each method throws the RemoteException. This is the AccountManager
interface and, as you can see, it belongs to the atm package.

It also imports the java.rmi package. And like the Account interface, it is a public
interface that extends the Remote interface. The first method of the AccountManager
interface finds an existing account for a given customer. If there is no account for a given
customer, null is returned. The second method creates a new account and allows a PIN
number and a starting balance to be specified.

• Generating stubs and skeletons


Once you have created your remote interfaces you need to create server classes
that implement them. These implementation classes must contain the code for the
methods declared in the remote interfaces. The implementation class for Account is called
AccountImpl.

It is the remote object that will be referenced by the stub on the client-side and the
skeleton on the server-side. As you can see, the AccountImpl class belongs to the atm

Page 323 Go To INDEX


package. It imports the java.rmi package and the java.rmi.server package. It also imports
the java.io.Serializable interface to allow the parameters and return values of its objects'
methods to be transmitted across address spaces.
The AccountImpl class extends the UnicastRemoteObject class, which all remote
implementation classes must extend. And it implements the Account interface and the
Serializable interface. The AccountImpl class has three private member variables which
specify the current balance of the account, its PIN number, and the name of the account
holder. This method constructs the AccountImpl class. Here, each of Account's methods
are implemented:
Returning an account balance
Depositing money in an account
Withdrawing money from an account
Changing the pin number

This is the AccountManagerImpl class - the implementation class for the


AccountManager interface.

Page 324 Go To INDEX


As you can see, it belongs to the atm package. The AccountManagerImpl class
imports the java.rmi and java.rmi.server packages to give it remote capabilities. It also
imports the java.util.Hashtable class so that hashtable data structure facilities can be
used. As you can see, AccountManagerImpl extends UnicastRemoteObject and
implements the AccountManager interface. This is the default class constructor code. In
this case it does nothing.
The first method creates a new account by putting the account holder's name and
account details into the hashtable. It contains the accountName, pin, and startBalance
parameters. This method searches the hashtable for an existing account when information
on an account is requested.

If it cannot find an account for a given customer name, it throws Exception. As you
have seen, both interfaces and both implementation classes belong to the atm package.
Each of these four sources needs to be compiled with the -d directoryname option in order
to specify a destination directory. The compiler will automatically create a subdirectory
called atm in the destination directory. And it will create the class files in the atm
subdirectory. The destination directory that you supply to the -d option should be in the
class path. You can do this easily by specifying the current working directory as the
destination directory, as shown here.

Page 325 Go To INDEX


After the implementation classes have been created, they are given to the rmic
utility. And it automatically creates the stub and skeleton classes from the interface and
implementation class details. This is the syntax you use to run the rmic.

And this is the necessary code to run the rmic for the AccountImpl class and for the
AccountManagerImpl class.

The rmic creates four class files for the AccountImpl and AccountManagerImpl
stubs and skeletons in the atm package directory. These are:
AccountImpl_Skel.class
AccountImpl_Stub.class
AccountManagerImpl_Skel.class
AccountManagerImpl_Stub.class

• Creating a remote client and server


Once the stubs and skeletons classes are created, the next step is to create the
server-side application. This part of the application allows remote clients to make method
calls on the stubs and skeletons. In this case, the server class is called Bank. It
instantiates the AccountManager object and makes it available to remote clients. The
Bank class belongs to the atm package, and imports the java.util and java.rmi packages.
Its first method creates and installs an RMI security manager.

Page 326 Go To INDEX


The next method creates an instance of AccountManager, and the system printout
is "Bank: create an AccountManager". This method binds a specified name to the
AccountManager object instance and registers it with the RMI registry. Any machine on
the network can refer to the AccountManager object by specifying the host machine and
the object name. You can see the system printout is "Bank: bind it to a name". You can
see that the static rebind method is used so that naming conflicts are avoided. The bind
method also associates a name with an object.
But when the name being bound has already been bound to an object, bind() will
throw the AlreadyBoundException, whereas rebind() will discard the old binding and
enforce the new. The next method creates a sample account. As you can see from the
parameters, the account holder is "jonwoo", the PIN number is "1234", and the initial
balance is $1000. If the binding is successful, the system prints out this message:
AccountManager is now ready
The next step in the process is to compile the server class. You can do this by
executing this command.
javac –depend atm\bank.java
Next, the server application should be started up. However, the RMI Registry must
be running before the server application can be invoked. It resides in the java/bin directory
and can be invoked by typing rmiregistry at the command prompt. This is the code you
use to invoke the RMI Registry and start up the Bank server.
rmiregistery
java atm.bank
If there are no errors, you should see this output.

Once an object has been passed to the RMI Registry, a remote client may request
a reference to the object. So a client application that can make requests needs to be
created and compiled. This client is called ATM and it simulates the behavior of an ATM
machine that is connected to a remote banking server.

Page 327 Go To INDEX


For simplicity, a user interface is not implemented in this example. The ATM
application checks the command line and expects two arguments and an optional third
from it. The first argument specifies the server. If you are testing on a single machine, you
should specify localhost as the server name. And the second argument is a string that
provides an account name. The next piece of code creates and installs the RMI security
manager. The ATM application needs to obtain a reference to the AccountManager object
on the remote server so that it can access it. It assumes that the server name has been
passed in as the first command-line argument.

This name is used to create a URL-type string of the format:


rmi://hostname/AccountManager
The string is passed to the static lookup method of the Naming class. The lookup
method call communicates with the remote server. The lookup method returns the handle
to the remote object that was created when the RMI Registry was run. This handle actually
refers to the stub that communicates with the remote object. The lookup method returns
the Remote interface, which is the parent of all stub interfaces. When the return value is
cast to type AccountManager, the methods of AccountManager can be invoked on it.
Once this has been done, the client can find the account manager object that
represents a customer's account.

Page 328 Go To INDEX


The client program then makes several withdrawals and one deposit.

Once the client code has been written, the next step is to compile the client
application. You can do this by executing this command.
javac –depend atm\atm.java
The final step in the process is to test the client. You can execute the client code
from any machine that has access to the server and to the supporting classes. This is the
command you use to execute the code for the "jonwoo" account, which is running locally
on the server. And this is the output that is returned from a successful execution.

As you can see, it details the transactions that were included in the client
application code.

Page 329 Go To INDEX


11.4. Java IDL

• Java IDL mapping


The Object Management Group (OMG) was established to design specifications for
object-oriented technology, which includes distributed object systems. These
specifications make it easier for communication across a variety of hardware platforms
and operating systems. The Common Object Request Broker Architecture (CORBA) is a
standard introduced by OMG. It is designed to handle client requests on remote objects
without the need to know:
Where the object is located
The programming language
The type of operating system
CORBA allows transparent access to objects and allows remote objects to appear
as local objects to the client. CORBA deals with client requests using an Object Request
Broker (ORB). To examine how an ORB works, imagine a banker (client) located in
Chicago who wants to update the account details (remote object) for a customer's account
on a remote server in San Francisco. When the banker submits the request for the
account details, methods are invoked on the remote object.
In this example, a single remote object contains the account details. The ORB
intercepts the request and locates the appropriate object capable of implementing the
method. It's responsible for passing the parameters to this object, invoking the method,
and returning the results to the client. The banker in Chicago doesn't need to know
specifics about the object like the programming language or the operating system to
access the account detail information.
ORBs can implement client requests through interfaces defined by an Interface
Definition Language (IDL). IDL is used to describe object interfaces. As IDL cannot
implement object interfaces, it's not described as a programming language. IDL definitions
are used to map CORBA object specifications with objects in programming languages like
C, C++, or Java. As CORBA is designed to be language - and platform-independent, this
allows systems written in different languages and on various platforms to interoperate.
Mapping IDL into Java entails converting CORBA objects into Java classes.
The process of Java IDL mapping starts with writing the IDL definition. IDL code is
compiled by a compiler such as the idlgen utility. When the IDL definition is passed
through idlgen, a number of skeleton and stub files are automatically generated. Stubs are
referred to as client mappings and contain methods required for client requests. Skeletons
are referred to as server mappings.
The programmer must add implementation code to the skeleton files by creating the
implementation objects and a server application. At this stage of the process, there are a
number of Java files that can be compiled by the Java compiler, javac.

Page 330 Go To INDEX


The compiled client stubs can be used by a programmer to build client applications
to enable access to a remote server object. As IDL to Java mapping begins with an IDL
definition, let's look at the features of an example IDL file.

This file, Account.idl, is used to manage bank accounts for the ABC bank. IDL
definitions of object interfaces contain:
Attributes
Operations
Operation parameters

Page 331 Go To INDEX


IDL attributes are the equivalent of Java variables, and IDL operations are the
equivalent of Java methods. The Account interface defines the attributes accountName
and balance. Both attributes are specified as read-only which means that any client can
read these values but not set them. The operations provided with the Account interface
are credit and debit. The "in" attribute on each parameter specifies that they are passed in
by value. IDL uses comments in a similar way to Java. Here they're illustrated with two
forward slashes "//". IDL definitions can be compiled into Java source code using a utility
called idlgen which generates stub and skeleton mappings for remote objects. The idlgen
development tool currently runs on:
Solaris 2 on SPARC
Windows 95
Windows NT on x86 systems.
You invoke the idlgen compiler at the command line using the syntax:
Idlgen <filename>.
It's not necessary to specify the filename extension .idl. There are a number of
options available when you run this utility. This syntax incorporates options into the idlgen
command.
Idlgen [options] <filename>.
To specify a directory where Java files are written to during compilation, you use
the -j option.

Here the Account.idl file is written to the ABCBank directory located on the c drive.
The default mapping of IDL modules is to the global Java package. Mapping IDL
declarations in this way could result in duplication of class names. The -p option places
Java symbols in a specified package.
Idlgen –p <filename>.
Examples of symbols used in this option are the Java dot symbol "." and the
directory/filename forward slash "/" symbol. The -J option allows you specify a filename,
for example, genlist.txt which contains a list of all the files generated when Account.idl is
compiled.

Specifying a list of Java files in this way is useful when you want to:
Clean up
Control building
Another useful option is the -e envfile or environment file. An environment file
supplies attributes required for mapping IDL to Java. These attributes represent variables
in Java and when you specify an environment file, the idlgen compiler reads the contents
of this file. Options passed during preprocessing of IDL files include:
-I, which is the name of a directory where a search is performed on IDL files
containing #included statements

Page 332 Go To INDEX


-D, which is the symbol to be defined during preprocessing
-U, which is the symbol to be undefined during prepossessing
When the IDL definition is compiled by idlgen, the programmer then provides the
implementation code required to continue the mapping process.

• Implementations for IDL objects


Let's examine how implementation code is written for this IDL file.

Modules in IDL are a means of grouping interfaces or definitions with common


functions and are mapped to a Java package.

The IDL module ABCBank is mapped to a Java package of the same name. IDL
declarations not defined in a module are mapped to a global package in Java called
"idlGlobal". When writing IDL declarations, it's a good idea to define them inside IDL
modules. The public class, AccountImpl, implements the interface
ABCBank.AccountServant. This interface was automatically generated by the idlgen utility.
Two instance variables associated with AccountImpl are accountName and balance.

These are derived from the accountName and balance attributes specified in the
IDL file.

Page 333 Go To INDEX


When a new instance of the AccountImpl class is created, the constructor
AccountImpl is invoked. The arguments specified by this constructor are copied into the
instance variables, accountName and balance. Two get methods that return the name and
balance of the account are getaccountName and getbalance.

These two methods are used to return the contents of the two member variables.
The credit method adds a specified amount to the account balance and the debit method
subtracts a specified amount from the balance. To make the Account object available to
clients, a server class is created. When an ORB receives a request from a client for a
remote object, the ORB uses the server class information to locate the object.

Page 334 Go To INDEX


This code must be written by the programmer as it is not automatically generated
by the idlgen utility. The server class, AccountServer, is created as a public class and is
responsible for implementing a server. The ORB that handles client requests is called the
sunw.door.Orb and is part of the Java IDL system. It calls the method
sunw.door.Orb.initialize to start the ORB listening for client requests.

The AccountImpl class is instantiated and the AccountSkeleton.createRef method


returns a reference r to this object. To make this reference available to an ORB, the
reference is published by passing it to the sunw.door.Orb.publish method. This step
involves binding the reference so that it's accessible by a URL. This code specifies the
error message that appears in the event of a problem arising when trying to bind the
object reference to a URL.

A message appears when the server class AccountServer is successfully


implemented.

Page 335 Go To INDEX


• Writing clients which access remote objects
Using the compiled client stubs, programmers can build client applications and
applets that allow access to remote server objects. Here's an example of an applet used
by clients to request or update bank account details for a bank account residing on a
remote server.

This applet contains fields where a client can enter:


The host name of the machine on which the account resides
Transaction amounts
Account details are queried by entering the host name and selecting the Connect
button. The results are displayed in the Account Balance field. When a client selects the
Debit or Credit button, this invokes a change to the account balance by the amount
specified in the Transaction Amount field. This change is displayed in the Account Balance
field. The status line displays system messages associated with client requests. A
reference to the remote object is held in the member variable ABCBank.AccountRef. The
user interface is created using the init method.

Page 336 Go To INDEX


This method initializes the fields and buttons that appear in the applet. When a
client enters a host name for an account, a URL is first created by the connect method for
the account server.

To construct this URL, the account server is assumed to run on the


default.sunw.door.ORB port.

A reference to an AccountStub is created by calling the


ABCBank.AccountStub.createRef method.

This reference r is then bound to a URL by the sunw.corba.Orb.resolve method. If


problems arise when resolving the remote object reference to a URL, an error message is
displayed. The updateStatus method uses the reference to the remote object to return the
account name and balance details. This reference was returned by the connect method.
The variables accName and balance are defined as strings and two get methods
are called to return values associated with these variables. The results returned for a client
query on account name and balance are displayed in the:
Account Name field
Account Balance field
Exceptions arising from the updateStatus method are recorded by the
systemException method and appear in the status line. The credit method describes what
happens when a user enters an amount in the Transaction Amount field and then selects
the Credit button. If the user selects the Credit button without first specifying the host
name, a message is displayed on the status line informing the client to connect to the
server first. If the user selects the Credit button before entering an amount in the
Transaction field, an error message is displayed when a transaction is complete, the
status line displays a message and the updateStatus method is called to return a new
balance.
The debit method describes what happens to the account balance when an amount
is specified in the Transaction Amount field and the Debit button is selected.

Page 337 Go To INDEX


12
Java Animation and Images
12.1. Working with Images

• Loading images from URLs and files


The Image class in java.awt provides abstract methods to represent common
image behavior. Image data referenced by an instance of the Image class may exist
anywhere on the Internet. The Java class library was designed to support asynchronous
image loading. This background loading of images ensures that a large amount of
processing time isn't taken up during initialization. Special methods defined in the Applet
and Graphics classes enable you to load and display images.
For example, the Applet class provides a method called getImage that retrieves an
image and automatically creates an instance of the Image class for you. Images are
stored separately from Java class files. To access these images, you have to tell Java
where to find them. Currently, Java supports images in GIF and JPEG formats. Loading
images is fairly straightforward provided you know their URLs and filenames and they are
in a GIF or JPEG format.
To load an image, you need to import the java.awt.Image class and then pass the
image's URL to getImage(). The getImage method can take one or two arguments.

If you use getImage() with a single argument, you retrieve the image at that
particular URL.

This form of getImage() is simple but inflexible. If any part of the URL changes, you
have to recompile your Java code to take the new location into account. The two-
argument form of getImage() allows for greater flexibility. The first argument is the base
URL and the second is a string representing the path or filename of the actual image.

The Applet class provides getDocumentBase and getCodeBase methods to handle


the base URL argument of getImage(). getDocumentBase() returns a URL object
representing the directory of the HTML file containing the applet. In this example, the
image1.PNG file is in the same directory as the HTML files that refer to the applet.

The getCodeBase method returns a string representing a directory containing the


applet. In this case, the file image2.PNG is in the same directory as the applet itself.

Page 338 Go To INDEX


If you are using more than one file, it's useful to put them into their own
subdirectory. In this example, getImage() looks for the file image2.PNG in the images
directory.

Using either the getDocument or getCodeBase methods is more flexible than hard-
coding a URL or path name into getImage(). Provided these methods are used, Java can
still find your images even if you move HTML files and applets around.
getImage() should be called from inside a method such as init(). If called in the
constructor of an applet, getImage methods won't work because the applet doesn't have
the full context (AppletContext). The Toolkit class also supplies getImage methods. You
can get a Toolkit object either by calling Toolkit's getDefaultToolkit() or by invoking the
Component getToolkit() instance method. Both Java applications and applets can use
Toolkit's getImage methods to load images.

The loading of an image doesn't actually start until the first time a program tries to
draw the image. The image that getImage() refers to isn't loaded until it's needed so that
Java doesn't have to keep enormous images around in memory. Instead, Java just keeps
a reference to the image data and retrieves what it wants at a later date.
To ensure a program doesn't try to draw an image before it's fully loaded, some
programs monitor the image loading process. Java provides the MediaTracker class and
the ImageObserver interface to implement this.

• Drawing Images
The getImage method can't display or draw an image. It merely returns an Image
object. The Graphics class supplies several drawImage methods for displaying images.
Although all drawImage methods have common elements, some provide additional
features such as the use of background color.

If the image has finished loading, the return boolean value of drawImage() is true.
The first form of drawImage() displays an image in its original dimensions. It takes four
arguments - the image itself, the x and y positions of the top left corner, and the keyword
this. The “this” keyword is an instance of a class that implements the ImageObserver
interface.

The “this” argument is used to pass in an object that, implements the


ImageObserver interface.

Page 339 Go To INDEX


The applet shown inherits from the Applet class which, by default, implements
ImageObserver. The ImageObserver is responsible for checking whether an image is
ready to be drawn or not. The Applet class contains default behavior for observing images
and the “this” parameter refers to our applet. The second version of drawImage() takes an
additional two arguments to represent the width and height of the image's bounding box.

If you specify dimensions larger or smaller than the original image, the image is
automatically scaled to fit the box. Scaling an image smaller or larger than its original size
can cause image degradation or distortion. To avoid this, you can check the size of an
image in advance, and then scale it to a specific size. You use getWidth() and getHeight()
to determine the size of an image.
getWidth(ImgaeObserver)
getHeight(ImageObserver)
These methods take a single argument, an instance of a class that implements
ImageObserver, which monitors image loading. In most cases, you can use the this
keyword as an argument to getWidth() or getHeight(). The drawImage method returns
after displaying the loaded image. If you want to make sure that only complete images are
drawn, then you need to track the loading of images. Let's take a look at a sample
program that displays an image and then scales it to half its original size. Retrieving the
image is the first step.

Here let's draw the actual image of the car after it has been loaded. The getWidth
and getHeight methods retrieve the image's original dimensions.

Page 340 Go To INDEX


You can then go on to specify the proportions you want in the width and height
arguments of g.drawImage(). In this example, the size of the image is halved.

• The image observer


For many programs, Java's background image loading works well. However, some
programs need to keep a close track of image loading. In such cases, Java provides the
media tracker and image observer to ensure that applets don't draw images until all the
image data is loaded. The image observer is an update interface that monitors image
information as an image is being created.
The Component class implements the ImageObserver interface. As image data is
loaded, the repaint method is called. When you call repaint(), you are asking Java to
repaint your applet as soon as it can. Repaint() triggers Java to call paint() which is
responsible for drawing the current frame. You can track image loading by calling the
imageUpdate method. imageUpdate() is called when information about an image becomes
available. This method signals that an image has changed in some way. The
imageUpdate method returns false if all of the image data has been loaded.

If further updates are needed, true is returned. Let's take another look at the syntax
of imageUpdate(). Its first argument represents the image you want to track. The flags
argument provides status information about image loading. The x, y, width, and height
parameters specify the bounding box of the image. If an image encounters an error while
loading, the error flag is set and any attempt to draw the image will fail.
The abort flag is set at the same time to indicate that image production has
terminated. If an image is terminated before production is complete, the abort flag is set.
Unless action is taken to trigger another image sequence, no more information on image
loading will become available. If the error flag is not set at the same time, accessing any of
the image data will restart production. When a previously-drawn static image is complete,
the allbits flag is set. The image can then be redrawn in its final form. In the case of a
multi-frame image, the framebits flag is set when another complete frame is ready to be
redrawn. Let's take a look at some code that illustrates how the loading and drawing of
images work.

Page 341 Go To INDEX


The init method is the first to run and here you specify which image to load. Next
paint() is called, and it's at this point that the image actually starts to load. You must pass
the this argument, an instance of a class implementing ImageObserver, to drawImage().
When image information changes, imageUpdate() is called. The imageUpdate method
calls repaint() which in turn calls paint() over and over again. Because all the image data
may not be loaded when the paint method finishes, only a partial image may be displayed.
This means that the paint method has to be called repeatedly until all of the image is
loaded. This constant redrawing of the screen catches your eye and creates flicker which
detracts from the overall appearance of an applet. Fortunately, there are specific
techniques you can use to produce professional, flicker-free applets.

• The media tracker


Sometimes an applet or application cannot do anything practical until its images are
fully loaded. This is particularly true of animations where delays can occur or blank frames
appear if an animation starts before all its frames are ready. To address such problems,
Java provides the MediaTracker utility class and addImage() to monitor the image loading
process. Media tracker ensures that images are fully loaded before they are displayed. It
can also group a set of images together. These features make it ideal for animation where
tracking of groups of images is vital. Let's take a look at a sample program that ensures an
image is loaded before it's drawn.

Page 342 Go To INDEX


First you use getImage() to retrieve your first frame. Then you create a specific
instance of MediaTracker to track your images. It takes an instance of ImageObserver as
an argument. The “this” argument of MediaTracker is an instance of ImageObserver and
refers to the applet. Now you can use addImage() to include the image in group 0 and
start the loading process. The first parameter of addImage is the image itself. The second
variable is an ID number that controls the order in which images are fetched.
Normally a program that produces several different animations will use one ID for
each animation. All images for the first animation might use an ID of 0, and an ID of 1 for
the second animation. Here checkID(0, true) determines whether images tagged with an
ID of 0 have been loaded. If loading is finished, then a true value is returned and drawing
can begin. The checkID method also returns true if an error occurs while loading or scaling
an image. When loading is finished, the image is drawn in the top left corner of the applet's
bounding box.
Otherwise, the paint process is invoked again by repaint. The media tracker can
monitor the loading of every image, or can be set to monitor only those with a specific ID.
The waitForAll method pauses until all images have finished loading, are aborted, or
receive an error. waitForID(int id) is more selective and will wait until all images with a
specific ID have been loaded or terminated for some reason. You can also specify how
long to wait for loading to complete.

The time is expressed in milliseconds. You may not want to take the time to load an
image before starting your applet. When you call statusID(), you pass on the ID you want
and a boolean flag to indicate whether it should start loading that image.

If a true value is passed, image loading will begin.

12.2. Animation

• The animator applet


The easiest way to create an animation is to use the Animator class provided by the
JDK. Animator is basically a general-purpose animation tool that allows you to create an
animation quickly and easily. Animator is available in both 1.02-compliant and 1.1-only
versions. To use the Animator tool, you first need to copy the following files to your
classes’ directory:
Animator.class
ParseException.class
ImageNotFoundException.class
You also need to create image and sound files for your animations. Then you add
the appropriate Animator applet parameters to your HTML file so that the Animator applet
can read them. The animation can then be viewed in a Java-enabled browser. Most of the
Animator applet tags are self-explanatory.

Page 343 Go To INDEX


For example, the BACKGROUND tag refers to the image to be displayed in the
background. The PAUSE tag indicates the number of milliseconds of delay between
frames. The default number of milliseconds is 3900. The tags for images need further
explanation. The default name of images used by the Animator class starts with the letter
T followed by a number.
For example, if you have two GIF files that form part of your animation, you name
them T1.PNG and T2.gif. If you wish to change the default name for images, you should
use the NAMEPATTERN parameter. For example, if your images are called anImage3.jpg
and anImage4.jpg, you should use the NAMEPATTERN parameter in this form.

You can specify the image sequence in an animation in two ways:


Using STARTIMAGE andENDIMAGE tags
Using the IMAGES tag
The STARTIMAGE and ENDIMAGE tags let you specify a range of images, and
both have default values of 1. If you specify an ENDIMAGE that has a lower numerical
value than STARTIMAGE, the images will be displayed in reverse order. For example,
setting STARTIMAGE="4" means that your frames will be displayed in reverse order from
4 to 1. If you specify ENDIMAGE="5", frames 1 to 5 will be shown. The IMAGES tag takes
multiple inputs, and you can arrange animation images in any order. Let's assume you
wish to display images T1.PNG, T6.gif, and T2.gif in that sequence. To do this, you simply
insert the appropriate image numbers in the HTML file, using the “|” character as the
separator.

The SOUNDS tag works in the same way as IMAGES, except that a value can be
left blank if no sound is to be played. If a PAUSE tag is omitted, a standard pause is set up
between images in the animation. The coordinates for displaying images are specified by
using the POSITIONS tag.
The default coordinates are (0,0). However, a "@" character is used to separate the
x and y values of a coordinate. If you want an image to remain in the same place as the
previous image, insert a blank in place of the coordinate. Let's assume you wish to display
your first and second images at (50, 30), and the third image at (80,80). To do this, you
insert an additional “|” separator between the coordinates of the first and third images.

• A simple animation thread


Animation creates the illusion of movement by displaying successive images at a
relatively high speed. Normally you need to display ten to twenty frames per second to
create effective computer animation. To animate in Java, your first step is to set up an
animation frame. Then you get Java to paint that frame. Repeating these steps will
simulate the movement you need. Because animation programs draw repeatedly at
regular intervals, they need an animation loop. An animation loop should be included in a
thread's run method. It should never be included in paint() or update(), since it would then

Page 344 Go To INDEX


take over the AWT thread that is responsible for all drawing and event handling. An
animation loop keeps track of the current animation frame.
It also forces periodic screen updates. To run the animation, the loop should be in
its own separate thread. To use threads in animation, you need to make a number of
changes to an applet's code. First you need to add the words "implements Runnable" to
the applet's declaration.

To hold the animation applet's thread, you need to include an instance variable.
thread animator;
Another animation requirement involves setting up start() so that it simply creates
and starts the animation thread.

You also need to include stop() to suspend execution of the animator thread when
a reader leaves the page.

Setting the animator variable to null makes it available for garbage collection so it
can be removed from memory after a certain length of time. The run method handles the
principal work of the animation thread. Here you include the actual animation loop that
cycles through the images and displays them.

Let's take a look at a complete program that creates a simple animation thread.

Page 345 Go To INDEX


First, the words "implements Runnable" are added to the applet's declaration. You
then set up an array of images for your animation. To keep track of each image in the
array, you use an index counter. Next, you add the instance variable animloop to hold the
applet's thread. To ensure images won't be displayed before they're fully loaded, you
create an instance of the media tracker. Then you use getImage() to retrieve the images
and add them to the media tracker. Here in the paint method, you check to see if all the
images in group 0 have been loaded.

When the images are fully loaded, you display them using g.drawImage(). Now let's
use start() to create and start the animation loop thread. The stop method suspends the
animation thread when the reader leaves the page. The run method is called directly after
start() and forms the main body of the program. Here you set up the for(;;) function to loop
indefinitely. You use the index counter to cycle through the sequence of images.

Page 346 Go To INDEX


Then repaint() is called to display them. This code handles exceptions or errors and
the animation thread pauses for 200 milliseconds. Finally you need to override update() so
that it simply calls paint(). This will prevent the background being repainted between
frames.

• The IFC extension and animation


Sun's AWT is the effective standard for Java applet and application user interface
elements. In theory, the AWT contains the basic tools to create a cross-platform graphical
user interface. In reality however, many developers find that the interface elements of
AWT's classes differ greatly from platform to platform. For example, a Java interface
designed to look well on a Windows 95 computer may look considerably different on a
UNIX machine or a Mac.
Struggling to get the AWT to display consistently across platforms can be one of
the most frustrating aspects of coding for Java developers. To overcome the limitations of
the AWT, Netscape developed the Internet Foundation Classes (IFC) library. The IFC is
completely written in Java and is built on top of the AWT. The IFC library replaces many of
the standard AWT elements with its own. For example, it supplies its own classes in order
to carry out simple tasks such as animation. Probably the most helpful animation features
provided by the IFC include:
A push/pop graphics model with a changeable clipping rectangle
Off-screen buffering for memory-efficient, flicker-free drawing
By enhancing the AWT system, the IFC library makes it easier for developers to
create fairly complex user interfaces that will display consistently across platforms. This
work can be accomplished without a huge coding overhead. IFC's main limitation is its
size. An applet written in the IFC can routinely exceed 600K, whereas the AWT equivalent
would be much smaller. The size issue will be overcome to some extent when Netscape
starts including the IFC classes with Java classes in future releases of Navigator.
On April 2, 1997, Sun and Netscape announced they were combining their
technologies to jointly develop Java Foundation Classes (JVC). JVC will combine Java's
AWT and Netscape's IFC to provide a powerful unified framework for Java application
development. The IFC library provides the following classes for images and animations:
Image

Page 347 Go To INDEX


Bitmap
DrawingSequence
ImageSequence
The Image class is the IFC's foundation class for imaging and animation. In IFC
terms, an image is an object that can draw itself within a rectangle. Both Bitmap and
DrawingSequence classes are extensions of the Image class. The Bitmap class is used
for working with bitmaps. The DrawingSequence class is used for working with animation
frames. The ImageSequence class, a subclass of DrawingSequence, is used specifically
for animating images. The fact that Bitmap, DrawingSequence, and ImageSequence are
all subclasses of Image gives you a certain degree of flexibility. It allows you to supply
different values for methods that take image as an argument. For example, you could
specify either an animation or a bitmap in the setImage method.
The DrawingSequence class provides IFC's basic animation support. To create an
animation, you can subclass DrawingSequence to create a custom class. Then you
override drawAt() to specify how the animation sequence should be drawn. To supply the
animation's dimensions, you need to override width and height. If you want to define the
direction of an animation sequence, you use setPlaybackMode(). The setFrameRate
method specifies an animation's speed in milliseconds. You must use setFrameCount() to
specify the number of animation frames or an exception will be thrown.

• Methods of avoiding flicker


Flicker is a side-effect of creating Java animations. It arises because Java paints
and repaints each frame of an animation applet. And each frame is painted incrementally.
The constant repainting of an applet creates flicker, which detracts from the overall
appearance of the applet. If you want professional-looking applets, you need to eliminate
flicker as much as possible. In Java, a call to repaint() results in a call to update(). Applet's
update method clears the applet by filling it with the original background color.
It then calls on paint() to draw the contents of the current frame. Animation flicker
actually happens because the update method clears the applet between frames. As a
result, the parts of the frame that don't change switch rapidly between being painted and
then being cleared. If the original color is white, for example, and paint() creates a much
darker image, then the flicker effect will be very obvious.
As a result, the animation will seem very jerky and disjointed. There are a variety of
techniques you can use to eliminate flicker and produce smoother Java animations. These
techniques can be applied to all images. In many animations, you only need to redraw a
small area of the screen to simulate the movement you want. Unfortunately, paint() can
only redraw the entire applet and not small portions of it. By limiting repainting to a part of
the applet, you can eliminate much of the flicker that arises from redrawing a full screen.
Clipping is a mechanism that allows you to limit the area of the screen that gets redrawn.
Once you know the area that needs to be redrawn, you use the Graphics class clipRect()
method.

Page 348 Go To INDEX


In this case, you reduce the drawing area to a rectangle sixty pixels wide and fifty
pixels high. The clipRect method tells the system that it needs to draw only within a
specific rectangle. While the full screen may get instructions to redraw, only the portions
inside the clipping area are actually drawn.
Besides reducing flicker, this is efficient and much faster than doing a full redraw. If
a component consists of just one image, then overriding the update method will be
sufficient to prevent flicker. The default implementation of update() clears the screen
before calling paint(). Overriding update(), so that it simply calls paint(), prevents the
background from being repainted.

When applets display more than one image, you need to use a technique called
double buffering to eliminate flicker. With double buffering, you first create the image off
screen. As soon as drawing is finished, you copy the off-screen image to your drawing
area in one quick call.
The drawing surface is then updated immediately. Because all the drawing is done
in the background, partial images won't appear suddenly to disrupt the smoothness of an
animation. Let's take a look at a program that prevents flicker by implementing double
buffering.

First you store your off-screen image and graphics context in instance variables
that can be passed on to paint(). During initialization, you create Image and Graphics
objects and assign them to the instance variables shown here. The off-screen image area
is based on the size of the applet. Here the program draws a white rectangle inside a
black one. The i variable will be incremented later in the animation loop to change the
dimensions of the white rectangle. Once the rectangles have been set up off screen, you

Page 349 Go To INDEX


can then draw the off screen image. To prevent screen clearance between frames, you
need to override update() so that it simply calls paint().

The paint method will then display the contents of the current animation frame. By
default, update() clears the screen by filling it with the original background color. Flicker
arises when update clears the screen between frames. The start method creates and
initiates the spinner animation thread. The run method is invoked directly afterwards. The i
variable gets incremented each time it passes through the animation loop. Once the
center of the rectangle is reached, i is reset to 0 and the animation loop begins again. The
repaint method then displays the sequence of images. Finally, stop() suspends execution
of the spinner animation thread when the user leaves the page.

12.3. Image manipulation

• Creating Images
Java provides a set of classes and interfaces to help you create and modify image
data. These classes and interfaces are grouped together in the java.awt.image package.
Two of the most important interfaces defined in the java.awt.image package are:
ImageProducer
ImageConsumer
Objects that implement the ImageProducer interface generate raw data for an
image. And objects that implement the ImageConsumer interface can receive information

Page 350 Go To INDEX


about the development of the image. The creation of an image is the result of
communication between ImageProducer and ImageConsumer objects. These are the
public methods defined in the ImageProducer interface.

Communication between an image producer and an image consumer is initiated


when the consumer object calls the ImageProducer's addConsumer method. The
startProduction method directs the producer to begin computing pixel values. As image
data is generated, the ImageProducer object passes information about the image to the
image consumer. The ImageProducer does this by invoking methods defined in the
ImageConsumer interface.

The constants defined in the ImageConsumer interface are passed as values to the
setHints() and imageComplete() methods. More than one image consumer can be
registered with an image producer at a given time. In cases like this, the image producer is
expected to maintain a list of its consumers and report information to each one. When the
image producer has delivered all the image pixels, it calls the ImageConsumer's
imageComplete method.

Page 351 Go To INDEX


This notifies the image consumer that the task has been completed. It's important to
realise that the component that displays the image isn't the image consumer. The AWT
uses image consumers behind the scenes, in response to drawImage() requests. In fact,
unless you want to do low-level manipulation of image data, you never need to use or
implement an image consumer. As you know, images can be loaded from external files.
But they can also be created from scratch and stored in memory. To create a new image,
an application must first convert pixel values into an integer or byte array. Remember,
image data is just a collection of different colored pixels. This array, or image data, is
generated using some user defined method. In this example, the build method is used to
load pixel data into an array.

Once an array of pixels has been formatted, you can construct an Image object
from it. Image objects can be constructed from the entire array or from just a portion of it.
As you know, the Image class is abstract, so you can't instantiate an Image object directly
from it. Instead, your application uses the MemoryImageSource class to create a
MemoryImageSource object. Like ImageProducer and ImageConsumer, this class is
defined in the java.awt.image package. As you can see, various constructors can be used
to create MemoryImageSource objects.

Page 352 Go To INDEX


MemoryImageSource constructors must be passed the specific following about the
image, including:
The size of the desired image
The int or byte array
An offset into the array
The width of hypothetical imagerepresented by the int array
They can also include information about the ColorModels and Hashtable properties
used for an Image object. You can see that the instance methods defined in
MemoryImageSource implement the standard ImageProducer interface. So a
MemoryImageSource object can be considered an image producer. The
MemoryImageSource constructor returns an ImageProducer object. This object acts as an
input parameter for the createImage method.

This method is defined as part of the java.awt.component class. Using


createImage, applications can take an ImageProducer object and create a new image
from the pixel array defined with MemoryImageSource. And this results in a usable image.

• Image filters
The java.awt package supports image manipulation by supplying image filters. An
image filter is an object that sits between an ImageProducer and an ImageConsumer.
Using image filters, your applications can modify image data before the consumer
receives it. Any number of filters can be inserted between an image producer and an
image consumer to produce a highly-filtered image. In this example, an unfiltered image is
run through a red filter and then through a contrast-enhancing filter.

Page 353 Go To INDEX


You could use one filter to perform both functions, but it is good policy to create
separate filter classes. This results in cleaner, reusable code. ImageFilter is the
superclass of all image filters. Because objects derived from the ImageFilter class must
intercept data intended for the ImageConsumer, they implement methods defined in the
ImageConsumer interface. But filters also need to communicate with ImageProducers. To
do this, they make use of a support class called FilteredImageSource. The
FilteredImageSource class implements the ImageProducer interface.

So ImageProducer objects derived from this class can communicate with


ImageConsumer objects. While FilteredImageSource objects can be viewed as image
producers, their real function is to filter image data that has been produced by some other
image producer. Each FilteredImageSource object communicates with a specific
ImageProducer and a specific ImageFilter. Two important ImageFilter subclasses perform
filtering:
CropImageFilter
RGBImageFilter
CropImageFilter creates a new Image from a region of an existing Image. In this
piece of code, you can see an image being downloaded and then cropped using
CropImageFilter.

The RGBImageFilter class is an abstract class that enables you to create color
filters. By subclassing RGBImageFilter, your application can modify the colors of the
individual pixels making up an image. ImageFilter subclasses don't need to implement
every ImageConsumer method. They only implement the methods that transmit data you

Page 354 Go To INDEX


want to change. The CropImageFilter class implements the following ImageConsumer
methods:
setDimensions()
setProperties()
setPixels()
And the RGBImageFilter class implements the following methods:
setColorModel
setPixels
Using an existing image filter is easy. First, your application needs to load an Image
object to be filtered.

This is usually achieved with the getImage() method. Next, the program uses the
getSource method to obtain a data source, or ImageProducer, for the Image object. An
instance of ImageFilter can now be created and intialized. The next step is to create a
FilteredImageSource object. This passes the constructor, the image source, and filter
objects. Finally, the Component class's createImage method is used to create a new
Image object.
FilteredImageSource is the image producer of this new image. If you can't find an
image filter that does exactly what you need, you can create your own. But all customized
image filters must be subclasses of the ImageFilter class. Before creating your own
ImageFilter, it is good policy to become thoroughly familiar with the ImageProducer and
ImageConsumer interfaces.

• Color models
The image you see on screen is a "rendered" image, or an arrangement of colors.
But at its base level, an image is just a collection of binary numbers. Some sort of model is
required to translate binary numbers into screen colors. In Java, this is the job of an
abstract class called ColorModel. Methods defined in the ColorModel class can be used to
translate an image's pixel values into its color components and transparencies.

Page 355 Go To INDEX


Let's examine how Java maps binary numbers to colors using ColorModel. In Java,
individual pixels are represented as a composite of four color components:
Alpha
Red
Green
Blue
By default, each color component occupies eight bits. So the color of each pixel is
represented by a 32-bit value. When an array of integers is passed to a
MemoryImageSource constructor, all the integers are expected to be in this format. A
pixel's alpha value determines its opacity, or degree of transparency. In current Java
implementations, alpha is either on (transparent) or off.
Two subclasses are derived from the ColorModel class. The DirectColorModel
subclass extracts the red, green, blue, and alpha values directly from the bits of a pixel.
Using this class, you can specify how many bits of an integer represent each of the four
color attributes.
In Java, the default color model - called the default RGB color model - is derived
from the DirectColorModel class. You can create an object that implements this default
model by using the static ColorModel method getRGBDefault. The other ColorModel
subclass is called IndexColorModel. The IndexColorModel class determines the color
values for a pixel by using the pixel value as an index into color map arrays. This
IndexColorModel is useful for images that:
Use relatively few colors
Represent digital information
Applications are free to create their own color models. For example, in a
customized color model, the red component might occupy 15 bits, as opposed to 8 bits in
the default RGB color model.

• The PixelGrabber class


A pixel grabber is used to extract a rectangular subset from a specified Image or
ImageProducer object. This image subset is then converted into an array of integers. The

Page 356 Go To INDEX


PixelGrabber class is part of the java.awt.image package. As you can see, the
PixelGrabber class implements an ImageConsumer interface.

This means it can be attached to any Image or ImageProducer object to retrieve a


subset of the pixels in that image. Because PixelGrabber can be applied to Image and
ImageProducer objects, it supports two constructors.
One takes an Image object and the other takes an ImageProducer object. Let's look
more closely at the PixelGrabber constructor that uses an image producer as an
argument.

The ImageProducer constructor is generally more useful than the Image


constructor for filtering situations. As you know, this constructor creates a PixelGrabber
object that can grab a subset of an image.
The pixels are captured from the image produced by the ImageProducer, ip. And
the subset to be grabbed is defined by x, y, w, and h. Once grabbed, the pixels are stored
in the array specified by []pix. The offset value marks the point in the array where the
PixelGrabber should start putting pixel values. And the scansize parameter gives the width
of the original image. Once the pixel grabber has been constructed, it is ready to grab
pixels.

Page 357 Go To INDEX


In this code, pixel capture is initiated using the grabPixels method. This is a JDK
1.0 method but it can be used with JDK 1.1. The method getPixels() is new for JDK 1.1.
When the grabPixels method returns, all the grabbed pixels are in an array. As you can
see, this method is placed within an exception handler to catch any errors. But it's good
practice, after using this method, to check for errors by calling the getStatus method.

12.4. Working with sound


Java applets can play audio clips, but this capability has not yet been fully
developed. The ability to play multiple, digital waveform audio sounds is supported in the
java.applet package. There is also provision for playing sound in Java applications. The
easiest way of playing a sound clip is by using the play method in the Applet class. There
are two constructors for play(), shown here.

The upper method plays the audio clip at the specified absolute URL. The lower
method plays the clip given at the URL and a specifier that is relative to it. The url
parameter supplies an absolute URL giving the base location of the audio clip, and the
name parameter gives the location of the clip relative to the url argument. In both cases
nothing happens if the audio clip cannot be found, so there is little or no control. The
methods are limited to simple situations. To play an audio clip in an applet, you follow four
stages:

Page 358 Go To INDEX


Create the AudioClip object
Load an .au sound file into AudioClip
Play the sounds once or loop continuously
Stop the playback
The basic code that implements the stages is shown here.

Both the AudioClip object and the getAudioClip method are part of the java.applet
package. The getAudioClip method is used in the same manner as getImage() is used to
get images. The getCodeBase method is used to get the URL specifying the directory on
the web server with the audio file. The standard, and currently the only supported, format
for audio data in Java is Sun's .au format. This format is suited to small audio files. The .au
format has good compression, but is lacking in quality. The .au format utilizes an
advanced storage technique that enables 14-bit digitized wave sounds to be stored in only
8 bits of data, with minimal loss. It is 8000Hz and monaural (one channel).
It is generally used in Unix workstations, including Sun and NeXT machines. As
only one format is currently supported, it is not necessary to specify this format to
getAudioClip(). Other formats contained in the sun.audio package are expected to form
the basis for more extensive audio support in future releases of Java. The Java Media
Framework (JMF) application programming interface is designed to incorporate a diversity
of media types into Java applications and applets.
These formats include MPEG-1, MPEG-2, QuickTime, AVI, and MIDI, as well as
the .au and .wav formats. The .wav audio format, developed by Microsoft and IBM, has
both 8-bit and 16-bit forms and can be either monaural or stereo. The play method of
getAudioClip() is used to start and play a sound file until the end of the file.
The loop method is used to play an audio file until the end, and repeat this
continuously. The stop method is employed to stop playing a sound file. Continuous
sounds, for example background music, the hum of conversation, or water trickling are
best represented using the loop method. Discrete sounds, such as a jingle or car horn are
best implemented using play(). Control, using play() and stop(), is needed to stop a sound
playing for a page other than the one being viewed, and to stop iconized programs playing
sounds.
Currently, there is no way to pause the sound file or to play part of the full clip. The
limitations of sound in Java are likely to be short-lived as development is proceeding
rapidly to remedy the shortcomings. A number of audio files can be played at the same
time, making up a composite of sounds. This is, of course, hardware-dependent. While
current sound cards normally support four channels, many still only support two. One of
the applications for such computer-based, discrete sounds is in virtual reality (VR).

Page 359 Go To INDEX


Experimenters have found that small improvements in sound enhance the experience of
immersion in three-dimensional VR, more so than small improvements in graphics quality.
The MediaTracker class is designed for coordinating displays ("tracking") in various media
- graphics, audio, and so on. For instance, it can be used with the getImage method to
load and display slides. Although audio is not currently supported by MediaTracker, it is
planned to extend tracking to audio files. Let's examine a complete Java applet that plays
an audio clip.

The sample program begins by importing the Java packages. You use
MouseListener so that the user can click the applet to replay the sound. The audio clip
named audio is declared. The first method called is init(). The addMouseListener method
tells the applet to listen for mouse events. Using the getAudioClip method, parameters are
passed to reference the audio clip hello.au. The audio data will start to download when the
play function is executed. When the applet stops, the audio clip is also stopped. The
drawString method prints the line of text "Click here to replay sound file".

Page 360 Go To INDEX


When the user releases the mouse button, the applet stops the sound and plays it
again. The methods at the end of the code are included because they are part of the
MouseListener interface.
Now, let's look at the use of audio in Java applications. Methods that are part of
java.applet cannot be used in applications. Instead, you rely on the sun.audio package to
provide audio in them. The features now described relate to the current JavaSoft JDK (up
to version 1.1), but are not officially documented by Sun Microsystems. There is no
guarantee that they will work in future releases.
Importing the sun.audio package is achieved by the code shown.
import sun.audio.*
import java.io.*
The displayed code opens an input stream, called istream, to the audio file.

To create an AudioStream object, named astream, from the input stream (istream)
just opened, you use the code shown.

Playing and stopping the audio clip is achieved by means of the class member
"player" from class AudioPlayer. This is now shown.

To play a stream continuously, use the ContinuousAudioDataStream class.

It is also possible to use a URL as the audio stream source. You define the URL
and then replace the input stream and audio stream setup with the code shown.

Page 361 Go To INDEX


13
Java Tips and Techniques
13.1. Features of the Language

• Language Issues
The Java language with its large libraries often provides you with different ways of
doing the same thing. Although each way might have the same end result you need also
to look at how the particular task is done. This is because performance is of critical
importance in building applications and applets. The speed and efficiency of your
application are often determined by the choice of implementation you make. For instance,
the efficiency of string handling is a major concern for programmers. Java uses a different
implementation of strings to C++.
In C, operations on strings occur on character arrays. But in Java they occur
through class methods. Java strings are constant, so their values cannot be changed after
they are created. Instead you apply methods to the strings in order to create new String
objects. Java can perform optimizing actions in your programs by sharing immutable
String objects. So you should use a String object for strings that are not intended to be
changed. The intern method can be used to facilitate the sharing of Strings.
Suppose you create a String object x which contains "Hello". At another time you
might create another String y which also contains "Hello". Calling the intern method in the
declaration of y tells Java to share the String object so y now points to x.

You should take care when using String objects in Java. In many cases it is more
useful and efficient to use StringBuffers. This is because StringBuffer objects essentially
are modifiable strings. StringBuffers should be used when strings need to be modified.
When you use the + operator to concatenate strings, the Java compiler uses the
StringBuffer class to perform the operation. The StringBuffer class allows you to specify a
particular size for a memory block. The capacity which you specify for the StringBuffer
represents the number of characters the object is capable of storing. If the capacity of a
StringBuffer is exceeded, the extra characters will be accommodated by expansion of the
capacity. The internal buffer is automatically made larger if it overflows. This piece of code
uses a String object called someString.

It allocates a new String each time the for loop iterates. This piece of code is,
however, far more efficient. It appends new characters onto a string rather than repeatedly
allocating a new string, which is a concatenation of the others. This could provide a critical

Page 362 Go To INDEX


increase in the performance of your application. The performance of Java programs is
aided by one of Java's revolutionary features - its support for multithreading. Of course
problems can still arise if there are many threads executing and many methods being
called at the same time. For example, one thread might read a certain value into a field
and another perform an operation on the contents of that field concurrently. The field may
end up containing a value contrary to that intended. Java allows you to suspend the
activity of one thread until another has finished what it is doing. The order in which the
threads execute is determined by a priority rating. The synchronized keyword is used to
indicate that a method cannot be entered until another call to it has finished. This is a
security feature that allows you to control data that is not being modified correctly.
However, if you place the synchronized keyword in front of every method you will
severely affect the performance of your network, causing it to slow up. This is because
you are effectively imposing single thread execution on your program. The overhead of a
synchronized method can be about six times that of a standard method. All calls to a
method could occur only providing previous calls to that method have finished. One way of
enhancing the multithreaded capabilities of your program is to synchronize blocks of code
rather than whole methods. Synchronizing blocks of code marks some sections off as
being critical. These are the sections that are most likely to cause problems if executed
concurrently. Any section which is not critical can be executed at any time. Java does not
provide a mechanism for turning synchronization off. Many of the methods that are defined
in JDK 1.1 are already synchronized. If you want to speed up the performance of your
program, you could remove the synchronized statements. Sometimes the amount of code
placed inside loops can be excessive. In this case, calls are made to length() and to
getSize() with each iteration of the for loop.

A more efficient way would be to use local variables to store the result of a method
call. The results of the calls made to length() and getSize() are copied into the local
variables len and wdt respectively.

The loop expressions can now use these local variables. Note that you need call a
method only once and copy its result into a local variable for further use. Repeated
method calls are slower to carry out than using local variables, which store the result. You
could also simplify your code by using references. Often programmers use the entire
package.class.field naming style when they are accessing fields. If you are dealing with a
primitive type, you could copy it to a local variable. If you are dealing with a reference
field, you could use a local reference to the class. Suppose you were writing to the
console frequently during the program's execution. Your code could contain numerous
calls to the println method of the System.out class.

Page 363 Go To INDEX


Having to write this line of code over and over is time consuming. You can assign a
PrintStream object to the output of System.out.

This lets you use a shorter piece of code to do fundamentally the same thing. One
useful feature of C is the way you can define compile-time constants. To use a compile-
time constant, you simply let a textual name represent some value. This makes your code
easier to read and maintain.
It is also faster at run time than using a normal variable. In Java you can do this by
creating public static final variables in a Java interface. You use the import statement to
make the interface visible.

The value stored in the age variable is concatenated to the string that is passed to
System.out.println.

Java is of particular importance to Internet and networking technologies. The speed


at which an application can carry out its tasks is of prime importance in this area. Delays in
transmission make it a useful practice to have all input buffered. You do this by using an
object derived from BufferedInputstream. When you use a BufferedInputstream a number
of logical blocks of data are read from a file. They are read as one large physical input
operation into a memory buffer. Blocks are taken from this buffer as they are needed by a
program.
If the buffer becomes empty, the next logical blocks are read in by the next physical
input operation from the input device. So the number of actual physical input operations is
small compared with the number of the program's read requests. Buffering inputs in your
program will yield significant performance benefits. This is because standard input
operations are particularly slow compared to typical processor speeds. When all input is
buffered, repeated seeks through the data are in the buffer. This means that
retransmission across the Internet is not required. This saves time while your program is
operating. You can access an input stream as follows.

Memory leaks have affected programs designed using traditional programming


languages. Many object-oriented languages require that you keep track of all the objects
you create and that you destroy them when they are no longer needed.
Java's memory management and garbage collection facility have cut down on the
risk of memory leaks occurring. However, sometimes a "zombie" object can cause
problems. An object that is still referenced cannot be returned to system resources. Such
objects are known as "zombie" objects. An object is eligible for garbage collection when

Page 364 Go To INDEX


there are no more references to that object. References that are held in a variable are
naturally dropped when the variable goes out of scope.
You can also explicitly drop an object reference by setting the value of a variable
whose data type is a reference type to null. Because Java has automatic garbage
collection, you don't have to explicitly delete objects. Each class in Java can have a
finalize method that can be used to tidy up a class before it is deleted. When a resource is
no longer referenced, it is ready to be returned to the system.
For instance, when the method 'setZombie' is called the string s is allocated.

The zombie string is then set to reference the string s before the method ends.
When the setZombie method ends, the String s is marked for garbage collection.
However, it will not be destroyed until the object itself (instance of ZombieExample) is
destroyed because there is still a reference to it. Finalization is a disciplined way to begin
to give resources that are no longer needed back to a system to avoid resource leaks.

• Security Issues
Applets are the source of one of the major security concerns connected with Java.
Browsers such as Netscape prevent Java applets from accessing files on the machine on
which they are run. Users would be less likely to download an applet if there was a risk
that it would tamper with their local files. You can view the HTML code source for the web
page that the applet is embedded in. However, you cannot view the Java source code for
the applet. The Java applet class file that is downloaded to your machine contains
bytecodes and not source code.
Therefore, you can not always be sure that there is no sinister function built in to
the applet. Reverse engineering is a process where an application can be decompiled. In
other words, the source code for the application is extracted and is capable of being
viewed. This also means that an application can be modified in a way that the original
developer never intended. Reverse engineering defeats the purpose of the principle of
information hiding and can facilitate infringements of copyright.
Decompilers read the bytecodes contained in one or more class files and convert
them back to Java source code. Many of the available decompilers are written in Java.
Often the code that is generated by a decompiler is not a perfect match for the original
source code. However, they are usually close enough to enable you to understand how
the implementations were made. The solution to the security risk presented by
decompilation is to use an obfuscator. An obfuscator is a tool that obfuscates or confuses
the contents of a class file so that decompiling them is made pointless.
Not all obfuscators guarantee total protection from decompilation but they can
make it exceedingly difficult to make sense of the decompiled bytecodes. Obfuscators
work by scrambling symbolic names in your Java class files. So things such as class,

Page 365 Go To INDEX


interface, and method names are scrambled. The JVM needs this information in its correct
form to create links from your classes to the relevant library packages.
The code is all but useless if these links can't be created. When you run an
obfuscator on your class files, another file is generated. It is this obfuscated class file that
will be transmitted and not the original insecure version.

• Designing programs for Java


When you are designing anything, the materials you will be working with are of the
utmost importance. Software design is directly affected by the language you use to
develop your application. By paying attention to design issues you can build better
applications. In object-oriented programming, such as Java, the emphasis is on mapping
real world objects into a software solution. Java provides an efficient way to design the
interaction between problem domain objects and human interaction objects. This is the
Observer/Observable object model.
The Observer/Observable object model can be used to implement the
Model/View/Controller architectures that are part of other languages such as SmallTalk.
Java is flexible enough to allow you to go beyond the basic Model/View/Controller
architectures. Both models represent a way of building problem-domain objects and
reusing them again even though the human interface may be quite different each time.
The idea that one object can notify other objects if a change in its state occurs is central to
the Observer/Observable mechanism.
It is useful in systems that make use of multiple, synchronized representations of
the same data. Observer and Observable are particularly useful in the area of AWT GUI
programming. Your application can have the capacity for different views and displays,
which are updated in synch with one another. The java.util package provides you with the
functionality to implement the Model/View paradigm. The relevant parts are the Observer
interface and the Observable class.
The Observer interface is declared like this.
public interface observer
A class that wants to be informed of changes in Observable objects implements this
interface. The object that can change state should be derived from Observable. The
Observable object maintains an editable list of the observers associated with it. The
update method of the Observer interface is called to notify the Observers that the object
being observed is changed.
Each Observer has its update method called with two arguments - o, which is the
observable object and arg, which is passed to the notifyObservers method. The
notifyObservers method is then called and the Observer should then interrogate the
Observable object to determine its new state.
public void notifyObservers()
When an Observer wishes to be notified about changes in the state of an
Observable object, your program notifies the Observable object. It does this by calling the
Observable object's addObserver method.
public synchronized void addObserver(Observer o)

Page 366 Go To INDEX


This modifies the list of Observers by adding a new one represented by o.
You can optimize the performance of the Observable by shielding it from the direct
passing of information to the Observers. You can do this by placing a threaded FIFO
queue between the Observer and the Observable. The threaded FIFO queue becomes the
single Observer to the Observable, and the Observers in turn become Observers of the
threaded FIFO queue.

• Native methods and JNI


Sometimes there may be situations where you will want to integrate Java with code
written in a different language. For instance, you may have a large amount of C code that
has already been tested rigorously and debugged. Porting this code to Java may not be
the best use of your available resources. It could take a large amount of time and
debugging would again be necessary. Java has a facility called native methods which
allows you to call precompiled code written in a different language. Native methods are
libraries of code that are compiled natively.
These libraries are dynamically called by the Java run-time interpreter for use by
Java applications and applets. They are several times faster in execution time than
compiled and interpreted Java bytecodes because they are compiled outside the Java
environment. JDK 1.1 provides a native programming interface called the Java Native
Interface (JNI) which allows you to use native methods.
It allows Java code that runs inside a JVM to interoperate with applications and
libraries written in other programming languages. These languages include C, C++, and
assembly. You can write one version of a native application or library and expect it to work
with all Java VMs that support the JNI on that platform. This is because JNI does not
restrict the implementation of the underlying Java VM. So JVM vendors can add support
for the JNI without affecting other parts of the VM.
There are three primary reasons for you to choose to use native methods. The
platform-dependent features needed by your application may not be supported by the
standard Java class library. You might want to make a library written in another language
accessible to Java code through the JNI. Finally, you might want to implement a small
portion of time-critical code in assembly or some other lower-level language. Programming
through the JNI allows you to use native methods to:
Create objects
Inspect objects
Update objects
These objects could be strings or even arrays. Using JNI you can also:
Call Java methods
Perform type checking at run time
Throw and catch exceptions
Load classes
Obtain class information

Page 367 Go To INDEX


You must write a nativemethod declaration for each native method that you want to
use. This declaration is similar to the declaration of a normal Java method interface but
you must specify the native keyword.
public native void copyLink();
The native keyword alerts the Java compiler that the definition for the method is
external. Native methods can be static or non-static. For example, the basic steps for
accessing native C code are:
Writing and compiling the Java code for the program with the native method
Generating the stubs and headers from the Java class file using the java
utility
Writing the native code for the required method
Compiling the native code into a Dynamic Link Library (DLL)
Making the library available to the Java run time
Loading the library into the Java run-time interpreter

13.2. Advanced GUI Features

• Lightweight Components
Currently, GUI components in Java are implemented as windows of the native
operating system, and are called heavyweight components. Each instantiation of a GUI
component gives rise to the creation of a full, native window. This one-to-one mapping of
heavyweight components and native windows gives rise to some serious problems.
These heavyweight components are not very efficient of resources, because each
is implemented as a full native window. When you place a large number of these
inefficient components into a container, it can severely impact on your application's
performance. Native windows are opaque - meaning that they cannot be used to
implement transparent regions on screen.
And because extended components are implemented natively, it is hard to
implement a common look and feel across different platforms. The JDK 1.1 includes the
implementation of alternative, lightweight components that help eliminate these problems.
Lightweight components do not have a one-to-one mapping to a native window. They are
rendered entirely within Java itself.
Transparent regions, for example, cannot be rendered in the component's paint()
method in order for them to be transparent. Lightweight components are more efficient
because they no longer need to have native data structures or peer classes. They are
implemented entirely in Java, meaning that a common look and feel can be maintained
across platforms. You can freely mix lightweight and heavyweight components in your
applications. Each can be the child or parent of the other. Heavyweight components that
overlap lightweight components will always appear on top, regardless of the z-order.
Z-ordering is the order in which components are painted onto the screen. You now
have greater control over the z-ordering of components, because you control fully the
paint method for a component. Additionally, non-rectangular shapes for components are
possible.

Page 368 Go To INDEX


• Printing
The JDK 1.1 AWT has a set of APIs to enable printing. The AWT components are
printed using the facilities of the native platform on which the Java program is running.
Printing relies on the current AWT graphics model, and it is AWT components that are
printed. To print, you first create an instance of PrintJob to contain all the necessary
information for the print job. Then you create a print graphics object suitable for printing
with. Thirdly, you must paint the component onto the print graphics object by invoking the
component's print() method and passing the print graphics object as a parameter. You
then flush the print graphics page to the printer. Finally, you end the print job, which
initiates the actual printing.
The PrintJob class contains all the print request information, such as user-defined
printer settings and defaults. For example, you are responsible for pagination and may
need to obtain the dimensions of the page. You get a PrintJob object through a call on the
getPrintJob method of the java.awt.Toolkit class.

You pass three arguments, the first being a Frame dialog box object.
You can design an arbitrarily complex frame dialog, depending on the application.
Then you pass a job title string to identify the print job you have initiated. Lastly, you can
pass a list of properties to the printer, which is an instance of the java.util.properties class.
These properties are printer configuration parameters, like the printer's name or the page
order.
Let's look at the relevant methods of PrintJob that return printer properties. You can
obtain the size of the print page, in pixels, using the getPageDimension method. You can
then get the resolution of the page, in pixels per inch, from the getPageResolution method.
Dividing the total number of pixels by the page resolution gives you the size, in inches, of
the printing page. You can find out the order the pages are printed in by checking the
lastPageFirst method. It returns true if the printing sequence starts with the last page.
Printing the last page first is useful for printers where the pages are gathered front-side up.
After setting up the print job, you must get a print graphics object using the getGraphics
method.

The getGraphics method returns a Graphics object that has been prepared for
printing. You then invoke the component's print method, passing the print graphics object.
The print method, in turn, calls the component's paint method.

The printAll method of java.awt.Component allows you to print an entire


containment hierarchy. You pass the Graphics object obtained from
printJob.getGraphics(), and all components are printed in sequence.

Page 369 Go To INDEX


You then flush the print page to the printer using the dispose method on the print
graphics object.

You then end the print job with the end method.
printing.end();
There is also a finalize method, which overrides the finalize method of Object. It
cleans up and ends the print job once a reference to it no longer exists. Printing is subject
to the same security constraints as for normal applets. There is no restriction on applets
creating print job objects or painting components into print graphics objects. It does mean,
however, that untrusted applets are not allowed to initiate print jobs.

• Java Foundation Classes (JFC)


Sun, IBM, and Netscape have combined resources to release a new set of GUI
APIs. This entirely new GUI API is called the Java Foundation Classes (JFC), and will
greatly enhance Java's usability. The JFC will combine the best of the current AWT with
the best from Netscape's Internet Foundation Classes (IFC). The JFC will offer a set of
comprehensive and state-of-the-art GUI tools for Java application development.
Because it is based partly on the current AWT, programs developed now will be
easily upgradeable to take advantage of the new JFC. The JFC will be included as part of
future JDK releases, as standard. Let's look at the Internet Foundation Classes (IFC) from
Netscape, to see what the new JFC will be likely to contain. The IFC is written entirely in
Java and is delivered as a class library that can be easily integrated with the standard
JDK. It replaces some of the AWT features and adds many new ones. The IFC contains a
Drawing/Event framework with features like:
Advanced clipping
Flicker-free drawing
Cursor management
Superior handling of mouse events and tracking
Transparent components
The drag-and-drop paradigm is used extensively in the IFC. Dragging and dropping
is a very intuitive element of modern GUIs. The IFC contains an entire framework to allow
programmers to add drag-and-drop facilities to their applets and applications. You may
often need to design programs that do several tasks at once, using Java's support for
multithreading. Sometimes, writing threads for Java programs can add unnecessary
complexity. The IFC offers objects called Timers that enable a form of concurrent
programming that avoids the use of threads.
A Timer sends messages to a target object at a particular, predefined rate. The
Timer places TimedEvents into the main thread's event queue. This means that, using
Timers, you can achieve simple concurrency without recourse to multithreading. The IFC
provides a simple way for you to connect components together without knowing their exact
types. Components implement the single, generic Target interface. The Target interface
allows arbitrary objects to communicate with each other. One of the IFC's main strengths

Page 370 Go To INDEX


is the ability to customize components. You are able to create a strong, custom look and
feel very easily with the IFC. You can do all this without having to extend the basic
components offered in the AWT or IFC.
The flexibility and range of windowing capabilities in the IFC is a huge improvement
on the AWT. Internal windows work within the Java application and can be layered on top
of one another, and become transparent. External windows are created by the underlying
environment's windowing system, but are still controlled by the Java application. Other
features of the IFC include:
User interface controls, including a color picker and font chooser
Animation
Multi-font text support
Object persistent system

• Advanced AWT
You can provide mouseless operation for users with JDK 1.1. Expert users may
prefer to use the keyboard, rather than the mouse, to issue commands and move between
components on screen. You should consider offering mouseless support for expert users
as it greatly enhances the usability of your GUI. For example, text fields into which the
user is currently typing are said to have the keyboard focus. The user traverses, or moves,
from field to field using the mouse or Tab key. They may just move the mouse pointer over
a field, or they may have to click inside that field. Using the Tab key is an alternative
traversal method. The components that can receive the focus are placed in a traversal
order. Pressing Tab moves the focus forward to the component next in order, while
Shift+Tab moves the focus back to the previous component.
Standard components return a boolean true from the isFocusTraversable method if
they can receive the focus, false otherwise. For your custom components, you override
isFocusTraversable() and return true or false depending on whether you want the
component to receive the focus or not. To grab the focus when an appropriate mouse
event occurs, use requestFocus(). When a keyboard event results in the focus being
gained, a FocusEvent event with the FOCUS_GAINED id is received.
Losing the focus due to a keyboard event results in a FocusEvent event with a
FOCUS_LOST id. You should then alert the user that the focus has been received, or lost,
through some visual change to the component. Shortcut keys can be enabled to trigger
menu commands under JDK 1.1.

You construct a MenuShortcut object, passing it a shortcut character and,


optionally, a boolean value stating whether Shift is to be used or not. Then you use the

Page 371 Go To INDEX


MenuItem constructor with the new MenuShortCut object as an extra parameter. When
the user presses the platform-dependent menu shortcut modifier key with the shortcut
character, then the menu command is issued. Popup menus are a new feature of JDK 1.1.
They are subclasses of the java.awt.Menu class.
They differ from ordinary menus in that they are not related to a menu bar, and
appear in the middle of the screen. You add the popup menu to the component parent as
you would any other component.

The menu is displayed using the show() method, with the parent component as a
parameter, and the x and y coordinate position relative to that component. You can use
the mouse event's pointer coordinate position to allow the menu to be popped up where
the pointer is.
While Java is fully platform-independent, there may arise occasions when you will
want to know more about the system on which your program is running. In
java.lang.System there is a series of methods for returning local system properties.
Properties include such things as the user's base directory, the host operating system, and
the version of the Java VM being run. Here is a list of the standard properties, which are
available on all systems.

These include information on:


The Java version and Java vendor
The Java home directory and class path
The user's name, home directory, and current working directory
The host IO system separators
The host operating system

Page 372 Go To INDEX


All property keys and property values are defined initially as String objects. You can
retrieve the relevant values of different types, such as boolean, by using the wrapper
classes for primitive types defined in java.lang. However, applets are restricted from
reading properties that may lead to security breaches, such as the user's home directory.
In addition to the standard properties, you can access system-dependent properties. And
you can set system property values too, using the System.setProperty() method. Let's look
at how to get Color and Font values from system properties. There is a static method
called getColor() in the Color class that loads a property from the system properties table
matching a string value passed to it. It interprets the property's value as a 24-bit integral
RGB color. Here is an example of a call to getColor(), looking for a property called
"Colors.backColor".

Let's see how you might set that property value. Here, you first create an instance
of the Properties class from a call to the static getProperties method of System.

Then you set the property value to the RGB equivalent of the octal value 0x00ff00
(green). Finally, you reset the system properties to reflect the new value of
Colors.backColor. Font values are specified using a string of the form "<FontName>-
<FontStyle>-<PointSize>". The styles are plain, italic, bold, and bolditalic. These style
strings are all lowercase, unlike Java variable names, so bolditalic is not to be spelt
boldItalic. Both the style and size are optional.
A Times Roman, bold, 16-point font is specified as "TimesRoman-bold-16", for
example. Reading and setting Font property values is the same as for reading and setting
Color values.

13.3. Using the Java packages

• The Java Archive tool (jar)


JAR - or Java Archive - is a file format that is used to aggregate multiple files into
one. JAR is based on the popular ZIP format and can be used for general archiving
purposes. ZIP files are generated by the PKZIP program or one of its variants. This form
of data compression is widely used on a number of computer platforms. Java uses it
particularly for the purpose of combining all of an applet's required files into a single file.
This considerably reduces the time required to download the applet. An applet often
consists of a number of files:
One or more .class files
Image files such as .jpg or .PNG
Audio files such as .au
Each time a browser downloads one of the applet's component files, an HTTP
transaction occurs. Each transaction takes a measurable amount of time. In addition, the
server might be busy when subsequent downloads are attempted. This could cause the

Page 373 Go To INDEX


applet to fail. JAR addresses this problem by combining all of an applet's files into a single
JAR file.
This results in the applet being downloaded in a single HTTP transaction. This
greatly improves the applet's execution speed. Like the ZIP file from which it was
developed, the JAR format also supports compression. This further cuts the download
time by reducing the file size. When you create a JAR file for an applet you have to modify
the <APPLET> tag in the relevant HTML page. The JAR file on the server is identified by
the ARCHIVE parameter. The name of the class file that starts execution of the applet still
has to be specified by the CODE parameter. However this class file is not stored
separately - it is extracted from the JAR file.

It is also possible to specify multiple JAR files with the ARCHIVE parameter. For
example, you might want to store all your class files in one archive and your multimedia
files in another. In this case you specify the JAR files in a comma-separated list.

After the JAR file is downloaded it is separated into its constituent files. As the
applet executes it searches the downloaded archive for required files. If it can't find a file it
then searches the server from which it was downloaded. This search can be directed by
the optional CODEBASE parameter. The Java archive tool jar is used to combine multiple
files into a single archive file. The syntax for the jar tool is very similar to that of the UNIX
tar command.
It is launched from the command line and always takes the following arguments:
The name of the destination JAR file
The names of one or more files to be archived
The advantage of using jar on a single file is the compression achieved - a small file
downloads more quickly. The jar command can take several options. The c option creates
a new or empty archive on the standard output. The t option lists the table of contents from
the standard output. The x file option extracts only the specified file, rather than all the
files. And the v option generates verbose output, which gives more information on the
files, such as their size and last modified date.
The jar tool generates a manifest file, which contains a list of all files present in the
archive. The manifest file is named META-INF/MANIFEST.INF, and it is always the first
entry in the JAR file. If you have a pre-existing manifest file that you want the jar tool to
use, you can specify it with the m option.

• Iner-applet communication
The greater the functionality built into an applet the larger it is likely to be. But large
applets take longer to download, and this can discourage their use. One solution to this

Page 374 Go To INDEX


problem is to split the functionality of the overall program between several smaller applets.
Java provides the following ways for applets to communicate with each other:
They can communicate with other applets running in the same Web page
They can interact with applets running in different Web pages in the same
browser
They can also communicate across a network with a server-side application
To find other applets Java provides two methods from the AppletContext class. The
getApplet method looks up another applet by name and returns the actual applet instance.
If the named applet does not exist the method returns a null value. The getApplets method
returns an Enumeration that lists all the accessible applets. The Enumeration interface is
part of the java.util package. Different browsers implement security policies in different
ways, and this may affect the way getApplets works. Usually getApplets returns a list of all
the applets that are running in a particular page and that originated on the same server.
An applet's name is specified in the HTML code of the page that calls it, not in the
Java code itself. You give an applet a name by specifying a NAME attribute within its
<APPLET> tag. Alternatively you can specify the name with a <PARAM> tag. Let's say we
have two applets on a page - a Transmitter and a Radio. The Transmitter applet has to
find Radio before it can transfer information to it. The name of the Radio applet is passed
to the getApplet method, and the return value is assigned to the radio variable.
This variable is then checked to make sure it is a valid instance of the Radio class.
If it is, a method of the Radio object is called to acknowledge the Transmitter.

It is possible for applets to communicate by using static variables and methods


within a common class. This is because the information in a static variable is the same in
all instances of the class. And static methods can not be overridden by any subclasses.
Using static methods and variables you can create a class that coordinates the activities of
several applets. For example, this class can maintain a list of all running applets. And it
can use a thread to synchronize activity among the applets.

Page 375 Go To INDEX


When using static variables for inter-applet communication the applets do not have
to be on the same Web page. The getApplet and getApplets methods require the applets
to be on the same page.
This can be a great advantage in certain circumstances. For example, using static
variables, you could build a navigation system for a Web site. You could then have a
navigation applet on each Web page, and a central applet coordinating all activity. Another
way for applets to communicate with each other is through a network connection. Like any
Java program, an applet can use the features of the java.net package to communicate
with a host computer. However the security restrictions imposed by Java limit the
usefulness of this approach. An applet can only communicate with the server that it was
downloaded from. It can't communicate directly with applets on other computers, even if
they were downloaded from the same server.

• Using URLs to access files


Using a browser to read Web pages can be interesting and fun. However while you
are connected to the Internet you are tying up bandwidth and possibly incurring
connection charges. One solution to this problem is to download Web files and view them
offline. Let's write a simple Java application that will download a file from the Internet and
write it to the local disk. This program will take two input parameters:
The URL of the file to be copied
The name the file will have on the local disk
You will need methods and classes from Java's network and I/O packages, so you
first import these packages. The program copies files from the Internet to disk, so you give
it the class name WebtoDisk. Then you write the main method, which accepts command
line arguments. The user is told what parameters the application expects. If the user does
not enter two parameters an error message is printed and the program terminates. The
main section of code is put in a try block to handle exceptions. A URL object is now
created from the absolute URL entered on the command line. Then a URLConnection
object is created with the URL object's openConnection method.

Page 376 Go To INDEX


Now that a connection has been made you will need an input stream to handle the
data. This is created with the URL object's openStream method.
You will also need to write the data to a file on the local disk. So you create a
FileOutputStream object from the second input parameter. Now that the data streams
have been set up, you can use them to transfer the data. The input stream's read method
reads the data one byte at a time. This method also controls the while loop - when the end
of the stream is reached a -1 is returned and the loop terminates. The file output stream's
write method writes the data to the disk, one byte at a time.
You then close the data streams and print a message to the standard output. You
then finish the code by handling the exceptions that are most likely to occur. The
MalformedURLException can be thrown by the URL object's constructor. And the
IOException can be thrown by the read, write, openStream, and openConnection
methods.

This application could have been written so as to use the URL to create the local
file name. It's possible to write a program that runs as both an applet and as an
application. Such a program can use URLs to locate files on both the Internet and on the
local disk.

• Converting applets into applications


There are several reasons why you might want to convert an applet you have
developed into an application. For example, it is easier to debug a standalone application
than an equivalent applet. Or you may wish to distribute it to users who do not use a Web

Page 377 Go To INDEX


browser. There are two basic steps that must be taken to convert an applet into an
application. First, you must provide it with a main method, as the Java interpreter requires
one. Second, you must provide a framework in which to display the applet. This is usually
done by extending the Frame object.
In most cases you will have to do more than just provide a main method and a
framework. This is because applets usually rely on features that the browser provides. So
you will in effect need to simulate a browser for any other than the simplest applets. The
Java API provides two interfaces that can be used to simulate a browser - AppletContext
and AppletStub. Both of these interfaces are in the java.applet package. The
AppletContext interface corresponds to the applet's environment.
This consists of the browser - or applet viewer program - and the HTML page that
calls the applet. The AppletStub interface is used to simulate the browser. It provides
methods, which an applet might call, such as getParameter and getAppletContext. Let's
create a class called BrowserSim that will simulate the browser environment. BrowserSim
is derived from Frame, which provides many useful window features.
It implements the AppletContext and AppletStub interfaces, which are necessary to
simulate the browser environment. It also implements the WindowListener interface, which
is required to handle window events. The BrowserSim class needs a main method to work
as an application. This method calls the BrowserSim constructor. This constructor takes
an argument list made up of the values entered on the command line.
The BrowserSim constructor can take a number of forms. If the applet is actually
contained within the BrowserSim class you can use the “this” keyword and set the size
explicitly. Alternatively you can write it so that you can specify the starting width and height
of the application. After instantiating the BrowserSim object the constructor calls Frame's
addWindowListener method. This method adds the specified window listener to receive
window events from this frame.

At the end of the BrowserSim class you handle the window events that could occur.

In this example it's only necessary to handle the windowClosed event, which
happens when the "close" icon is clicked. However, you still must write dummy handlers
for the other window events. The AppletStub interface defines a number of methods that
have to be implemented. The exact implementation of these methods depends on the
requirements of the application.

Page 378 Go To INDEX


The appletResize method is called because it is necessary to resize the Frame
when the applet is resized. It uses Frame's insets method to return values for border and
title bar thickness. The getAppletContext method gets a handler to the applet's context.

The getDocumentBase and getCodeBase methods both return URLs. There are
some platform-dependent issues to consider when writing the code for these methods. On
Windows computers the path to a file will contain backslashes. To convert to a URL these
slashes must be replaced with forward slashes. Another point to watch out for is that the
colon in a Windows filename should be replaced with a vertical bar. The vertical bar is also
known as the pipe symbol.
The getParameter method returns one of the applet's parameters. How you
implement this method depends on what you have done with the parameters. For
example, if you had created a hashtable called paramset you would use the get method.
The final AppletStub method is isActive. You can set this to always return true as the
applet is running when the application is running.

The AppletContext methods also have to be implemented. These methods are


used by an applet to obtain information from the applet's environment. The getApplet
method simply returns null as in this case the applet is not named. As you have seen
already, an applet's name is specified in the HTML code of the Web page that calls it, not
in the Java code itself. The getApplets method returns an Enumeration listing the
accessible applets. In this case the method returns an Enumeration of one element - the
applet itself. The getAudioClip method returns an audio clip. As this applet does not use
sound, the method simply returns a null value.

The getImage method takes a URL as a parameter and returns an image. This
involves downloading the image from the Internet - this would be the normal behaviour of
an applet. In the context of an application it is usually the case that images are stored
locally. So how you implement this method depends on whether or not you will be
converting URLs to filenames. In this case you use a method called localFileName to
convert the URL into a filename appropriate for the operating system. You then use two
methods from java.awt.Toolkit. This class is used to bind the abstract AWT classes to the

Page 379 Go To INDEX


toolkit implementation of the operating system. The getDefaultToolkit method returns the
default toolkit. And the getImage method returns the pixel data from the specified file.

There are two versions of the showDocument method. When it takes only a URL as
a parameter, it loads the document from that address into the browser.
public abstract void showDocument(URL url)
When showDocument takes a String as well as the URL, it loads the document in a
separate window specified by the string.
public abstract void showDocument(URL url, String target)
This method is not very likely to be used in an application, so it's not implemented
here. The showStatus method is used to display a message in the browser's status bar.
You can use a non-editable text area to display such messages.

Page 380 Go To INDEX

Você também pode gostar