Java Programming
Java Programming
OBJECT:
Objects are key to understanding object-oriented technology. Look around right now and you'll find
many examples of real-world objects: your dog, your desk, your television set, your bicycle.
Real-world objects share two characteristics: They all have state and behavior. Dogs have state (name,
color, breed, hungry) and behavior (barking, fetching, wagging tail). Bicycles also have state (current
gear, current pedal cadence, current speed) and behavior (changing gear, changing pedal cadence,
applying brakes). Identifying the state and behavior for real-world objects is a great way to begin
thinking in terms of object-oriented programming.
Take a minute right now to observe the real-world objects that are in your immediate area. For each
object that you see, ask yourself two questions: "What possible states can this object be in?" and "What
possible behavior can this object perform?". Make sure to write down your observations. As you do,
you'll notice that real-world objects vary in complexity; your desktop lamp may have only two possible
states (on and off) and two possible behaviors (turn on, turn off), but your desktop radio might have
additional states (on, off, current volume, current station) and behavior (turn on, turn off, increase
volume, decrease volume, seek, scan, and tune). You may also notice that some objects, in turn, will also
contain other objects. These real-world observations all translate into the world of object-oriented
programming.
A software object.
Software objects are conceptually similar to real-world objects: they too consist of state and related
behavior. An object stores its state in fields (variables in some programming languages) and exposes its
behavior through methods (functions in some programming languages). Methods operate on an object's
internal state and serve as the primary mechanism for object-to-object communication. Hiding internal
state and requiring all interaction to be performed through an object's methods is known as data
encapsulation — a fundamental principle of object-oriented programming.
By attributing state (current speed, current pedal cadence, and current gear) and providing methods for
changing that state, the object remains in control of how the outside world is allowed to use it. For
example, if the bicycle only has 6 gears, a method to change gears could reject any value that is less than
1 or greater than 6.
Bundling code into individual software objects provides a number of benefits, including:
Modularity: The source code for an object can be written and maintained independently of the source
code for other objects. Once created, an object can be easily passed around inside the system.
Information-hiding: By interacting only with an object's methods, the details of its internal
implementation remain hidden from the outside world.
Code re-use: If an object already exists (perhaps written by another software developer), you can use
that object in your program. This allows specialists to implement/test/debug complex, task-specific
objects, which you can then trust to run in your own code.
Pluggability and debugging ease: If a particular object turns out to be problematic, you can simply
remove it from your application and plug in a different object as its replacement. This is analogous to
fixing mechanical problems in the real world. If a bolt breaks, you replace it, not the entire machine.
CLASS:
In the real world, you'll often find many individual objects all of the same kind. There may be thousands
of other bicycles in existence, all of the same make and model. Each bicycle was built from the same set
of blueprints and therefore contains the same components. In object-oriented terms, we say that your
bicycle is an instance of the class of objects known as bicycles. A class is the blueprint from which
individual objects are created.
class Bicycle {
int cadence = 0;
int speed = 0;
int gear = 1;
cadence = newValue;
gear = newValue;
void printStates() {
The syntax of the Java programming language will look new to you, but the design of this class is based
on the previous discussion of bicycle objects. The fields cadence, speed, and gear represent the object's
state, and the methods (changeCadence, changeGear, speedUp etc.) define its interaction with the
outside world.
You may have noticed that the Bicycle class does not contain a main method. That's because it's not a
complete application; it's just the blueprint for bicycles that might be used in an application. The
responsibility of creating and using new Bicycle objects belongs to some other class in your application.
Here's a BicycleDemo class that creates two separate Bicycle objects and invokes their methods:
class BicycleDemo {
[Link](50);
[Link](10);
[Link](2);
[Link]();
[Link](50);
[Link](10);
[Link](2);
[Link](40);
[Link](10);
[Link](3);
[Link]();
Method
A method is a group of instructions that is given a name and can be called up at any point in a program
simply by quoting that name. For instance, we met an instruction in the last lesson that draws a straight
line on the screen. We could use this instruction three times to draw a simple triangle.
Better still, we could define a method to call this instruction three times and draw the triangle.
We would call the method triangle, presumably, and whenever we wanted a triangle drawn, we
would call the method.
People who have come to Java from other programming languages will almost certainly have
recognised this by now. The idea of methods appears in all programming languages, although
sometimes it goes under the name functions and sometimes under the name procedures. The
name methods is a throw-back to the language C++, from which Java was developed. In C++,
there is an object called a class which can contain methods. However, you will have noticed that
everything in Java is enclosed within a class of some sort (after all, the program contains the
instruction public class extends Applet), so the functions within it are called methods.
import [Link].*;
import [Link].*;
Just calling the method isn't enough. It has to be defined somewhere, or Java will not know
exactly what to do when it comes across the calculation(); command. The definition starts with
either the word public or private (at the moment, it doesn't matter which of these you use - we
will be going into these in more detail in a later section), followed by the method name
(calcuation in this case) and the pair of brackets again.
On the next line we have an open curly bracket followed by the statements that make up the
method. In this case, we only have one statement - the one that sets up the value of answer. Then
we have a closing curly bracket to show that we are at the end of the method.
Calling the method calculation() is equivalent to executing the statement answer = first * 2. In
this case, it is hardly worth defining a method to carry out one simple instruction. However, it
does show the minimum needed for a method to be defined in a program.
A common mistake - and one that I am always making! - is forgetting the closing curly bracket at
the end of the method definition. Here is the same definition that you saw above but with a
deliberate mistake:
import [Link].*;
import [Link].*;
The word after the public or private (i.e. the second word of the method declaration) is the
return type of the method. We will be dealing with values returned from methods in the next
section, so I don't want to say much about them here. The word void in this case indicates that
the method does not return a number or a value.
If you want to call a method using a simple instruction (as in the case of the method
calculation() above), then you should include the word void after the word public or private.
Parameters
The following program shows a Java program with a method to draw a triangle:
import [Link].*;
import [Link].*;
Messages
A single object alone is generally not very useful and usually appears as a component of a larger
program or application that contains many other objects. Through the interaction of these objects,
programmers achieve higher order functionality and more complex behavior. Your bicycle hanging from
a hook in the garage is just a bunch of titanium alloy and rubber; by itself the bicycle is incapable of any
activity. The bicycle is useful only when when another object (you) interacts with it (starts pedaling).
Software objects interact and communicate with each other by sending messages to each other.
When object A wants object B to perform one of B's methods, object A sends a message to
object B.
Sometimes the receiving object needs more information so that it knows exactly what to do--for
example, when you want to change gears on your bicycle, you have to indicate which gear you want.
This information is passed along with the message as parameters.
These three components are enough information for the receiving object to perform the desired
method. No other information or context is required.
An object's behavior is expressed through its methods, so (aside from direct variable access)
message passing supports all possible interactions between objects.
Objects don't need to be in the same process or even on the same machine to send and receive
messages back and forth to each other.
Abstraction is simplifying complex reality by modelling classes appropriate to the problem, and working
at the most appropriate level of inheritance for a given aspect of the problem. For example, Lassie the
Dog may be treated as a Dog much of the time, a Collie when necessary to access Collie-specific
attributes or behaviors, and as an Animal (perhaps the parent class of Dog) when counting Timmy's pets.
Encapsulation conceals the functional details of a class from objects that send messages to it. For
example, the Dog class has a bark() method. The code for the bark() method defines exactly how a bark
happens (e.g., by inhale() and then exhale(), at a particular pitch and volume). Timmy, Lassie's friend,
however, does not need to know exactly how she barks. Encapsulation is achieved by specifying which
classes may use the members of an object. The result is that each object exposes to any class a certain
interface - those members accessible to that class. The reason for encapsulation is to prevent clients of
an interface from depending on those parts of the implementation that are likely to change in future,
thereby allowing those changes to be made more easily, that is, without changes to clients. For example,
an interface can ensure that puppies can only be added to an object of the class Dog by code in that
class. Members are often specified as public, protected or private, determining whether they are
available to all classes, sub-classes or only the defining class. Some languages go further: Java uses the
default access modifier to restrict access also to classes in the same package, C# and [Link] reserve
some members to classes in the same assembly using keywords internal (C#) or Friend ([Link]), and
Eiffel and C++ allow one to specify which classes may access any member.
Inheritance
Different kinds of objects often have a certain amount in common with each other. Mountain bikes,
road bikes, and tandem bikes, for example, all share the characteristics of bicycles (current speed,
current pedal cadence, current gear). Yet each also defines additional features that make them
different: tandem bicycles have two seats and two sets of handlebars; road bikes have drop handlebars;
some mountain bikes have an additional chain ring, giving them a lower gear ratio.
Object-oriented programming allows classes to inherit commonly used state and behavior from other
classes. In this example, Bicycle now becomes the superclass of MountainBike, RoadBike, and
TandemBike. In the Java programming language, each class is allowed to have one direct superclass, and
each superclass has the potential for an unlimited number of subclasses:
The syntax for creating a subclass is simple. At the beginning of your class declaration, use the extends
keyword, followed by the name of the class to inherit from:
class MountainBike extends Bicycle {
This gives MountainBike all the same fields and methods as Bicycle, yet allows its code to focus
exclusively on the features that make it unique. This makes code for your subclasses easy to read.
However, you must take care to properly document the state and behavior that each superclass defines,
since that code will not appear in the source file of each subclass.
Abstract classes
There are situations in which you will want to define a superclass that declares the structure of a given
abstraction without providing a complete implementation of every method. That is, sometimes you will
want to create a superclass that only defines a generalized form that will be shared by all of its
subclasses, leaving it to each subclass to fill in the details. Such a class determines the nature of the
methods that the subclasses must implement. One way this situation can occur is when a superclass is
unable to create a meaningful implementation for a method. This is the case with the class Figure used
in the preceding example. The definition of area( ) is simply a placeholder. It will not compute and
display the area of any type of object.
As you will see as you create your own class libraries, it is not uncommon for a method to have no
meaningful definition in the context of its superclass. You can handle this situation two ways. One
way, as shown in the previous example, is to simply have it report a warning message. While this
approach can be useful in certain situations—such as debugging—it is not usually appropriate. You
may have methods which must be overridden by the subclass in order for the subclass to have any
meaning. Consider the class Triangle. It has no meaning if area( ) is not defined. In this case, you
want some way to ensure that a subclass does, indeed, override all necessary methods. Java's
solution to this problem is the abstract method.
You can require that certain methods be overridden by subclasses by specifying the abstract type
modifier. These methods are sometimes referred to as subclasser responsibility because they have
no implementation specified in the superclass. Thus, a subclass must override them—it cannot
simply use the version defined in the superclass. To declare an abstract method, use this general
form:
class B extends A {
void callme() {
[Link]("B's implementation of callme.");
}
}
class AbstractDemo {
public static void main(String args[]) {
B b = new B();
[Link]();
[Link]();
}
}
Notice that no objects of class A are declared in the program. As mentioned, it is not possible to
instantiate an abstract class. One other point: class A implements a concrete method called
callmetoo( ). This is perfectly acceptable. Abstract classes can include as much implementation as
they see fit.
Polymorphism
Generally, the ability to appear in many forms. In object-oriented programming, polymorphism
refers to a programming language's ability to process objects differently depending on their data type
or class. More specifically, it is the ability to redefine methods for derived classes. For example, given a
base class shape, polymorphism enables the programmer to define different area methods for any
number of derived classes, such as circles, rectangles and triangles. No matter what shape an object is,
applying the area method to it will return the correct results. Polymorphism is considered to be a
requirement of any true object-oriented programming language (OOPL).
1) A variable with a given name may be allowed to have different forms and the program can determine
which form of the variable to use at the time of execution. For example, a variable named USERID may
be capable of being either an integer (whole number) or a string of characters (perhaps because the
programmer wants to allow a user to enter a user ID as either an employee number - an integer - or
with a name - a string of characters). By giving the program a way to distinguish which form is being
handled in each case, either kind can be recognized and handled.
2) A named function can also vary depending on the parameters it is given. For example, if given a
variable that is an integer, the function chosen would be to seek a match against a list of employee
numbers; if the variable were a string, it would seek a match against a list of names. In either case, both
functions would be known in the program by the same name. This type of polymorphism is sometimes
known as overloading.
Following is the code for a class called SimplePoint that represents a point in 2D space:
You create an object from a class such as SimplePoint by instantiating the class. When you create a
new SimplePoint object (we show you how shortly), space is allocated for the object and its
members x and y. In addition, the x and y members inside the object are initialized to 0 because
of the assignment statements in the declarations of these two members.
This diagram shows the difference between primitive types and reference types. Both width and height
are integers and are fully contained within SimpleRectangle. On the other hand, origin simply
references a SimplePoint object somewhere else. The SimplePoint and SimpleRectangle classes as
shown are simplistic implementations for these classes. Both should provide a mechanism for initializing
their members to values other than 0. Additionally, SimpleRectangle could provide a method for
computing its area, and because SimpleRectangle creates a SimplePoint when it's created, the class
should provide for the clean up of the SimplePoint when SimpleRectangle gets cleaned up. So, here's
a new version of SimplePoint, called Point, that contains a constructor which you can use to initialize a
new Point to a value other than (0,0):
Now, let's beef up the SimpleRectangle class. Here's a new version of SimpleRectangle, called
Rectangle, that contains four constructors, a method to "move" the rectangle, a method to compute
the area of the rectangle, and a finalize method to provide for clean up:
public class Rectangle {
public int width = 0;
public int height = 0;
public Point origin;
// four constructors
public Rectangle() {
origin = new Point(0, 0);
}
public Rectangle(Point p) {
origin = p;
}
public Rectangle(int w, int h) {
this(new Point(0, 0), w, h);
}
public Rectangle(Point p, int w, int h) {
origin = p;
width = w;
height = h;
}
// a method for moving the rectangle
public void move(int x, int y) {
origin.x = x;
origin.y = y;
}
// a method for computing the area of the rectangle
public int area() {
return width * height;
}
// clean up!
protected void finalize() throws Throwable {
origin = null;
[Link]();
}
}
Creating Objects
In Java, you create an object by creating an instance of a class or, in other words, instantiating a class.
Often, you will see a Java object created with a statement like the following, which creates a new
Rectangle object from the Rectangle class given in the previous section:
1. Declaration: Rectangle rect is a variable declaration that declares to the compiler that the
name rect will be used to refer to a Rectangle object. Notice that a class name is used as the
variable's type.
2. Instantiation: new is a Java operator that creates the new object (allocates space for it).
3. Initialization: Rectangle() is a call to Rectangle's constructor, which initializes the object.
Declaring an Object
The declaration of an object is not a necessary part of object creation, although it often appears on the
same line. Like other variable declarations, object declarations can also appear alone, like this:
Rectangle rect;
Variables and Data Types in the previous lesson discussed variable declarations in detail. To declare an
object, you just follow the same rules and declare a variable to refer to that object by declaring its type
and name:
type name
In Java, classes and interfaces can be used as data types. So type can be the name of a class such as the
Rectangle class or the name of an interface. Classes and interfaces are both reference types (the
variable's actual value is a reference to the value or set of values represented by the variable). In this
tutorial, a reference may also be called an object reference or an array reference, depending on the data
to which the reference refers.
Declarations notify the compiler that you will use name to refer to a variable whose type is type.
Declarations do not create new objects. Rectangle rect does not create a new Rectangle object,
just a variable named rect to hold a Rectangle object. To create a Rectangle object, or any other
object, use the new operator.
Instantiating an Object
The new operator instantiates a class by allocating memory for a new object of that type. new requires
a single, postfix argument: a call to a constructor. Each Java class provides a set of constructors used to
initialize new objects of that type. The new operator creates the object, and the constructor initializes it.
Here's an example of using the new operator to create a Rectangle object:
Access Specifiers
One of the techniques in object-oriented programming is encapsulation. It concerns the hiding of data in
a class and making this class available only through methods. In this way the chance of making
accidental mistakes in changing values is minimized. Java allows you to control access to classes,
methods, and fields via so-called access specifiers.
public
protected
default (no specifier)
private
public
public classes, methods, and fields can be accessed from everywhere. The only constraint is that a file
with Java source code can only contain one public class whose name must also match with the
filename. If it exists, this public class represents the application or the applet, in which case the public
keyword is necessary to enable your Web browser or appletviewer to show the applet. You use public
classes, methods, or fields only if you explicitly want to offer access to these entities and if this access
cannot do any harm. An example of a square determined by the position of its upper-left corner and its
size:
protected
protected methods and fields can only be accessed within the same class to which the methods and
fields belong, within its subclasses, and within classes of the same package, but not from anywhere else.
You use the protected access level when it is appropriate for a class's subclasses to have access to the
method or field, but not for unrelated classes.
private
private methods and fields can only be accessed within the same class to which the methods and fields
belong. private methods and fields are not visible within subclasses and are not inherited by subclasses.
So, the private access specifier is opposite to the public access specifier. It is mostly used for
encapsulation: data are hidden within the class and accessor methods are provided. An example, in
which the position of the upper-left corner of a square can be set or obtained by accessor methods, but
individual coordinates are not accessible to the user.
Static Members
In addition to (instance) members, a Java class can include static members that are
attached to the class rather than instances of the class. We have already seen how static final fields
provide a simple way to define constants.
The static members of a class are not included in the template used to create class
instances. There is only one copy of a static field for an entire class--regardless of how many
instances of the class are created (possibly none). Similarly, the code in a static method cannot
refer to this or to the fields of this because there is no class instance to serve as the receiver for
such an access./footnoteOf course, a static method can invoke an instance method (or extract an
instance field) of class if it explicitly specifies a receiver for the invocation.
Static methods are useful because we occasionally need to write methods where the
primary argument is either a primitive value or an object from a class that we cannot modify. For
example, the library method [Link](int i) converts an int to the corresponding String. Since
an int is not an object, there is no int class to hold such a method.1.7Consequently, the Java library
provides a static method toString(int i) in the class Integer.
Similarly, an operation
Finally, all operations on arrays must be expressed in static (procedural) form because array
types do not have conventional class definitions; they are built-in to the Java virtual machine. We
will discuss arrays in Chapter 2 when we address imperative programming in Java.
class MyUtils {
...
//================================================= mean
public static double mean(int[] p) {
int sum = 0; // sum of all the elements
for (int i=0; i<[Link]; i++) {
sum += p[i];
}
return ((double)sum) / [Link];
}//endmethod mean
...
}
Constructors
When you create a new instance (a new object) of a class using the new keyword, a
constructor for that class is called. Constructors are used to initialize the instance variables
(fields) of an object. Constructors are similar to methods, but with some important differences.
Constructor name is class name. A constructors must have the same name as the class its in.
Default constructor. If you don't define a constructor for a class, a default parameterless
constructor is automatically created by the compiler. The default constructor calls the default
parent constructor (super()) and initializes all instance variables to default value (zero for
numeric types, null for object references, and false for booleans).
Default constructor is created only if there are no constructors. If you define any constructor
for your class, no default constructor is automatically created.
Differences between methods and constructors.
o There is no return type given in a constructor signature (header). The value is this object
itself so there is no need to indicate a return value.
o There is no return statement in the body of the constructor.
o The first line of a constructor must either be a call on another constructor in the same
class (using this), or a call on the superclass constructor (using super). If the first line is
neither of these, the compiler automatically inserts a call to the parameterless super
class constructor.
These differences in syntax between a constructor and method are sometimes hard to see
when looking at the source. It would have been better to have had a keyword to clearly
mark constructors as some languages do.
this(...) - Calls another constructor in same class. Often a constructor with few parameters will
call a constructor with more parameters, giving default values for the missing parameters. Use
this to call other constructors in the same class.
super(...). Use super to call a constructor in a parent class. Calling the constructor for the
superclass must be the first statement in the body of a constructor. If you are satisfied with the
default constructor in the superclass, there is no need to make a call to it because it will be
supplied automatically.
The Java compiler inserts a call to the parent constructor (super) if you don't have a constructor
call as the first statement of you constructor. The following is the equivalent of the constuctor
above.
Finalize method
protected void finalize() throws Throwable {}
try {
} finally {
[Link]();
any exception thrown by finalize() during garbage collection halts the finalization but is
otherwise ignored
finalize() is never run more than once on any object
UNIT-II
ARRAYS
Creating Arrays:
There are three steps to creating an array, declaring it, allocating it and initializing it.
Declaring Arrays:
Like other variables in Java, an array must have a specific type like byte, int, String or
double. Only variables of the appropriate type can be stored in an array. You cannot
have an array that will store both ints and Strings, for instance.
Like all other variables in Java an array must be declared. When you declare an array
variable you suffix the type with [] to indicate that this variable is an array. Here are
some examples:
int[] k;
float[] yt;
String[] names;
In other words you declare an array like you'd declare any other variable except you append
brackets to the end of the variable type.
Allocating Arrays
Declaring an array merely says what it is. It does not create the array. To actually create the
array (or any other object) use the new operator. When we create an array we need to tell the
compiler how many elements will be stored in it. Here's how we'd create the variables
declared above: new
k = new int[3];
yt = new float[7];
names = new String[50];
The numbers in the brackets specify the dimension of the array; i.e. how many slots it has to
hold values. With the dimensions above k can hold three ints, yt can hold seven floats and
names can hold fifty Strings.
Initializing Arrays
Individual elements of the array are referenced by the array name and by an integer which
represents their position in the array. The numbers we use to identify them are called
subscripts or indexes into the array. Subscripts are consecutive integers beginning with 0. Thus
the array k above has elements k[0], k[1], and k[2]. Since we started counting at zero there is
no k[3], and trying to access it will generate an ArrayIndexOutOfBoundsException. subscripts
indexes k k[0] k[1] k[2] k[3] ArrayIndexOutOfBoundsException
You can use array elements wherever you'd use a similarly typed variable that wasn't
part of an array.
Here's how we'd store values in the arrays we've been working with:
k[0] = 2;
k[1] = 5;
k[2] = -2;
yt[6] = 7.5f;
names[4] = "Fred";
This step is called initializing the array or, more precisely, initializing the elements of
the array. Sometimes the phrase "initializing the array" would be reserved for when we
initialize all the elements of the array.
For even medium sized arrays, it's unwieldy to specify each element individually. It is
often helpful to use for loops to initialize the array. For instance here is a loop that fills
an array with the squares of the numbers from 0 to 100.
Two dimensional arrays are declared, allocated and initialized much like one dimensional
arrays. However we have to specify two dimensions rather than one, and we typically use two
nested for loops to fill the array. for
The array examples above are filled with the sum of their row and column indices.
Here's some code that would create and fill such an array:
class FillArray {
Multidimensional Arrays
You don't have to stop with two dimensional arrays. Java lets you have arrays of three, four or
more dimensions. However chances are pretty good that if you need more than three
dimensions in an array, you're probably using the wrong data structure. Even three
dimensional arrays are exceptionally rare outside of scientific and engineering applications.
The syntax for three dimensional arrays is a direct extension of that for two-
dimensional arrays. Here's a program that declares, allocates and initializes a three-
dimensional array:
class Fill3DArray {
int[][][] M;
M = new int[4][5][3];
Strings
Strings, which are widely used in Java programming, are a sequence of characters. In the Java
programming language, strings are objects.
The Java platform provides the String class to create and manipulate strings.
Creating Strings
The most direct way to create a string is to write:
As with any other object, you can create String objects by using the new keyword and a
constructor. The String class has thirteen constructors that allow you to provide the initial value of
the string using different sources, such as an array of characters:
String Length
Methods used to obtain information about an object are known as accessor methods. One accessor
method that you can use with strings is the length() method, which returns the number of characters
contained in the string object. After the following two lines of code have been executed, len equals 17:
Concatenating Strings
The String class includes a method for concatenating two strings:
[Link](string2);
This returns a new string that is string1 with string2 added to it at the end.
You can also use the concat() method with string literals, as in:
"Hello, world!"
The + operator is widely used in print statements. For example:
Packages
Package = directory. Java classes can be grouped together in packages. A package name is the
same as the directory (folder) name which contains the .java files. You declare packages when
you define your Java program, and you name the packages you want to use from other libraries
in an import statement.
Package declaration
The first statement, other than comments, in a Java source file, must be the package declaration.
Following the optional package declaration, you can have import statements, which allow you to
specify classes from other packages that can be referenced without qualifying them with their
package.
Default package. Altho all Java classes are in a directory, it's possible to omit the package
declaration. For small programs it's common to omit it, in which case Java creates what it calls a
default package. Sun recommends that you do not use default packages.
package illustration;
import [Link].*;
import [Link].*; // Make all classes visible altho only one is used.
class ImportTest {
public static void main(String[] args) {
[Link](null, "Hi");
[Link](0);
}
}
Classes can be specified explicitly on import instead of using the wildcard character.
class ImportTest {
public static void main(String[] args) {
[Link](null, "Hi");
[Link](0);
}
}
class ImportTest {
public static void main(String[] args) {
[Link](null, "Hi");
[Link](0);
}
}
Javadoc Comments are specific to the Java language and provide a means for a programmer to
fully document his / her source code as well as providing a means to generate an Application
Programmer Interface (API) for the code using the javadoc tool that is bundled with the JDK.
These comments have a special format which we will discuss in this section and then in the
following section we will look at how to use the javadoc tool to generate an API.
/**
* A Container is an object that contains other objects.
* @author Trevor Miller
* @version 1.2
* @since 0.3
*/
public abstract class Container {
/**
* Create an empty container.
*/
protected Container() { }
/**
* Return the number of elements contained in this container.
* @return The number of objects contained
*/
public abstract int count();
/**
* Clear all elements from this container.
* This removes all contained objects.
*/
public abstract void clear();
/**
* Accept the given visitor to visit all objects contained.
* @param visitor The visitor to accept
*/
public abstract void accept(final Visitor visitor);
/**
* Return an iterator over all objects conatined.
* @return An iterator over all objects
*/
public abstract Iterator iterator();
/**
* Determine whether this container is empty or not.
* @return <CODE>true</CODE> if the container is empty:
* <CODE>count == 0</CODE>, <CODE>false</CODE>
* otherwise
*/
public boolean isEmpty() {
return ([Link]() == 0);
}
/**
* Determine whether this container is full.
* @return <CODE>true</CODE> if conatiner is full,
* <CODE>false</CODE> otherwise
*/
public boolean isFull() {
return false;
}
We will now discuss the descriptions of a Javadoc comment first before looking at the different
tags and their uses.
Descriptions
The description should give a concise summary of the item being commented. It should be
written in simple and clear English using correct spelling and grammar. Punctuation is required.
There are some important style guidelines to bear in mind:
Take a look at the example above again and you'll see that the first sentence is a brief descriptive
summary of each item.
Omission of parenthesis
When referring to a method that has no parameters or a method which has multiple forms
(method overloading) it is acceptable and even encouraged to simply omit the parenthesis.
Consider the following example:
This is the correct way of doing it as opposed to the incorrect way in the next example:The
<code>add()</code> method inserts items into the vector
Inheritance
Different kinds of objects often have a certain amount in common with each other. Mountain
bikes, road bikes, and tandem bikes, for example, all share the characteristics of bicycles
(current speed, current pedal cadence, current gear). Yet each also defines additional features
that make them different: tandem bicycles have two seats and two sets of handlebars; road
bikes have drop handlebars; some mountain bikes have an additional chain ring, giving them a
lower gear ratio.
This gives MountainBike all the same fields and methods as Bicycle, yet allows its code to
focus exclusively on the features that make it unique. This makes code for your subclasses easy
to read. However, you must take care to properly document the state and behavior that each
superclass defines, since that code will not appear in the source file of each subclass.
Java Inheritance defines an is-a relationship between a superclass and its subclasses. This means
that an object of a subclass can be used wherever an object of the superclass can be used. Class
Inheritance in java mechanism is used to build new classes from existing classes. The
inheritance relationship is transitive: if class x extends class y, then a class z, which extends class
x, will also inherit from class y.
For example a car class can inherit some properties from a General vehicle class. Here we find
that the base class is the vehicle class and the subclass is the more specific car class. A subclass
must use the extends clause to derive from a super class which must be written in the header of
the subclass definition. The subclass inherits members of the superclass and hence promotes
code reuse. The subclass itself can add its own new behavior and properties. The
[Link] class is always at the top of any Class inheritance hierarchy.
class Box {
double width;
double height;
double depth;
Box() {
}
Box(double w, double h, double d) {
width = w;
height = h;
depth = d;
}
void getVolume() {
[Link]("Volume is : " + width * height * depth);
}
}
double weight;
MatchBox() {
}
MatchBox(double w, double h, double d, double m) {
super(w, h, d);
weight = m;
}
public static void main(String args[]) {
MatchBox mb1 = new MatchBox(10, 10, 10, 10);
[Link]();
[Link]("width of MatchBox 1 is " + [Link]);
[Link]("height of MatchBox 1 is " + [Link]);
[Link]("depth of MatchBox 1 is " + [Link]);
[Link]("weight of MatchBox 1 is " + [Link]);
}
}
Output
Volume is : 1000.0
width of MatchBox 1 is 10.0
height of MatchBox 1 is 10.0
depth of MatchBox 1 is 10.0
weight of MatchBox 1 is 10.0
1. Private members of the superclass are not inherited by the subclass and can only be indirectly
accessed.
2. Members that have default accessibility in the superclass are also not inherited by subclasses
in other packages, as these members are only accessible by their simple names in subclasses
within the same package as the superclass.
3. Since constructors and initializer blocks are not members of a class, they are not inherited by a
subclass.
4. A subclass can extend only one superclass
class Vehicle {
// Instance fields
int noOfTyres; // no of tyres
private boolean accessories; // check if accessorees present or not
protected String brand; // Brand of the car
// Static fields
private static int counter; // No of Vehicle objects created
// Constructor
Vehicle() {
[Link]("Constructor of the Super class called");
noOfTyres = 5;
accessories = true;
brand = "X";
counter++;
}
// Instance methods
public void switchOn() {
accessories = true;
}
public void switchOff() {
accessories = false;
}
public boolean isPresent() {
return accessories;
}
private void getBrand() {
[Link]("Vehicle Brand: " + brand);
}
// Static methods
public static void getNoOfVehicles() {
[Link]("Number of Vehicles: " + counter);
}
}
Output
Class hierarchy
o class [Link]
o class [Link] (implements [Link])
o class [Link] (implements [Link], [Link])
o class [Link]
o class [Link]
o class [Link] (implements [Link])
o class [Link]
o class [Link]
o class [Link]
o class [Link] (implements [Link])
o class [Link] (implements [Link])
o class [Link] (implements [Link])
o class [Link] (implements [Link])
o class [Link] (implements [Link])
o class [Link] (implements [Link])
o class [Link] (implements [Link])
o class [Link]
o class [Link] (implements [Link], [Link])
o class [Link] (implements [Link])
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link] (implements [Link])
o class [Link]
o class [Link] (implements [Link], [Link],
[Link])
o class [Link] (implements [Link], [Link])
o class [Link]
o class [Link] (implements [Link])
o class [Link]
o class [Link]
o class [Link]
o class [Link] (implements [Link])
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
o class [Link]
Polymorphism
o The dictionary definition of polymorphism refers to a principle in biology in which an organism
or species can have many different forms or stages. This principle can also be applied to object-
oriented programming and languages like the Java language. Subclasses of a class can define
their own unique behaviors and yet share some of the same functionality of the parent class.
o Polymorphism can be demonstrated with a minor modification to the Bicycle class. For example,
a printDescription method could be added to the class that displays all the data currently stored
in an instance.
o public void printDescription(){
o [Link]("\nBike is in gear " + [Link] + " with a cadence of " +
o [Link] + " and travelling at a speed of " + [Link] + ". ");
o }
o To demonstrate polymorphic features in the Java language, extend the Bicycle class with a
MountainBike and a RoadBike class. For MountainBike, add a field for suspension, which is a
String value that indicates if the bike has a front shock absorber, Front. Or, the bike has a front
and back shock absorber, Dual.
o Here is the updated class:
o public class MountainBike extends Bicycle{
o private String suspension;
o
o public MountainBike(int startCadence, int startSpeed, int startGear, String suspensionType){
o super(startCadence, startSpeed, startGear);
o [Link](suspensionType);
o }
o
o public String getSuspension(){
o return [Link];
o }
o
o public void setSuspension(String suspensionType){
o [Link] = suspensionType;
o }
o
o public void printDescription(){
o [Link]();
o [Link]("The MountainBike has a " + getSuspension()
o + " suspension.");
o }
o }
o Note the overridden printDescription method. In addition to the information provided before,
additional data about the suspension is included to the output.
o Next, create the RoadBike class. Because road or racing bikes have skinny tires, add an attribute
to track the tire width. Here is the RoadBike class:
o public class RoadBike extends Bicycle{
o private int tireWidth; // In millimeters (mm)
o
o public RoadBike(int startCadence, int startSpeed, int startGear, int newTireWidth){
o super(startCadence, startSpeed, startGear);
o [Link](newTireWidth);
o }
o
o public int getTireWidth(){
o return [Link];
o }
o
o public void setTireWidth(int newTireWidth){
o [Link] = newTireWidth;
o }
o
o public void printDescription(){
o [Link]();
o [Link]("The RoadBike has " + getTireWidth()
o + " MM tires.");
o }
o
o }
o Note that once again, the printDescription method has been overridden. This time, information
about the tire width is displayed.
o To summarize, there are three classes: Bicycle, MountainBike, and RoadBike. The two subclasses
override the printDescription method and print unique information.
o Here is a test program that creates three Bicycle variables. Each variable is assigned to one of
the three bicycle classes. Each variable is then printed.
o public class TestBikes {
o public static void main(String[] args){
o Bicycle bike01, bike02, bike03;
o
o bike01 = new Bicycle(20, 10, 1);
o bike02 = new MountainBike(20, 10, 5, "Dual");
o bike03 = new RoadBike(40, 20, 8, 23);
o
o [Link]();
o [Link]();
o [Link]();
o
o }
o }
o The following is the output from the test program:
o Bike is in gear 1 with a cadence of 20 and travelling at a speed of 10.
o
o Bike is in gear 5 with a cadence of 20 and travelling at a speed of 10.
o The MountainBike has a Dual suspension.
o
o Bike is in gear 8 with a cadence of 40 and travelling at a speed of 20.
o The RoadBike has 23 MM tires.
o The Java virtual machine (JVM) calls the appropriate method for the object that is referred to in
each variable. It does not call the method that is defined by the variable's type. This behavior is
referred to as virtual method invocation and demonstrates an aspect of the important
polymorphism features in the Java language.
Dynamic binding
Dynamic binding and static binding have to do with inheritance. In Java, any derived class object can be
assigned to a base class variable. For instance, if you have a class named Animal from which you derived
the class Dog, you can do this:
The variable on the left is type Animal, but the object on the right is type Dog. As long as the variable on
the left is a base class of Dog, you are allowed to do that. Being able to do assignments like that sets up
what is called "polymorphic behavior": if the Dog class has a method that is the same as a method in the
Animal class, then the version of the method in the Dog class will be called. For instance, if both classes
define a method called show(), and you do this:
[Link]();
the version of show() in the Dog class will be called. Even though you are using an Animal variable type
to call the method show(), the version of show() in the Animal class won't be executed. Instead, it is the
version of show() in the Dog class that will be executed. The type of the object that is assigned to the
Animal variable determines the method that is called.
So, when the compiler scans the program and sees a statement like this:
[Link]();
it knows that myAnimal is of type Animal, but the compiler also knows that myAnimal can be a
reference to any class derived from Animal. Therefore, the compiler doesn't know what version of
show() that statement is calling. It's not until the assignment:
is executed that the version of show() is determined. Since the assignment doesn't occur until runtime,
it's not until runtime that the correct version of show() is known. That is known as "dynamic binding" or
"late binding": it's not until your program performs some operation at runtime that the correct version
of a method can be determined. In Java, most uses of inheritance involve dynamic binding.
"Static binding" or "early binding" occurs when the compiler can readily determine the correct version
of something during compile time, i.e. before the program is executed. In Java, member variables have
static binding because Java does not allow for polymorphic behavior with member variables. That means
if both the Animal class and the Dog class have a member variable with the same name, it's the base
class version that is used. For instance, if you set up the necessary ingredients for polymorphic behavior:
and both the Animal and Dog classes have a String member variable 'type', then if you do this:
the value of 'type' can be fully determined by the compiler. Because polymorphic behavior is not
allowed for member variables, that statement is referring to the value of 'type' in the Animal class--not
the Dog's value for 'type'. The result is: with member variables, it's the type of the variable(e.g.
myAnimal) that determines which version is called--not the type of the object the variable refers to(e.g.
Dog). When the compiler is able to figure out the correct version of something during compilation, that's
known as static binding.
Here is an example of both dynamic and static binding:
class Animal
[Link] = type;
final Keyword
The final keyword has slightly different meanings depending on the context, but in general it says “This
cannot be changed.” You might want to prevent changes for two reasons: design or efficiency. Because
these two reasons are quite different, it’s possible to misuse the final keyword.
The following sections discuss the three places where final can be used: for data, methods and for a
class.
Final data
Many programming languages have a way to tell the compiler that a piece of data is “constant.” A
constant is useful for two reasons:
In the case of a compile-time constant the compiler is allowed to “fold” the constant value into any
calculations in which it’s used; that is, the calculation can be performed at compile time, eliminating
some run-time overhead. In Java, these sorts of constants must be primitives and are expressed using
the final keyword. A value must be given at the time of definition of such a constant.
A field that is both static and final has only one piece of storage that cannot be changed.
When using final with object handles rather than primitives the meaning gets a bit confusing. With a
primitive, final makes the value a constant, but with an object handle, final makes the handle a
constant. The handle must be initialized to an object at the point of declaration, and the handle can
never be changed to point to another object. However, the object can be modified; Java does not
provide a way to make any arbitrary object a constant. (You can, however, write your class so that
objects have the effect of being constant.) This restriction includes arrays, which are also objects.
class Value {
int i = 1;
}
[Link]("fd1");
[Link]("Creating new FinalData");
FinalData fd2 = new FinalData();
[Link]("fd1");
[Link]("fd2");
}
} ///:~
Since i1 and I2 are final primitives with compile-time values, they can both be used as compile-time
constants and are not different in any important way. I3 is the more typical way you’ll see such
constants defined: public so they’re usable outside the package, static to emphasize that there’s only
one, and final to say that it’s a constant. Note that final static primitives with constant initial values (that
is, compile-time constants) are named with all capitals by convention. Also note that i5 cannot be known
at compile time, so it is not capitalized.
Just because something is final doesn’t mean that its value is known at compile-time. This is
demonstrated by initializing i4 and i5 at run-time using randomly generated numbers. This portion of
the example also shows the difference between making a final value static or non- static. This difference
shows up only when the values are initialized at run-time, since the compile-time values are treated the
same by the compiler. (And presumably optimized out of existence.) The difference is shown in the
output from one run:
fd1: i4 = 15, i5 = 9
Creating new FinalData
fd1: i4 = 15, i5 = 9
fd2: i4 = 10, i5 = 9
Final methods
There are two reasons for final methods. The first is to put a “lock” on the method to prevent any
inheriting class from changing its meaning. This is done for design reasons when you want to make sure
that a method’s behavior is retained during inheritance and cannot be overridden.
The second reason for final methods is efficiency. If you make a method final, you are allowing the
compiler to turn any calls to that method into inline calls. When the compiler sees a final method call it
can (at its discretion) skip the normal approach of inserting code to perform the method call mechanism
(push arguments on the stack, hop over to the method code and execute it, hop back and clean off the
stack arguments, and deal with the return value) and instead replace the method call with a copy of the
actual code in the method body. This eliminates the overhead of the method call. Of course, if a method
is big, then your code begins to bloat and you probably won’t see any performance gains from inlining
since any improvements will be dwarfed by the amount of time spent inside the method. It is implied
that the Java compiler is able to detect these situations and choose wisely whether to inline a final
method. However, it’s better to not trust that the compiler is able to do this and make a method final
only if it’s quite small or if you want to explicitly prevent overriding.
Any private methods in a class are implicitly final. Because you can’t access a private method, you can’t
override it (the compiler gives an error message if you try). You can add the final specifier to a private
method but it doesn’t give that method any extra meaning.
Final classes
When you say that an entire class is final (by preceding its definition with the final keyword), you state
that you don’t want to inherit from this class or allow anyone else to do so. In other words, for some
reason the design of your class is such that there is never a need to make any changes, or for safety or
security reasons you don’t want subclassing. Alternatively, you might be dealing with an efficiency issue
and you want to make sure that any activity involved with objects of this class is as efficient as possible.
//: [Link]
// Making an entire class final
class SmallBrain {}
You can add the final specifier to a method in a final class, but it doesn’t add any meaning.
Abstract classes
Abstract class is a class that has no direct instances, but whose descendants may have direct instances.
There are case i which it is useful to define classes for which the programmer never intends to
instantiate any objects; because such classes normally are used as bae-classes in inheritance hierarchies,
we call such classes abstract classes These classes cannot be used to instantiate objects; because
abstract classes are incomplete. Derived classes called concrete classesmust define the missing pieces.
Abstract classes normally contain one or more abstract methods or abstract properties, such methods or
properties do not provide implementations, but our derived classes must override inherited abstract
methods or properties to enable obejcts ot those derived classes to be instantiated, not to override
those methods or properties in derived classes is syntax error, unless the derived class also is an abstract
class.
In some cases, abstract classes constitute the top few levels of the hierarchy, for Example abstract class
Shape with abstract method Draw() has tow derived abstract classe Shape2D & Shape3D inherites the
method Draw() & also do not provide any implementation for it. Now we have normal classes Rectangle,
Square & Circle inherites from Shape2D, and another group of classes Sphere, Cylinder & Cube inherites
from Shape3D. All classes at the bottom of the hierarchy must override the abstract method Draw().
Example:
}
UNIT-III
The Object class
The Object class sits at the top of the class hierarchy tree in the Java development
environment. Every class in the Java system is a descendent (direct or indirect) of the Object
class. The Object class defines the basic state and behavior that all objects must have, such as
the ability to compare oneself to another object, to convert to a string, to wait on a condition
variable, to notify other objects that a condition variable has changed, and to return the object's
class.
Use the equals to compare two objects for equality. This method returns true if the
objects are equal, false otherwise. Note that equality does not mean that the objects
are the same object. Consider this code that tests two Integers, one and
anotherOne, for equality:
if ([Link](anotherOne))
[Link]("objects are equal");
This code will display objects are equal even though one and anotherOne reference
two different, distinct objects. They are considered equal because they contain the
same integer value.
One handy use of the getClass method is to create a new instance of a class without
knowing what the class is at compile time. This sample method creates a new
instance of the same class as obj which can be any class that inherits from Object
(which means that it could be any class):
Object's toString method returns a String representation of the object. You can use
toString to display an object. For example, you could display a String representation
of the current Thread like this:
[Link]([Link]().toString());
The String representation for an object is entirely dependent on the object. The
String representation of an Integer object is the integer value displayed as text. The
String representation of a Thread object contains various attributes about the
thread, such as its name and priority. For example, the previous of code above
display the following:
Thread[main,5,main]
The toString method is very useful for debugging and it would behoove you to
override this method in all your classes.
The Object class provides a method, finalize that cleans up an object before its
garbage collected. This method's role during garbage collection is discussed in this
lesson in Cleaning Up Unused Objects. Also, Writing a finalize Method shows you
how to write override the finalize method to handle the finalization needs for you
classes.
The Object class also provides five methods that are critical when writing
multithreaded Java programs:
notify
notifyAll
wait (three versions)
These methods help you ensure that your threads are synchronized and are covered
in Threads of Control . Take particular note of the page titled Synchronizing
Threads.
Reflection
A Simple Example
import [Link].*;
try {
Class c = [Link](args[0]);
[Link](m[i].toString());
catch (Throwable e) {
[Link](e);
}
}
[Link])
public synchronized
[Link] [Link]()
public synchronized
[Link] [Link]()
public synchronized
int [Link]([Link])
Interfaces
In Java an interface is similar to an abstract class in that its members are not
implemented. In interfaces, _none_ of the methods are implemented. There is no code at all
associated with an interface. For example, from my personal library:
Inner Classes
Static Inner Classes
Consider the following Java code fragment:
public class A
{
int y;
void f () {}
}
}
This fragment defines the class A which contains an static inner class B.
A static inner class behaves like any ``outer'' class. It may contain methods and fields, and it may
be instantiated like this:
A.B object = new A.B ();
This statement creates an new instance of the inner class B. Given such an instance, we can invoke the f
method in the usual way:
object.f();
Note, it is not necessarily the case that an instance of the outer class A exists even when we have
created an instance of the inner class. Similarly, instantiating the outer class A does not create
any instances of the inner class B.
The methods of a static inner class may access all the members (fields or methods) of the inner
class but they can access only static members (fields or methods) of the outer class. Thus, f can
access the field x, but it cannot access the field y.
public class B
{
int x;
void f () {}
}
}
This fragment defines the class A which contains a non-static inner class B.
A non-static inner class can be instantiated only inside a non-static method of the outer class.
This is because every instance of a non-static inner class must be associated with an instance of
the outer class. In a sense, every instance of a non-static inner class exists ``inside'' an instance of
the outer class. A single instance of the outer class may have associated with it more than one
instance of the inner class.
Because an instance of a non-static inner class has an associated instance of the outer class, the
methods of the inner class can access directly any of the members (fields or methods) of the
outer class instance. For example, the f method defined above can access both x and y directly.
The Java keyword this can be used in a non-static method to refer to the current object instance.
Thus in the method f, this refers to an instance of the inner B class. Every non-static inner class is
associated with an instance of the outer class. To access the outer class instance inside the
method f we write [Link].
Proxies
Proxy provides static methods for creating dynamic proxy classes and instances, and it is
also the superclass of all dynamic proxy classes created by those methods.
or more simply:
Foo f = (Foo) [Link]([Link](),
new Class[] { [Link] },
handler);
A dynamic proxy class (simply referred to as a proxy class below) is a class that
implements a list of interfaces specified at runtime when the class is created, with behavior as
described below. A proxy interface is such an interface that is implemented by a proxy class. A
proxy instance is an instance of a proxy class. Each proxy instance has an associated invocation
handler object, which implements the interface InvocationHandler. A method invocation on a proxy
instance through one of its proxy interfaces will be dispatched to the invoke method of the
instance's invocation handler, passing the proxy instance, a [Link] object
identifying the method that was invoked, and an array of type Object containing the arguments.
The invocation handler processes the encoded method invocation as appropriate and the result
that it returns will be returned as the result of the method invocation on the proxy instance.
A proxy class has the following properties:
Graphics programming
The Canvas class
Displaying graphics on a component
Drawing lines
Drawing rectangles
Drawing ovals
Drawing images
Add a canvas to a frame just like you would any other component:
Drawing lines
To draw lines, the drawLine() method of the Graphics class is used. This method takes four
numeric attributes - the first two indicating the x/y starting point of the line, the last two
indicating the x/y ending point of the line.
Example:
public void paint(Graphics g){ //draw a line starting at point 10,10 and ending at point 50,50.
[Link](10, 10, 50, 50); }
Drawing rectangles
To draw rectangles, the drawRect() method is used. This method takes four numeric
attributes - the first two indicating the x/y starting point of the rectangle, the last two
indicating the width and height of the rectangle.
Example:
public void paint(Graphics g){ //draw a rectangle starting at 100,100 width a width and height of 80
[Link](100, 100, 80, 80); }
Filling a rectangle
By default a rectangle will have no color on the inside (it will just look like a box). You can
use the fillRect() method to fill a rectangle. The fillRect() method has four numeric
attributes indicating the x/y starting position to begin filling and the height and width. Set
these values the same as you did for the drawRect() method to properly fill the rectangle.
Example:
public void paint(Graphics g){ //draw a rectangle starting at 100,100 width a width and height of 80
[Link](100, 100, 80, 80); [Link](100, 100, 80, 80); }
Something's missing...
The rectangle is filled, but we didn't set a color for it! To do this, we will use the setColor()
method.
[Link]([Link]);
Drawing ovals
To draw ovals, the drawOval() method is used. This method takes four numeric attributes -
the first two indicating the x/y starting point of the oval, the last two indicating the width
and height of the oval. Fill an oval with the fillOval() method which also takes four numeric
attributes indicating the starting position to begin filling and the height and width. Set
these values the same as you did for the drawOval() method to properly fill the oval.
Example:
public void paint(Graphics g){ [Link]([Link]); //draw an oval starting at 20,20 with a width and
height of 100 and fill it [Link](20,20, 100, 100); [Link](20,20, 100, 100); }
Displaying images
To display images, the Image class is used together with the Toolkit class. Use these classes
to get the image to display. Use the drawImage() method to display the image.
Example:
Java's Abstract Windowing Toolkit provides windows containers that allow you to create
separate windows for your applications. When used with a Web browser, they can run outside
the main window (unlike panels which are nested within the applet window.)
Frames have a title bar and if they are created by an applet, they should be destroyed
BEFORE you close the applet that created them so that you can reclaim the resources they were
using. This is how you create a frame with a title:
There are several things you must be concerned with after a frame is created in order for it to be
visible on the screen:
Resizing the frame: Unlike a panel, a frame must be given a size before you can see it.
[Link](300,200);
If you want to hide the frame again, in order to show a different frame for example, use the hide
method.
[Link]();
Once a frame has been created and the show method has been called, it can be resized,
maximized, and minimized just like any other window. When you are finished with the frame,
you should always use the dispose method to get rid of it. Some of you system's resources are
used when the frame is running and they will be restored when you get rid of it.
[Link]();
Notice that the frame can be minimized, resized or maximized but not closed by clicking
on the X button or control icon on the top left and right of the frame. The applet's event handling
routines cannot detect or deal with events that occur to the frame. This stems from the object
oriented nature of Java. As you can see in the diagram below the Frame class will not handle
many of the events that occur to the frame we've created.
The new frame inherits handlers for the Maximize, Minimize and Resize events from the Frame
class but no others. Any other frame events or actions would need to be handled by a class that
extends the Frame class. We will write this type of class in the next section.
Let's start by defining the difference between user space and device space. In most computer
graphics environments, each pixel is numbered. If you draw a square at, say (20, 20), then the top left
corner of the square will begin at approximately the twentieth pixel from the left edge, or axis, of the
drawing space and at the twentieth pixel from the top axis of the drawing space. Coordinates that are
offset from axes are called Cartesian coordinates. The location of Java 2D objects are also specified using
Cartesian coordinates. The beginning of the space occurs in the upper left side of a hypothetical
rectangle that increases to the right and downward.
Java 2D, however, defines coordinates in units (72 units to an inch), and rendering occurs in a
hypothetical plane called the user space.
Note that we use the term units and not pixels. The latter term implies that the output device is
a computer screen. When an object is drawn to the output device, such as a screen or printer, the
results may have to be scaled to ensure that the object is the same size. After all, a shape that appears
as four inches wide on the screen should also appear four inches wide when it is printed on a piece of
paper. A computer monitor typically uses 72 pixels per inch, so each Java 2D unit is conveniently
equivalent to a pixel. However, a computer printer may use 300, 600, or even 1200 or more dots per
inch. In this case, the Java 2D graphics engine has to scale its user space to a new device space when the
object is "drawn" to the printer output device.
The easiest Java 2D primitives to learn are lines and shapes, so let's start there. Let's assume
that we are writing the code for the inner rendering routine of a custom Swing component. With the
older AWT classes, you would use the methods of the [Link] class to draw the lines and
shapes you wanted on a screen.
public paint(Graphics g) {
[Link](10,10,40,40);
This graphics capability was very limited. Fonts were limited; shapes could be drawn with only
one pixel thickness; and image support was rudimentary. With the added graphics capabilities of the
Java 2D API, on the other hand, graphics are much more robust.
We now create an implementation of the abstract [Link] class, a Line2D, and pass this
to the more sophisticated rendering capabilities of the Graphics2D class. With the Java 2 platform, you
can do this by casting the Graphics class that is passed in to your custom component's paint methods to
a [Link].Graphics2D object, using it to render the appropriate shapes:
public paint(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
[Link]([Link]);
[Link](new BasicStroke(10));
[Link](line);
[Link](rect);
[Link](
[Link](rect);
If you've been using the old Graphics routines in your Swing components, you're in luck. You
don't have to explicitly call upon the draw() and fill() methods of Graphics2D on the Line2D and
Rectangle2D objects to get the job done. You can still invoke methods such as [Link]() and
[Link]() -- the same functionality is invoked in either case. With Java 2D, the object passed
into the paintComponent() method is the same object, whether it is cast to a Graphics or a Graphics2D.
So casting to Graphics simply allows the use of more familiar methods to access to the same Java 2D
rendering functionality.
For example, let's assume that you wanted to render a rectangle. You likely want to use the Rectangle2D
class in the Java 2D libraries. However, you cannot do the following:
In addition, if you need to use the older integer-based coordinates, you can also write this:
The use of a Float or a Double inner class is consistent with a number of other 2D lines and shapes as
well. For example, here are the constructors for the Line2D class:
public [Link]()
public [Link]()
Also, here is the QuadCurve2D class, which represents a quadratic curve segment -- that is, a single
control point between the two endpoints that the curve will "bend around":
public [Link]()
public [Link]()
public [Link](float x1, float y1, float ctrlx, float ctrly,
Here is CubicCurve2D, which represents a cubic curve segment. It is much like a QuadCurve2D, except
that it has two control points instead of one:
public [Link]()
public [Link]()
The class RoundRectangle2D is the same as Rectangle2D, except that the corners are rounded off:
With the Arc2D class, there are three different types of arcs that you can create. [Link] will simply
leave the arc open as a curved line; [Link] will create lines from either endpoint that meet in the
center of the arc's ellipse (it is shown in Figure 2). [Link] will simply connect the endpoints with
a straight line. Here are the constructors:
public [Link]()
int type)
public [Link]()
int type)
Let's use this simple example to draw a Java 2D ellipse to the screen:
public void drawMyEllipse(Graphics2D g) {
[Link](RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
[Link](new BasicStroke(5));
[Link]([Link]);
[Link](myEllipse);
[Link]([Link]);
[Link](myEllipse);
This example takes in a Graphics2D object and creates a simple ellipse 100 units high by 200 units wide
at (x,y) coordinate (10, 10), then paints the ellipse's outline (five pixels wide, thanks to the stroke) in red,
with the inside of the ellipse in white. The result is identical to the ellipse shown in Figure 2 above.
UNIT-IV
Basics of event handling
This chapter covers two different event models, or ways of handling events. In Java 1.0.2 and
earlier, events were passed to all components that could possibly have an interest in them. Events
themselves were encapsulated in a single Event class. Java 1.1 implements a "delegation" model, in
which events are distributed only to objects that have been registered to receive the event. While this is
somewhat more complex, it is much more efficient and also more flexible, because it allows any object
to receive the events generated by a component. In turn, this means that you can separate the user
interface itself from the event-handling code.
In the Java 1.1 event model, all event functionality is contained in a new package,
[Link]. Within this package, subclasses of the abstract class AWTEvent represent different
kinds of events. The package also includes a number of EventListener interfaces that are
implemented by classes that want to receive different kinds of events; they define the methods that are
called when events of the appropriate type occur. A number of adapter classes are also included; they
correspond to the EventListener interfaces and provide null implementations of the methods in the
corresponding listener. The adapter classes aren't essential but provide a convenient shortcut for
developers; rather than declaring that your class implements a particular EventListener interface,
you can declare that your class extends the appropriate adapter.
The old and new event models are incompatible. Although Java 1.1 supports both, you should not use
both models in the same program.
Once deliverEvent() identifies a target, it calls that target's handleEvent() method (in
this case, the handleEvent() method of Blood) to deliver the event for processing. If Blood has not
overridden handleEvent(), its default implementation would call Blood's action() method. If Blood
has not overridden action(), its default implementation (which is inherited from Component) is
executed and does nothing. For your program to respond to the event, you would have to provide your
own implementation of action() or handleEvent().
handleEvent() plays a particularly important role in the overall scheme. It is really a dispatcher,
which looks at the type of event and calls an appropriate method to do the actual work: action() for
action events, mouseUp() for mouse up events, and so on. Table 4.1 shows the event-handler methods
you would have to override when using the default handleEvent() implementation. If you create your
own handleEvent(), either to handle an event without a default handler or to process events
differently, it is best to leave these naming conventions in place. Whenever you override an event-
handler method, it is a good idea to call the overridden method to ensure that you don't lose any
functionality. All of the event handler methods return a boolean, which determines whether there is any
further event processing; this is described in the next section, "Passing the Buck."
MOUSE_ENTER mouseEnter()
MOUSE_EXIT mouseExit()
MOUSE_MOVE mouseMove()
MOUSE_DRAG mouseDrag()
MOUSE_DOWN mouseDown()
MOUSE_UP mouseUp()
KEY_PRESS keyDown()
KEY_ACTION keyDown()
KEY_RELEASE keyUp()
KEY_ACTION_RELEASE keyUp()
GOT_FOCUS gotFocus()
LOST_FOCUS lostFocus()
ACTION_EVENT action()
Event Handlers
The convenience event handlers like mouseDown(), keyUp(), and lostFocus() are all
implemented by the Component class. The default versions of these methods do nothing and return
false. Because these methods do nothing by default, when overriding them you do not have to ensure
that the overridden method gets called. This simplifies the programming task, since your method only
needs to return false if it has not completely processed the event. However, if you start to subclass
nonstandard components (for example, if someone has created a fancy AudioButton, and you're
subclassing that, rather than the standard Button), you probably should explicitly call the overridden
method. For example, if you are overriding mouseDown(), you should include a call to
[Link](), just as we called [Link]() in the previous example. This call is
"good housekeeping"; most of the time, your program will work without it. However, your program will
break as soon as someone changes the behavior of the AudioButton and adds some feature to its
mouseDown() method. Calling the super class's event handler helps you write "bulletproof " code.
The code below overrides the mouseDown() method. I'm assuming that we're extending a standard
component, rather than extending some custom component, and can therefore dispense with the call to
[Link]().
Here's a debugging hint: when overriding an event handler, make sure that the parameter
types are correct--remember that each convenience method has different parameters. If your
overriding method has parameters that don't match the original method, the program will still
compile correctly. However, it won't work. Because the parameters don't match, your new
method simply overloads the original, rather than overriding it. As a result, your method will
never be called.
Adapter Classes
The AWT provides a number of adapter classes for the different EventListener interfaces.
These are:
ComponentAdapter
ContainerAdapter
FocusAdapter
KeyAdapter
MouseAdapter
MouseMotionAdapter
WindowAdapter
Each adapter class implements the corresponding interface with a series of do-nothing
methods. For example, MouseListener declares these five methods:
public abstract void mouseClicked(MouseEvent evt)
public abstract void mousePressed(MouseEvent evt)
public abstract void mouseReleased(MouseEvent evt)
public abstract void mouseEntered(MouseEvent evt)
public abstract void mouseExited(MouseEvent evt)
package [Link];
import [Link].*;
import [Link].*;
}
import [Link].*;
import [Link].*;
[Link]().beep();
Without extending the MouseAdapter class, I would have had to write the same class like this
import [Link].*;
import [Link].*;
[Link]().beep();
Actions
public interface Action
extends ActionListener
The Action interface provides a useful extension to the ActionListener interface in cases where the
same functionality may be accessed by several controls.
One or more text strings that describe the function. These strings can be used, for example, to
display the flyover text for a button or to set the text in a menu item.
One or more icons that depict the function. These icons can be used for the images in a menu
control, or for composite entries in a more sophisticated user interface.
The enabled/disabled state of the functionality. Instead of having to separately disable the
menu item and the toolbar button, the application can disable the function that implements this
interface. All components which are registered as listeners for the state change then know to
disable event generation for that item and to modify the display accordingly.
Certain containers, including menus and tool bars, know how to add an Action object. When an
Action object is added to such a container, the container:
a. Creates a component that is appropriate for that container (a tool bar creates a button
component, for example).
b. Gets the appropriate property(s) from the Action object to customize the component (for
example, the icon image and flyover text).
c. Checks the initial state of the Action object to determine if it is enabled or disabled, and
renders the component in the appropriate fashion.
d. Registers a listener with the Action object so that is notified of state changes. When the
Action object changes from enabled to disabled, or back, the container makes the appropriate
revisions to the event-generation mechanisms and renders the component accordingly.
For example, both a menu item and a toolbar button could access a Cut action object. The text
associated with the object is specified as "Cut", and an image depicting a pair of scissors is specified as
its icon. The Cut action-object can then be added to a menu and to a tool bar. Each container does the
appropriate things with the object, and invokes its actionPerformed method when the component
associated with it is activated. The application can then disable or enable the application object without
worrying about what user-interface components are connected to it.
This interface can be added to an existing class or used to create an adapter (typically, by subclassing
AbstractAction). The Action object can then be added to multiple action-aware containers and
connected to Action-capable components. The GUI controls can then be activated or deactivated all at
once by invoking the Action object's setEnabled method.
Note that Action implementations tend to be more expensive in terms of storage than a
typical ActionListener, which does not offer the benefits of centralized control of functionality and
broadcast of property changes. For th is reason, you should take care to only use Actions where their
benefits are desired, and use simple ActionListeners elsewhere.
Mouse Events
The mouse listeners allow you to receive events to process:
Normally handled for you. The mouse is handled automatically by most components, so
you never have to know about it. For example, if someone clicks on a button (JButton), the
JButton translates that click into an ActionEvent, which is a higher level event that can be caused
by a number of things. You don't need to know (and shouldn't care) whether the ActionEvent
was from a mouse click on the button, or from a keyboard shortcut, or hitting enter while that
button had focus, or ....
Sometimes used with graphics. If you are are drawing your own graphics (eg, on a
JComponent or JPanel) and need to know where the user clicks, then you need to know about
mouse events. You can easily add a mouse listener to a JComponent or JPanel.
Important Classes and Interfaces
These classes and interfaces are defined in [Link]. The first three are the most commonly
used.
MouseEvent A MouseEvent object is passed to all mouse listeners. The most useful
information in a MouseEvent is the x and y coordinates of the mouse cursor.
MouseListener Interface for mouse presses, releases, clicks, enters, and exits.
Adapter classes - You only have to override the methods you need.
MouseAdapter Class useful for writing anonymous listener for mouse button presses,
entering, ...
MouseMotionAdapter Class useful for writing anonymous listener for mouse movement.
[Link]
+---[Link]
+---[Link]
+---[Link]
+---[Link]
+---[Link]
|
+---[Link]
+----[Link]
+---[Link]
| |
| +---[Link]
| |
| +---[Link]
+---[Link]
+---[Link]
+---[Link]
Introduction to swing
Almost all GUI applications have a main or top-level window. In Swing, such window is usually
instance of JFrame or JWindow. The difference between those two classes is in simplicity –
JWindow is much simpler than JFrame (most noticeable are visual differences - JWindow does
not have a title bar, and does not put a button in the operating system task bar). So, your
applications will almost always start with a JFrame.
Though you can instantiate a JFrame and add components to it, a good practice is to
encapsulate and group the code for a single visual frame in a separate class. Usually, I subclass
the JFrame and initialize all visual elements of that frame in the constructor.
Always pass a title to the parent class constructor – that String will be displayed in the
title bar and on the task bar. Also, remember to always initialize frame size (by calling
setSize(width,height)), or your frame will not be noticeable on the screen.
1. package [Link].ch1;
2.
3. import [Link];
4.
5. public class MainFrame extends JFrame
6. {
7. public MainFrame()
8. {
9. super("My title");
10.
11. setSize(300, 300);
12. }
13. }
Now you have created your first frame, and it is time to display it. Main frame is usually
displayed from the main method – but resist the urge to put the main method in the frame class.
Always try to separate the code that deals with visual presentation from the code that deals with
application logic – starting and initializing the application is part of application logic, not a part
of visual presentation. A good practice is to create an Application class, that will contain
initialization code.
view plaincopy to clipboardprint?
1. package [Link].ch1;
2.
3. public class Application
4. {
5. public static void main(String[] args)
6. {
7. // perform any initialization
8.
9. MainFrame mf = new MainFrame();
10. [Link]();
11. }
12. }
If you run the code now, you will see an empty frame. When you close it, something not quite
obvious will happen (or better said, will not happen). The application will not end. Remember
that the Frame is just a visual part of application, not application logic – if you do not request
application termination when the window closes, your program will still run in the
background (look for it in the process list). To avoid this problem, add the following line to
the MainFrame constructor:
Adding Components
Now is the time to add some components to the window. In Swing (and the Swing
predecessor, AWT) all visual objects are subclasses of Component class. The Composite pattern
was applied here to group visual objects into Containers, special components that can
contain other components. Containers can specify the order, size and position of
embedded components (and this can all be automatically calculated, which is one of the best
features of Swing).
JButton is a component class that represents a general purpose button – it can have a text
caption or an icon, and can be pressed to invoke an action. Let’s add the button to the frame
(note: add imports for [Link].* and [Link].* to the MainFrame source code so that you
can use all the components).
When you work with JFrame, you want to put objects into it’s content pane –
special container intended to hold the window contents. Obtain the reference to that container
with the getContentPane() method.
If you try to add more buttons to the frame, most likely only the last one added will be displayed.
That is because the default behavior of JFrame content pane is to display a single component,
resized to cover the entire area.
Grouping Components
To put more than one component into a place intended for a single component, group them into a
container. JPanel is a general purpose container, that is perfect for grouping a set of components
into a “larger” component. So, let’s put the buttons into a JPanel:
Model
Most Swing components have models. A button (JButton), for example, has a model (a
ButtonModel object) that stores the button's state — what its keyboard mnemonic is, whether it's
enabled, selected, or pressed, and so on. Some components have multiple models. A list (JList), for
example, uses a ListModel to hold the list's contents, and a ListSelectionModel to track the list's
current selection.
Models have other benefits, too. They mean that data isn't copied between a program's data
structures and those of the Swing components. Also, models automatically propagate changes to
all interested listeners, making it easy for the GUI to stay in sync with the data. For example, to
add items to a list you can invoke methods on the list model. When the model's data changes, the
model fires events to the JList and any other registered listeners, and the GUI is updated
accordingly.
An Example: Converter
This section features an example called Converter, which is an application that continuously converts
distance measurements between metric and U.S. units. You can run Converter ( download JDK 6). Or, to
compile and run the example yourself, consult the example index.
As the following picture shows, Converter features two sliders, each tied to a text field. The
sliders and text fields all display the same data — a distance — but using two different units of
measure.
The important thing for this program is ensuring that only one model controls the value of the
data. There are various ways to achieve this; we did it by deferring to the top slider's model. The
bottom slider's model (an instance of a custom class called FollowerRangeModel) forwards all data
queries to the top slider's model (an instance of a custom class called ConverterRangeModel). Each
text field is kept in sync with its slider, and vice versa, by event handlers that listen for changes
in value. Care is taken to ensure that the top slider's model has the final say about what distance
is displayed.
When we started implementing the custom slider models, we first looked at the API section of
How to Use Sliders. It informed us that all slider data models must implement the
BoundedRangeModel interface. The BoundedRangeModel API documentation tells us that the interface
has an implementing class named DefaultBoundedRangeModel. The API documentation for
DefaultBoundedRangeModel shows that it's a general-purpose implementation of BoundedRangeModel.
We didn't use DefaultBoundedRangeModel directly because it stores data as integers, and Converter
uses floating-point data. Thus, we implemented ConverterRangeModel as a subclass of Object. We
then implemented FollowerRangeModel as a subclass of ConverterRangeModel.
View
A very important part of the text package is the View class. As the name suggests it represents a
view of the text model, or a piece of the text model. It is this class that is responsible for the look
of the text component. The view is not intended to be some completely new thing that one must
learn, but rather is much like a lightweight component. In fact, the original View implementation
was a lightweight component. There were several reasons why the Component implementation
was abandoned in favor of an alternative.
1. There was barely time to get the lightweight component support in the 1.1 version of the
JDK. There simply wasn't time to lighten up the component further to where it would
need to be to be used for text purposes. The additions made to JComponent increased the
memory consumption, and as it currently stands its much too heavy for representing text.
2. The layout semantics aren't quite right for text, and changing the current layout semantics
of component might break existing applications.
3. The component api uses integers, but in 1.2 one can use floating point device independent
coordinates. An api that works in both 1.1 and 1.2 would be convenient for minimizing
transition difficulties. The View class uses the Shape interface and float arguments to
enable View implementations for the Java 2 platform v1.2 and later while still
functioning in the older 1.1 JDK.
By default, a view is very light. It contains a reference to the parent view from which it can fetch
many things without holding state, and it contains a reference to a portion of the model
(Element). A view does not have to exactly represent an element in the model, that is simply a
typical and therefore convenient mapping. A view can alternatively maintain a couple of Position
objects to maintain its location in the model (i.e. represent a fragment of an element). This is
typically the result of formatting where views have been broken down into pieces. The
convenience of a substantial relationship to the element makes it easier to build factories to
produce the views, and makes it easier to keep track of the view pieces as the model is changed
and the view must be changed to reflect the model. Simple views therefore represent an Element
directly and complex views do not.
Participate in layout.
The view has a setSize method which is like doLayout and setSize in Component combined.
The view has a preferenceChanged method which is like invalidate in Component except that
one can invalidate just one axis and the child requesting the change is identified.
A View expresses the size that it would like to be in terms of three values, a minimum, a
preferred, and a maximum span. Layout in a view is can be done independently upon
each axis. For a properly functioning View implementation, the minimum span will be
<= the preferred span which in turn will be <= the maximum span.
The minimum set of methods for layout are:
getMinimumSpan
getPreferredSpan
getMaximumSpan
getAlignment
preferenceChanged
setSize
The setSize method should be prepared to be called a number of times (i.e. It may be
called even if the size didn't change). The setSize method is generally called to make sure
the View layout is complete prior to trying to perform an operation on it that requires an
up-to-date layout. A view's size should always be set to a value within the minimum and
maximum span specified by that view. Additionally, the view must always call the
preferenceChanged method on the parent if it has changed the values for the layout it would
like, and expects the parent to honor. The parent View is not required to recognize a
change until the preferenceChanged has been sent. This allows parent View implementations
to cache the child requirements if desired. The calling sequence looks something like the
following:
The exact calling sequence is up to the layout functionality of the parent view (if the view
has any children). The view may collect the preferences of the children prior to
determining what it will give each child, or it might iteratively update the children one at
a time.
This is done in the paint method, which is pretty much like a component paint method.
Views are expected to potentially populate a fairly large tree. A View has the following
semantics for rendering:
The view gets its allocation from the parent at paint time, so it must be prepared to
redo layout if the allocated area is different from what it is prepared to deal with.
The coordinate system is the same as the hosting Component (i.e. the Component
returned by the getContainer method). This means a child view lives in the same
coordinate system as the parent view unless the parent has explicitly changed the
coordinate system. To schedule itself to be repainted a view can call repaint on the
hosting Component.
The default is to not clip the children. It is more efficient to allow a view to clip only if it
really feels it needs clipping.
The Graphics object given is not initialized in any way. A view should set any settings
needed.
A View is inherently transparent. While a view may render into its entire allocation,
typically a view does not. Rendering is performed by tranversing down the tree of View
implementations. Each View is responsible for rendering its children. This behavior is
depended upon for thread safety. While view implementations do not necessarily have
to be implemented with thread safety in mind, other view implementations that do
make use of concurrency can depend upon a tree traversal to guarantee thread safety.
The order of views relative to the model is up to the implementation. Although child
views will typically be arranged in the same order that they occur in the model, they
may be visually arranged in an entirely different order. View implementations may have
Z-Order associated with them if the children are overlapping.
Because the view objects are produced from a factory and therefore cannot necessarily be
counted upon to be in a particular pattern, one must be able to perform translation to
properly locate spatial representation of the model. The methods for doing this are:
modelToView
viewToModel
getDocument
getElement
getStartOffset
getEndOffset
The layout must be valid prior to attempting to make the translation. The translation is
not valid, and must not be attempted while changes are being broadcasted from the model
via a DocumentEvent.
If the overall view is represented by many pieces (which is the best situation if one want
to be able to change the view and write the least amount of new code), it would be
impractical to have a huge number of DocumentListeners. If each view listened to the
model, only a few would actually be interested in the changes broadcasted at any given
time. Since the model has no knowledge of views, it has no way to filter the broadcast of
change information. The view hierarchy itself is instead responsible for propagating the
change information. At any level in the view hierarchy, that view knows enough about its
children to best distribute the change information further. Changes are therefore
broadcasted starting from the root of the view hierarchy. The methods for doing this are:
insertUpdate
removeUpdate
changedUpdate
The model is the domain-specific representation of the data upon which the application operates.
Domain logic adds meaning to raw data (for example, calculating whether today is the user's
birthday, or the totals, taxes, and shipping charges for shopping cart items). When a model
changes its state, it notifies its associated views so they can be refreshed.
Many applications use a persistent storage mechanism such as a database to store data. MVC
does not specifically mention the data access layer because it is understood to be underneath or
encapsulated by the model. Models are not data access objects; however, in very simple apps that
have little domain logic there is no real distinction to be made. Also, the ActiveRecord is an
accepted design pattern which merges domain logic and data access code - a model which knows
how to persist itself.
The view renders the model into a form suitable for interaction, typically a user interface
element. Multiple views can exist for a single model for different purposes.
The controller receives input and initiates a response by making calls on model objects.
MVC is often seen in web applications where the view is the HTML or XHTML generated by
the app. The controller receives GET or POST input and decides what to do with it, handing over
to domain objects (i.e. the model) that contain the business rules and know how to carry out
specific tasks such as processing a new subscription.
Button
JButton Basics
Simple uses of JButton are very similar to Button. You create a JButton with a String as a label, and
then drop it in a window. Events are normally handled just as with a Button: you attach an
ActionListener via the addActionListener method.
1. the main image (use setIcon to specify it if not supplied in the constructor),
2. the image to use when the button is pressed (setPressedIcon),
3. the image to use when the mouse is over it (setRolloverIcon, but you need to call
setRolloverEnabled(true) first),
4. the image to use when the button is selected and enabled (setSelectedIcon),
5. the image to use when the button is disabled (setDisabledIcon),
6. the image to use when it is selected but disabled (setDisabledSelectedIcon), and
7. the image to use when the mouse is over it while it is selected (setRolloverSelectedIcon).
You can also change the alignment of the text or icon in the button (setHorizontalAlignment and
setVerticalAlignment; only valid if button is larger than preferred size), and change where the text is
relative to the icon (setHorizontalTextPosition, setVerticalTextPosition).
You can also easily set keyboard mnemonics via setMnemonic. This results in the specified
character being underlined on the button, and also results in ALT-char activating the button.
[Link]
import [Link].*;
import [Link].*;
public JButtons() {
super("Using JButton");
[Link]();
addWindowListener(new ExitListener());
Container content = getContentPane();
[Link]([Link]);
[Link](new FlowLayout());
JButton button1 = new JButton("Java");
[Link](button1);
ImageIcon cup = new ImageIcon("images/[Link]");
JButton button2 = new JButton(cup);
[Link](button2);
JButton button3 = new JButton("Java", cup);
[Link](button3);
JButton button4 = new JButton("Java", cup);
[Link]([Link]);
[Link](button4);
pack();
setVisible(true);
}
}
// : c14:[Link]
// Various Swing buttons.
// <applet code=Buttons width=350 height=100></applet>
// From 'Thinking in Java, 3rd ed.' (c) Bruce Eckel 2002
// [Link]. See copyright notice in [Link].
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
Layout Management
One of the best features of Swing is automatic component positioning and resizing. That is
implemented trough a mechanism known as Layout management. Special objects –
layout managers – are responsible for sizing, aligning and positioning components
Each container can have a layout manager, and the type of layout manager determines the layout
of components in that container. There are several types of layout managers, but the two you will
most frequently use are FlowLayout (orders components one after another, without resizing) and
BorderLayout (has a central part and four edge areas – component in the central part is resized to
take as much space as possible, and components in edge areas are not resized). In the
previous examples, you have used both of them. FlowLayout is the default for a JPanel (that is
why all three buttons are displayed without resizing), and BorderLayout is default for JFrame
content panes
Layout for a container is defined using the setLayout method (or usually in the constructor). So,
you could change the layout of content pane to FlowLayout and add several components, to see
them all on the screen.
The best choice for the window content pane is usually a BorderLayout with a central content
part and a bottom status (or button) part. The top part can contain a toolbar, optionally.
Now, let’s combine several components and layouts, and introduce a new component
JTextArea. JTextArea is basically a multiline editor. Initialize the frame content pane
explicitly to BorderLayout, put a new JTextArea into the central part and move the button
panel below.
1. package [Link].ch1;
2.
3. import [Link].*;
4. import [Link].*;
5.
6. public class MainFrame extends JFrame
7. {
8. public MainFrame()
9. {
10. super("My title");
11.
12. setSize(300,300);
13.
14. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
15.
16. Container content = getContentPane();
17. [Link](new BorderLayout());
18.
19. JPanel panel = new JPanel(new FlowLayout());
20. [Link](new JButton("Button 1"));
21. [Link](new JButton("Button 2"));
22. [Link](new JButton("Button 3"));
23.
24. [Link](panel, [Link]);
25. [Link](new JTextArea(), [Link]);
26. }
27. }
Swing Components
We'll start with the simplest components: buttons and labels. Frankly, there isn't much to say
about them. If you've seen one button, you've seen them all; and you've already seen buttons in
the applications in Chapter 2, A First Application (HelloJava3 and HelloJava4). A button generates
an ActionEvent when the user presses it. To receive these events, your program registers an
ActionListener, which must implement the actionPerformed( ) method. The argument passed to
actionPerformed( ) is the event itself.
There's one more thing worth saying about buttons, which applies to any component that
generates an action event. Java lets us specify an "action command" string for buttons (and other
components, like menu items, that can generate action events). The action command is less
interesting than it sounds. It is just a String that serves to identify the component that sent the
event. By default, the action command of a JButton is the same as its label; it is included in action
events, so you can use it to figure out which button an event came from.
To get the action command from an action event, call the event's getActionCommand( ) method.
The following code checks whether the user pressed the Yes button:
You can change the action command by calling the button's setActionCommand( ) method. The
following code changes button myButton's action command to "confirm":
[Link]("confirm");
It's a good idea to get used to setting action commands explicitly; this helps to prevent your code
from breaking when you or some other developer "internationalizes" it, or otherwise changes the
button's label. If you rely on the button's label, your code will stop working as soon as that label
changes; a French user might see the label Oui rather than Yes. By setting the action command,
you eliminate one source of bugs; for example, the button myButton in the previous example will
always generate the action command confirm, regardless of what its label says.
Swing buttons can have an image in addition to a label. The JButton class includes constructors
that accept an Icon object, which knows how to draw itself. You can create buttons with captions,
images, or both. A handy class called ImageIcon takes care of loading an image for you and can
be used to easily add an image to a button. The following example shows how this works:
//file: [Link]
import [Link].*;
import [Link].*;
import [Link].*;
public PictureButton( ) {
super("PictureButton v1.0");
setSize(200, 200);
setLocation(200, 200);
There's even less to be said about JLabel components. They're just text strings or images housed
in a component. There aren't any special events associated with labels; about all you can do is
specify the text's alignment, which controls the position of the text within the label's display area.
As with buttons, JLabels can be created with Icons if you want to create a picture label. The
following code creates some labels with different options:
Swing can interpret HTML-formatted text in JLabel and JButton labels. The following example
shows how to create a button with HTML-formatted text:
A checkbox is a labeled toggle switch. Each time the user clicks it, its state toggles between
checked and unchecked. Swing implements the checkbox as a special kind of button. Radio
buttons are similar to checkboxes, but they are usually arranged in groups. Click on one radio
button in the group, and the others automatically turn off. They are named for the preset buttons
on old car radios.
Checkboxes and radio buttons are represented by instances of JCheckBox and JRadioButton,
respectively. Radio buttons can be tethered together using an instance of another class called
ButtonGroup. By now you're probably well into the swing of things (no pun intended) and could
easily master these classes on your own. We'll use an example to illustrate a different way of
dealing with the state of components and to show off a few more things about containers.
A JCheckBox sends ItemEvents when it's pushed. Since a checkbox is a kind of button, it also fires
ActionEvents when it becomes checked. For something like a checkbox, we might want to be lazy
and check on the state of the buttons only at some later time, such as when the user commits an
action. It's like filling out a form; you can change your choices until you submit the form.
The following application, DriveThrough, lets us check off selections on a fast food menu, as
shown in Figure 14-1. DriveThrough prints the results when we press the Place Order button.
Therefore, we can ignore all the events generated by our checkboxes and radio buttons and listen
only for the action events generated by the regular button.
//file: [Link]
import [Link].*;
import [Link].*;
import [Link].*;
public class DriveThrough {
public static void main(String[] args) {
JFrame f = new JFrame("Lister v1.0");
[Link](300, 150);
[Link](200, 200);
[Link](new WindowAdapter( ) {
public void windowClosing(WindowEvent we) { [Link](0); }
});
[Link](new ActionListener( ) {
public void actionPerformed(ActionEvent ae) {
String entree =
[Link]().getActionCommand( );
[Link](entree + " sandwich");
Component[] components = [Link]( );
for (int i = 0; i < [Link]; i++) {
JCheckBox cb = (JCheckBox)components[i];
if ([Link]( ))
[Link]("With " + [Link]( ));
}
}
});
[Link](true);
}
}
Figure 14-1. The DriveThrough application
DriveThrough lays out three panels. The radio buttons in the entreePanel are tied together through
a ButtonGroup object. We add( ) the buttons to a ButtonGroup to make them mutually exclusive.
The ButtonGroup object is an odd animal. One expects it to be a container or a component, but it
isn't; it's simply a helper object that allows only one RadioButton to be selected at a time.
JLists and JComboBoxes are a step up on the evolutionary chain from JButtons and JLabels. Lists
let the user choose from a group of alternatives. They can be configured to force the user to
choose a single selection or to allow multiple choices. Usually, only a small group of choices are
displayed at a time; a scrollbar lets the user move to the choices that aren't visible. The user can
select an item by clicking on it. He or she can expand the selection to a range of items by holding
down Shift and clicking on another item. To make discontinuous selections, the user can hold
down the Control key instead of the Shift key.
A combo box is a cross-breed between a text field and a list. It displays a single line of text
(possibly with an image) and a downward pointing arrow at one side. If you click on the arrow,
the combo box opens up and displays a list of choices. You can select a single choice by clicking
on it. After a selection is made, the combo box closes up; the list disappears and the new
selection is shown in the text field.
Like every other component in Swing, lists and combo boxes have data models that are distinct
from visual components. The list also has a selection model that controls how selections may be
made on the list data.
Lists and combo boxes are similar because they have similar data models. Each is simply an
array of acceptable choices. This similarity is reflected in Swing, of course: the type of a
JComboBox's data model is a subclass of the type used for a JList's data model. The next example
demonstrates this relationship.
The following example creates a window with a combo box, a list, and a button. The combo box
and the list use the same data model. When you press the button, the program writes out the
current set of selected items in the list. Figure 14-2 shows the example; the code itself follows.
Figure 14-2. A combo box and a list using the same data model
/file: [Link]
import [Link].*;
import [Link].*;
import [Link].*;
[Link](true);
}
}
Borders
Any Swing component can have a decorative border. JComponent includes a method called
setBorder( ); all you have to do is call setBorder( ), passing it an appropriate implementation of the
Border interface.
Swing provides many useful Border implementations in the [Link] package. You could
create an instance of one of these classes and pass it to a component's setBorder( ) method, but
there's an even simpler technique.
The BorderFactory class can create any kind of border for you using static "factory" methods.
Creating and setting a component's border, then, is simple:
Every component has a setBorder( ) method, from simple labels and buttons right up to the fancy
text and table components we'll cover in the next chapter.
BorderFactory is convenient, but it does not offer every option of every border type. For example,
if you want to create a raised EtchedBorder instead of the default lowered border, you'll need to
use EtchedBorder's constructor rather than a method in BorderFactory, like this:
The Border implementation classes are listed and briefly described here:
BevelBorder
This border draws raised or lowered beveled edges, giving an illusion of depth.
SoftBevelBorder
EmptyBorder
Doesn't do any drawing, but does take up space. You can use it to give a component a
little breathing room in a crowded user interface.
EtchedBorder
A lowered etched border gives the appearance of a rectangle that has been chiseled into a
piece of stone. A raised etched border looks like it is standing out from the surface of the
screen.
LineBorder
Draws a simple rectangle around a component. You can specify the color and width of the line in
LineBorder's constructor.
MatteBorder
A souped-up version of LineBorder. You can create a MatteBorder with a certain color and
specify the size of the border on the left, top, right, and bottom of the component.
MatteBorder also allows you to pass in an Icon that will be used to draw the border. This could
be an image (ImageIcon) or any other implementation of the Icon interface.
TitledBorder
A regular border with a title. TitledBorder doesn't actually draw a border; it just draws a title in
conjunction with another border object. You can specify the locations of the title, its
justification, and its font. This border type is particularly useful for grouping different sets of
controls in a complicated interface.
CompoundBorder
A border that contains two other borders. This is especially handy if you want to enclose a
component in an EmptyBorder and then put something decorative around it, like an
EtchedBorder or a MatteBorder.
Menus
A JMenu is a standard pull-down menu with a fixed name. Menus can hold other menus as
submenu items, enabling you to implement complex menu structures. In Swing, menus are first-
class components, just like everything else. You can place them wherever a component would
go. Another class, JMenuBar, holds menus in a horizontal bar. Menu bars are real components,
too, so you can place them wherever you want in a container: top, bottom, or middle. But in the
middle of a container, it usually makes more sense to use a JComboBox rather than some kind of
menu.
Menu items may have associated images and shortcut keys; there are even menu items that look
like checkboxes and radio buttons. Menu items are really a kind of button. Like buttons, menu
items fire action events when they are selected. You can respond to menu items by registering
action listeners with them.
There are two ways to use the keyboard with menus. The first is called mnemonics. A mnemonic
is one character in the menu name. If you hold down the Alt key and type a menu's mnemonic,
the menu will drop down, just as if you had clicked on it with the mouse. Menu items may also
have mnemonics. Once a menu is dropped down, you can select individual items in the same
way.
Menu items may also have accelerators. An accelerator is a key combination that selects the
menu item, whether or not the menu that contains it is showing. A common example is the
accelerator Ctrl-C, which is frequently used as a shortcut for the Copy item in the Edit menu.
The following example demonstrates several different features of menus. It creates a menu bar
with three different menus. The first, Utensils, contains several menu items, a submenu, a
separator, and a Quit item that includes both a mnemonic and an accelerator. The second menu,
Spices, contains menu items that look and act like checkboxes. Finally, the Cheese menu
demonstrates how radio button menu items can be used.
This application is shown in Figure 14-4 with one of its menus dropped down. Choosing Quit
from the menu (or pressing Ctrl-Q) removes the window. Give it a try.
//file: [Link]
import [Link].*;
import [Link].*;
import [Link].*;
public DinnerMenu( ) {
super("DinnerMenu v1.0");
setSize(200, 200);
setLocation(200, 200);
One of Swing's nifty components is JPopupMenu, a menu that automatically appears when you
press the appropriate mouse button inside of a component. (On a Windows system, for example,
clicking the right mouse button invokes a popup menu.) Which button you press depends on the
platform you're using; fortunately, you don't have to care--Swing figures it out for you.
The care and feeding of JPopupMenu is basically the same as any other menu. You use a different
constructor (JPopupMenu( )) to create it, but otherwise, you build a menu and add elements to it
the same way. The big difference is you don't need to attach it to a JMenuBar. Instead, just pop up
the menu whenever you need it.
The following example, PopupColorMenu, contains three buttons. You can use a JPopupMenu to
set the color of each button or the frame itself, depending on where you press the mouse. Figure
14-5 shows the example in action; the user is preparing to change the color of the bottom button.
//file: [Link]
import [Link].*;
import [Link].*;
import [Link].*;
public PopUpColorMenu( ) {
super("PopUpColorMenu v1.0");
setSize(100, 200);
setLocation(200, 200);
addWindowListener(new WindowAdapter( ) {
public void windowClosing(WindowEvent e) { [Link](0); }
});
getContentPane( ).addMouseListener(mouseListener);
setVisible(true);
}
Dialogs
A dialog is another standard feature of user interfaces. Dialogs are frequently used to present
information to the user ("Your fruit salad is ready.") or to ask a question ("Shall I bring the car
around?"). Dialogs are used so commonly in GUI applications that Swing includes a handy set of
pre-built dialogs. These are accessible from static methods in the JOptionPane class. Many
variations are possible; JOptionPane groups them into four basic types:
message dialog
confirmation dialog
Ask a question and displays answer buttons, usually Yes, No, and Cancel.
input dialog
option dialogs
The most general type--you pass it your own components, which are displayed in the dialog.
Let's look at examples of each kind of dialog. The following code produces a message dialog:
Generic programming is a sub-discipline of computer science that deals with finding abstract
representations of efficient algorithms, data structures, and other software concepts, and with their
systematic organization. The goal of generic programming is to express algorithms and data structures in
a broadly adaptable, interoperable form that allows their direct use in software construction. Key ideas
include:
Expressing algorithms with minimal assumptions about data abstractions, and vice versa, thus
making them as interoperable as possible.
Lifting of a concrete algorithm to as general a level as possible without losing efficiency; i.e., the
most abstract form such that when specialized back to the concrete case the result is just as
efficient as the original algorithm.
When the result of lifting is not general enough to cover all uses of an algorithm, additionally
providing a more general form, but ensuring that the most efficient specialized form is
automatically chosen when applicable.
Providing more than one generic algorithm for the same purpose and at the same level of
abstraction, when none dominates the others in efficiency for all inputs. This introduces the
necessity to provide sufficiently precise characterizations of the domain for which each
algorithm is the most efficient.
The intention in this seminar is to focus on generic programming techniques that can be used in
practice, rather than to discuss purely theoretical issues. By the end of the seminar we would like to
come up with the following results:
1. A list of problems in generic programming. These include new components, new kinds of
abstractions, language extensions, tools.
2. A process for extending the existing body of generic components, as well as methods for their
specification and verification and for establishing their efficiency in actual programs.
Generic class
public T getFirst(){
return first;
}
public S getSecond() {
return second;
}
Generic method
Here is an example of a generic method using the generic class above:
Pair<int, int> pair; // this fails. You have to use Integer instead.
So far so good.
At first blush this looks simple (and it actually is) but I had a number of false starts trying to
make this work. My first (failing) cut at this tried to the obvious and looked like this:
{
... application global specific bus operations (few)
}
public class busEntry : TimeTrakkerBusinessBase<EntryEntity, TimeTrakkerContext>
{
... specific implementation for logical business entities
}
but alas, this fails to compile with:
‘TContext' must be a non-abstract type with a public parameterless constructor in order to use it
as parameter 'TContext' in the generic type or method
'[Link]<TEntity,TContext>
When this error first hit I immediately assumed that you simply cannot inherit from a generic
type and pass generic parameters to the base definition. Specifically I misinterpreted the ‘abstract
type’ in the message to mean the non-specific type reference (ie. TEntity). In a way this makes
sense – generics expects a concrete type to create the custom class based on these types. I asked
around in regards to this and got a lot of the same head-scratching I was going through.
However, if I had read the error message more carefully and given a little more thought to this
the error, I would have seen that the error message actually complains about a very specific issue
– namely that the generic parameters aren’t provided properly – there’s some ambiguity in that
the base type requires only specific object instances. By not restraining the inherited parameters
there’s potential that the values provided are not of the same typed as a result – Bonkage!
The solution is to add the same constraints of the base generic class to the inherited application
level generic class. So the following does work as expected:
The main thing I did was to add generic support. This was pretty interesting as doing it gave me a really
good idea of how the CLR and compilers actually work to create generic type.
}
public class SortedList<T> where T : IComparable {
A quick ILDASM of the assembly shows me what the metadata really looks like:
extends [mscorlib][Link]
extends [mscorlib][Link]
Notice the “type” of the type parameter, T? This is how we include the constraints.. List can work over
any type (all types both value and reference satisfy the constraint of being derived from [Link].
Whereas sorted list will only work over types that implement the IComparable interface.
Cool enough, but how do we get reflection to give us this data… Once you understand the metadata
layout it is not that bad… See comments in line
//Fist we loop through all the generic arguments (T) in our case
//If there are any or there is a base type other than object then we
WriteTypeName(t);
Write(":");
if ([Link] != typeof(Object))
WriteTypeName([Link]);
WriteTypeName(arr[i]);
//"new" constraint.
if (arr2[i].GetType() ==
typeof([Link]))
Write("new()");
else
Write(arr2[i].ToString());
public List();
public SortedList();
Multithreaded programming
At any time, a thread is said to be in one of several thread states that are illustrated in the UML state
diagram in Fig. 23.1. A few of the terms in the diagram are defined in later sections. Fig. 23.1 Thread life-
cycle UML state diagram.
A new thread begins its life cycle in the new state. It remains in this state until the program starts
the thread, which places the thread in the runnable state. A thread in this state is considered to be
executing its task.
Sometimes a thread transitions to the waiting state while the thread waits for another thread to
perform a task. Once in this state, a thread transitions back to the runnable state only when
another thread signals the waiting thread to continue executing.
A runnable thread can enter the timed waiting state for a specified interval of time. A thread in
this state transitions back to the runnable state when that time interval expires or when the event
it is waiting for occurs. Timed waiting threads cannot use a processor, even if one is available. A
thread can transition to the timed waiting state if it provides an optional wait interval when it is
waiting for another thread to perform a task. Such a thread will return to the runnable state when
it is signaled by another thread or when the timed interval expires—whichever comes first.
Another way to place a thread in the timed waiting state is to put the thread to sleep. A sleeping
thread remains in the timed waiting state for a designated period of time (called a sleep
interval) at which point it returns to the runnable state. Threads sleep when they momentarily do
not have work to perform. For example, a word processor may contain a thread that periodically
writes a copy of the current document to disk for recovery purposes. If the thread did not sleep
between successive backups, it would require a loop in which it continually tests whether it
should write a copy of the document to disk. This loop would consume processor time without
performing productive work, thus reducing system performance. In this case, it is more efficient
for the thread to specify a sleep interval (equal to the period between successive backups) and
enter the timed waiting state. This thread is returned to the runnable state when its sleep interval
expires, at which point it writes a copy of the document to disk and reenters the timed waiting
state.
A runnable thread enters the terminated state when it completes its task or otherwise terminates
(perhaps due to an error condition). In the UML state diagram in Fig. 23.1, the terminated state is
followed by the UML final state (the bull’s-eye symbol) to indicate the end of the state
transitions.
At the operating-system level, Java’s runnable state actually encompasses two separate states
(Fig. 23.2). The operating system hides these two states from the Java Virtual Machine (JVM),
which only sees the runnable state. When a thread first transitions to the runnable state from the
new state, the thread is in the ready state. A ready thread enters the running state (i.e., begins
executing) when the operating system assigns the thread to a processor—also known as
dispatching the thread. In most operating systems, each thread is given a small amount of
processor time—called a quantum or timeslice—with which to perform its task. When the
thread’s quantum expires, the thread returns to the ready state and the operating system assigns
another thread to the processor (see Section 23.3). Transitions between these states are handled
solely by the operating system. The JVM does not “see” these two states—it simply views a
thread as being in the runnable state and leaves it up to the operating system to transition threads
between the ready and running states. The process that an operating system uses to decide which
thread to dispatch is known as thread scheduling and is dependent on thread priorities
(discussed in the next section). Fig. 23.2 Operating system’s internal view of Java’s runnable
state.
[Note: These constants (MAX_PRIORITY, MIN_PRIORITY and NORM_PRIORITY) are declared in the
Thread class. It is recommended that you do not explicitly create and use Thread objects to
implement concurrency, but rather use the Runnable interface (which is described in Section 23.4).
The Thread class does contain some static methods that are useful, as you will see later in this
chapter.]
Most Java platforms support timeslicing, which enables threads of equal priority to share a
processor. Without timeslicing, each thread in a set of equal-priority threads runs to completion
(unless it leaves the runnable state and enters the waiting or timed waiting state, or gets
interrupted by a higher-priority thread) before other threads of equal priority get a chance to
execute. With timeslicing, even if the thread has not finished executing when the quantum
expires, the processor is taken away from that thread and given to the next thread of equal
priority, if one is available.
The job of an operating system’s thread scheduler is to determine which thread runs next. One
simple implementation of the thread scheduler keeps the highest-priority thread running at all
times and, if there is more than one highest-priority thread, ensures that all such threads execute
for a quantum each in round-robin fashion. Figure 23.3 illustrates a multi-level priority queue
for threads. In the figure, assuming a single-processor computer, threads A and B each execute
for a quantum in round-robin fashion until both threads complete execution. This means that A
gets a quantum of time to run. Then B gets a quantum. Then A gets another quantum. Then B
gets another quantum. This continues until one thread completes. The processor then devotes all
its power to the thread that remains (unless another thread of that priority becomes ready). Next,
thread C runs to completion (assuming that no higher-priority threads arrive). Threads D, E and
F each execute for a quantum in round-robin fashion until they all complete execution (again
assuming that no higher-priority threads arrive). This process continues until all threads run to
completion. Fig. 23.3 Thread-priority scheduling.
Creating and Executing Threads
In J2SE 5.0, the preferred means of creating a multithreaded application is to implement the Runnable
interface (package [Link]) and use built-in methods and classes to create Threads that execute the
Runnables. The Runnable interface declares a single method named run. Runnables are executed by
an object of a class that implements the Executor interface (package [Link]). This
interface declares a single method named execute. An Executor object typically creates and manages a
group of threads called a thread pool. These threads execute the Runnable objects passed to the
execute method. The Executor assigns each Runnable to one of the available threads in the thread
pool. If there are no available threads in the thread pool, the Executor creates a new thread or waits for
a thread to become available and assigns that thread the Runnable that was passed to method
execute. Depending on the Executor type, there may be a limit to the number of threads that can be
created. Interface ExecutorService (package [Link] ) is a subinterface of Executor that
declares a number of other methods for managing the life cycle of the Executor. An object that
implements the ExecutorService interface can be created using static methods declared in class
Executors (package [Link]). We use these interfaces and methods in the next application,
which executes three threads.
Class PrintTask (Fig. 23.4) implements Runnable (line 5), so that each PrintTask object can execute
concurrently. Variable sleepTime (line 7) stores a random integer value (line 17) chosen when the
PrintTask constructor executes. Each thread running a PrintTask object sleeps for the amount of time
specified by the corresponding PrintTask object’s sleepTime, then outputs its name.
Figure 23.5 creates three threads of execution using the PrintTask class. Method main (lines 8–28)
creates and names three PrintTask objects (lines 11–13). Line 18 creates a new ExecutorService. This
line uses the newFixedThreadPool method of class Executors, which creates a pool consisting of a fixed
number of Threads as indicated by the method’s argument (in this case, 3). These Threads are used by
threadExecutor to execute the Runnables. If method execute is called and all the threads in the
ExecutorService are being used, the Runnable will be placed in a queue and assigned to the first
thread that completes its previous task. Executors method newCachedThreadPool returns an
ExecutorService that creates new threads as they are needed by the application.
Thread properties
Name Description
CurrentPrincipal Gets or sets the thread's current principal (for role-based security).
CurrentUICulture Gets or sets the current culture used by the Resource Manager to
look up culture-specific resources at run time.
IsAlive Gets a value indicating the execution status of the current thread.
Synchronisation
Thread Interference
Consider a simple class called Counter
class Counter {
private int c = 0;
c++;
c--;
return c;
Counter is designed so that each invocation of increment will add 1 to c, and each invocation of
decrement will subtract 1 from c. However, if a Counter object is referenced from multiple threads,
interference between threads may prevent this from happening as expected.
Interference happens when two operations, running in different threads, but acting on the same data,
interleave. This means that the two operations consist of multiple steps, and the sequences of steps
overlap.
It might not seem possible for operations on instances of Counter to interleave, since both operations
on c are single, simple statements. However, even simple statements can translate to multiple steps by
the virtual machine. We won't examine the specific steps the virtual machine takes — it is enough to
know that the single expression c++ can be decomposed into three steps:
The expression c-- can be decomposed the same way, except that the second step decrements instead
of increments.
Suppose Thread A invokes increment at about the same time Thread B invokes decrement. If the
initial value of c is 0, their interleaved actions might follow this sequence:
Thread A: Retrieve c.
Thread B: Retrieve c.
Thread A's result is lost, overwritten by Thread B. This particular interleaving is only one
possibility. Under different circumstances it might be Thread B's result that gets lost, or there
could be no error at all. Because they are unpredictable, thread interference bugs can be difficult
to detect and fix.
Synchronized Methods
The Java programming language provides two basic synchronization idioms: synchronized methods and
synchronized statements. The more complex of the two, synchronized statements, are described in the
next section. This section is about synchronized methods.
To make a method synchronized, simply add the synchronized keyword to its declaration:
private int c = 0;
c++;
c--;
If count is an instance of SynchronizedCounter, then making these methods synchronized has two
effects:
First, it is not possible for two invocations of synchronized methods on the same object to
interleave. When one thread is executing a synchronized method for an object, all other threads
that invoke synchronized methods for the same object block (suspend execution) until the first
thread is done with the object.
Note that constructors cannot be synchronized — using the synchronized keyword with a constructor
is a syntax error. Synchronizing constructors doesn't make sense, because only the thread that creates
an object should have access to it while it is being constructed.
Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API
specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects
of synchronization: enforcing exclusive access to an object's state and establishing happens-before
relationships that are essential to visibility.
Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive
and consistent access to an object's fields has to acquire the object's intrinsic lock before
accessing them, and then release the intrinsic lock when it's done with them. A thread is said to
own the intrinsic lock between the time it has acquired the lock and released the lock. As long as
a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will
block when it attempts to acquire the lock.
You might wonder what happens when a static synchronized method is invoked, since a static
method is associated with a class, not an object. In this case, the thread acquires the intrinsic lock
for the Class object associated with the class. Thus access to class's static fields is controlled by a
lock that's distinct from the lock for any instance of the class.
Synchronized Statements
Another way to create synchronized code is with synchronized statements. Unlike synchronized
methods, synchronized statements must specify the object that provides the intrinsic lock:
Synchronized statements are also useful for improving concurrency with fine-grained
synchronization. Suppose, for example, class MsLunch has two instance fields, c1 and c2, that are
never used together. All updates of these fields must be synchronized, but there's no reason to
prevent an update of c1 from being interleaved with an update of c2 — and doing so reduces
concurrency by creating unnecessary blocking. Instead of using synchronized methods or
otherwise using the lock associated with this, we create two objects solely to provide locks.
Executors
The most important new feature for the casual developer of multithreaded applications is the new
Executor framework. A [Link] is an object that executes Runnable tasks.
It is similar to calling
For a single new thread, there is perhaps not much reason to use an Executor. However, most
multithreaded applications involve several threads. Threads need stack and heap space, and,
depending on the platform, thread creation can be expensive. In addition, cancellation and
shutdown of threads can be difficult, as seen in Chapter 8, and a well-designed and implemented
thread pooling scheme is not simple.
The new Executor framework solves all those problems in a way that decouples task submission
from the mechanics of how each task will be run, including the details of thread use, scheduling,
etc.
An Executor can and should be used instead of explicitly creating threads. For example, rather
than creating a new thread and starting it as above, you can use:
Notice that our Executor object was returned by an Executor factory. (We discuss design patterns
like factory methods in Chapter 16; a factory is a standard name for a method that is used to
obtain an instance of a class or subclass rather than making it with a constructor.)
There are several static Executor factory methods available in the [Link]
class. If you have several Runnable tasks to carry out, but do not have specific requirements
about the order in which they occur, then a simple thread pool arrangement is provided as
follows:
Here the tasks run and complete under the control of the Executor, which reuses threads from the
thead pool as needed without incurring the overhead of always creating new threads. You can
stop the threads with
[Link]();
There are several more Executor factories in the Executors class for other needs beyond the
scope of this book. Refer
If you need a result from a Runnable task, you have to provide some external means of getting
that result. A common technique is to set an instance variable in the Runnable object and provide
a method to retrieve that value. For example,
} // class MyRunnable
The Callable interface solves these problems. Instead of a run() method the Callable interface
defines a single call() method that takes no parameters but is allowed to throw an exception. A
simple example is
import [Link].*;
public class MyCallable implements Callable
{
public Integer call () throws [Link] {
return 1;
}
} // MyCallable
This call() method returns an Integer. (Note that we have conveniently used the autoboxing
support in J2SE 5.0 to have the literal int 1 value automatically boxed into an Integer return
value.)
Synchronizers
The purpose of most (if not all) synchronizers is to guard some area of the code (critical section)
from concurrent access by threads. To do this the following parts are often needed in a
synchronizer:
State
The state of a synchronizer is used by the access condition to determine if a thread can be
granted access. In a Lock the state is kept in a boolean saying whether the Lock is locked or not. In
a Bounded Semaphore the internal state is kept in a counter (int) and an upper bound (int) which
state the current number of "takes" and the maximum number of "takes". In a Blocking Queue
the state is kept in the List of elements in the queue and the maximum queue size (int) member (if
any).
Here are two code snippets from both Lock and a BoundedSemaphore. The state code is marked in
bold.
throws InterruptedException{
while(isLocked){
wait();
isLocked = true;
...
[Link] = upperBound;
[Link]++;
[Link]();
...