Java
Java
Contents
• 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.
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.
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.
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.
• 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.
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".
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.
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.
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.
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.
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.
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.
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.
• 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
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
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
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.
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++:
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.
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.
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.
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.
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.
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.
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.
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.
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".
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.
• Inheritance in Java:
You can extend a class in Java to create subclasses.
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.
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.
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.
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
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).
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.
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.
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.
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.
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.
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.
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
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.
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.
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:
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.
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.
• 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.
• 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.
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
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.
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.
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).
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 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.
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.
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.
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.
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.
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.
Java's integers are stored in two's complement form, where the leftmost bit
indicates sign.
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.
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.
In bitwise XOR, "^", 1 is returned only when the bits are different from each other.
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
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.
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.
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.
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, "++"
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.
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.
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.
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.
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
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.
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.
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.
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.
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
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.
• 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
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.
• 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.
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
• 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
• 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
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.
• 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.
• 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.
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.
• 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
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();
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.
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.
• 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:
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
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.
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.
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.
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
Note how this method call enables mouse events for this new extended component.
Listeners are the objects that handle events fired from sources.
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
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.
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.
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.
You follow a similar procedure for the Reset and Exit buttons.
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.
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.
• 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
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);
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.
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.
• 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.
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.
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.
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.
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
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.
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.
• 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.
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 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.
This makes Width the first menu item on the menu. When it's clicked, the Width
menu opens.
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.
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.
The final code section in our program is the paint handler. This writes a string to the
screen with the drawString method.
You can also declare a variable, which references a String object and then set its
value later in another part of your program.
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.
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
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.
• 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.
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.
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.
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
• 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.
• 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.
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
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.
All classes derived from Thread can support multithreading. The Thread class
defines four default methods:
Init
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.
• 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.
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.
• 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
• 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.
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
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.
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.
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:
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.
• 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:
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
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:
• 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.
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)
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
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.
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.
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
A number of points are worth noting about this code. A socket connection is
established using the Socket class and it is called conn.
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.
• 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
• 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
• 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-
• 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
• 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);
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.
• 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
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.
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.
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.
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.
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
The remaining code provides support for handling lists of property change and
vetoable change listeners.
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.
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.
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.
• 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
• 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.
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
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.
Newly loaded drivers are automatically registered with the DriverManager as soon
as an instance of the driver is created.
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.
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
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.
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.
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.
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.
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
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
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.
• 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
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
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.
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
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.
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
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.
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.
This file, Account.idl, is used to manage bank accounts for the ABC bank. IDL
definitions of object interfaces contain:
Attributes
Operations
Operation parameters
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
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.
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.
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.
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.
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.
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.
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.
12.2. Animation
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.
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.
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.
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
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.
• 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
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.
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.
• 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.
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
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.
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:
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).
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".
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.
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.
• 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
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.
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.
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,
• 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.
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.
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.
• 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.
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.
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.
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
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.
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.
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 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
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.