377
Table Of Contents Introduction to Java Programming and OOP’s Concept........4 An Introductory Description of OOP.......................5 Object-Oriented Programming Vocabulary...................7 Instance and Class Variables............................14 Constructors, Destructors, and Garbage Collection.......21 Polymorphism............................................25 Exception Handling......................................29 Core Java Classes, Input and Output Streams..............32 Introduction............................................32 Getting Started with I/O Streams........................33 Hierarchy Diagrams for I/O Streams......................36 Miscellaneous Classes...................................38 Reading and Writing Memory Buffers using Streams........39 Event Handling in JDK 1.0.2, The Event Class.............48 What is an Event........................................48 Encapsulating User Activities into Event Objects........49 Preview of Event Handling...............................52 The Component Class.....................................53 Methods.................................................55 The AWT Package, An Overview.............................56 The AWT Package, Placing Components in Containers, Absolute Coordinates.............................................. 59 Absolute Positioning and Size...........................59 Sample Program..........................................60 Program Listing.........................................63 The AWT Package, The Container, Panel, Window, and Frame Classes ......................................................... 65 Arranging Components in Containers......................66 Sample Program for Panels...............................68 Sample Program for Frame Class..........................69 Event Handling in JDK 1.1, A First Look, Delegation Event Model ......................................................... 74 A Quick Review of the 1.0 Event Model...................74 Sample Program..........................................76 More Detailed Overview of the Delegation Model..........81 Event Hierarchy.........................................82 JDK Object Serialization..............................94

Basic Java Handout

Embed Size (px)

Citation preview

Page 1: Basic Java Handout

Table Of Contents

Introduction to Java Programming and OOP’s Concept..............................................4An Introductory Description of OOP..............................................................................5Object-Oriented Programming Vocabulary.....................................................................7Instance and Class Variables..........................................................................................14Constructors, Destructors, and Garbage Collection......................................................21Polymorphism................................................................................................................25Exception Handling.......................................................................................................29

Core Java Classes, Input and Output Streams.............................................................32Introduction....................................................................................................................32Getting Started with I/O Streams...................................................................................33Hierarchy Diagrams for I/O Streams.............................................................................36Miscellaneous Classes...................................................................................................38Reading and Writing Memory Buffers using Streams...................................................39

Event Handling in JDK 1.0.2, The Event Class............................................................48What is an Event............................................................................................................48Encapsulating User Activities into Event Objects.........................................................49Preview of Event Handling............................................................................................52The Component Class....................................................................................................53Methods.........................................................................................................................55

The AWT Package, An Overview...................................................................................56The AWT Package, Placing Components in Containers, Absolute Coordinates.......59

Absolute Positioning and Size.......................................................................................59Sample Program.............................................................................................................60Program Listing.............................................................................................................63

The AWT Package, The Container, Panel, Window, and Frame Classes...................65Arranging Components in Containers...........................................................................66Sample Program for Panels...........................................................................................68Sample Program for Frame Class..................................................................................69

Event Handling in JDK 1.1, A First Look, Delegation Event Model..........................74A Quick Review of the 1.0 Event Model.......................................................................74Sample Program.............................................................................................................76More Detailed Overview of the Delegation Model.......................................................81Event Hierarchy.............................................................................................................82

JDK    Object Serialization..............................................................................................94Writing an Object to a Stream.......................................................................................95Reading an Object from the Stream...............................................................................96Sample Program.............................................................................................................97

JDBC, Introduction to JDBC and Database Access...................................................103Network Programming - General Information...........................................................113

Communication Protocol.............................................................................................113Domain Names............................................................................................................116Socket Programming....................................................................................................118URL Programming......................................................................................................120

Page 2: Basic Java Handout

Threading in Java..........................................................................................................121Multitasking vs. Multithreading..................................................................................121What is a Thread?........................................................................................................121The Thread Classes......................................................................................................122Naming Threads...........................................................................................................127Synchronization: the problem. part 1...........................................................................129Thread Groups.............................................................................................................136Daemon Threads..........................................................................................................137

Java Applet Programming............................................................................................140HTML Overview.........................................................................................................140Applet Basics............................................................................................................143Applet Security............................................................................................................150The Basic Applet Life Cycle........................................................................................153

Page 3: Basic Java Handout

Introduction to Java Programming and OOP’s Concept

Introduction

This lesson concentrates on Object-Oriented Programming (OOP). The lesson is intended to be independent of any specific language. As a practical matter, it is necessary to use some language for illustration purposes, and rather than to conjure up some artificial language, examples in this lesson are provided using either the Java or the C++ programming language.

Some languages such as C do not readily support OOP. Other languages such as C++ support OOP, but don't require you to use the object-oriented features of the language.

Still other languages such as Java require you to program using OOP techniques. In particular, it is not possible to write a program in Java without taking an object-oriented approach. You may do a good job, or you may do a poor job, but you must program using objects in Java.

Since C++ does not enforce a requirement to write object-oriented programs, it is possible to learn to use major aspects of the C++ language without ever learning to use the object-oriented features. In that case, the major challenge is simply learning to use the rudiments of the language.

On the other hand, the real challenge in becoming a Java programmer is not simply to learn the language. Even though the language contains some very sophisticated features such as multi-threading, it is not a complex language and is not particularly difficult to learn.

Page 4: Basic Java Handout

Persons capable of programming in Pascal or C should be able to master the core aspects of the language with a modest effort.

The real challenge in becoming a Java programmer lies in two areas:

1 Learning to productively utilize the large set of class libraries containing dozens of classes and hundreds of methods which are provided as part of the Java Development Kit to supplement the language.

2 Learning to design and program in the object-oriented paradigm.

The first of these challenges can be met on a gradual basis. In other words, it is not necessary to know the entire class library to produce useful Java programs.

The second challenge cannot be met on a gradual basis. It is not possible to create even the simplest Java program without programming in the object-oriented paradigm.

The technical prerequisite for this lesson is the ability to successfully write programs in Pascal or some other suitable modern structured programming or scripting language. It is assumed that students in this lesson are not familiar with OOP.

This lesson provides a discussion of OOP from both a theoretical and a practical viewpoint. In other words,

1 what is OOP,

2 why is it important, and

This lesson also provides a very brief introduction to object-oriented design (OOD) and introduces a

Page 5: Basic Java Handout

methodology for performing the first pass of an object-oriented design. However, this lesson will not endeavor to teach OOD to any significant depth. OOD is a very complex topic that is reserved for other lessons.

Finally, this lesson attempts to determine the minimum skill set that would be required of a beginning programmer before that programmer would have the ability to design and implement a program using object-oriented techniques.

An Introductory Description of OOP

An introductory description of OOP can be based on the following guideline:

The solution to the problem should resemble the problem, and observers of the solution should be able to recognize the problem without necessarily knowing about it in advance.

A good example of this guideline from the computing world is the use of OOP to develop a stack class from which stack objects can be instantiated. If a stack is implemented as a class, instantiated as an object, and documented appropriately, programmers familiar with stacks, queues, and other similar data structures will recognize it as a stack without other prior knowledge.

Many "application frameworks" are written according to the OOP paradigm. Important among these is the Borland ObjectWindows Library (OWL) which can be used to simplify the development of the Graphical User Interface (GUI) portions of Windows programs. This package and other similar application frameworks use

Page 6: Basic Java Handout

C++ class libraries to encapsulate the interface and implementation of the operating platform's applications programing interface (API). While the use of the OWL does not make it easy to develop GUI programs, the use of the OWL does greatly reduce the complexity of such development.

An Object-Oriented World

We are object-oriented creatures living in an object-oriented world. We tend to think in object-oriented ways.

For example, when planning a motor trip, we usually think first about the best way to get from point A to point B without being too concerned about how to get through the traffic in each of the cities along the way.

Once we are satisfied that we have the overall route mapped out appropriately, we may go back and begin thinking about the details, such as how to avoid five-oclock traffic in a particular city, where is the best place to stop for the night, is there some particular restaurant that we want to visit, and if so, how can we arrange the timing so as to arrive there at dinner time, etc. This is object-oriented thinking.

Previous approaches to programming (pre-OOP) tend to separate the data from the methods used to manipulate that data, or at least don't strongly encourage them to be considered in concert.

The world and its applications are not organized into values and procedures separate from one another. People who solve problems in other crafts do not perceive the world that way. They deal with their problem domains by concentrating on the objects and letting the characteristics of those objects determine the

Page 7: Basic Java Handout

procedures to apply to them.

To build a house, fix a flat tire, or repair a carburetor, you first think about the object and its purpose and behavior. Then you select your tools and procedures. The solution fits the problem.

Any object-oriented language must support three very important concepts:

1 encapsulation,

2 inheritance,

3 polymorphism.

We use these three concepts extensively as we attempt to model the real-world problems that we are trying to solve with our object-oriented programs.

Encapsulation Example

Consider the steering mechanism of a car as real-world an example of encapsulation. During the past eighty years or so, the steering mechanism has evolved into an object in the OOP sense. In particular, most of us know how to use the steering mechanism of an automobile without having any idea whatsoever how it is implemented. All most of us care about is the interface which we refer to as a steering wheel. We know that if we turn the steering wheel clockwise, the automobile will turn to the right, and if we turn it counterclockwise, the car will turn to the left.

Most of us don't know, and don't really care, how the steering mechanism is actually implemented "under the hood." In fact, there are probably a number of different implementations for various brands and models of

Page 8: Basic Java Handout

automobiles. Regardless of the brand and model, however, the human interface is pretty much the same. Clockwise turns to the right, counterclockwise turns to the left.

To appreciate the importance of this standard interface, attach a short rental trailer to your car and try backing it into your driveway. Turning the steering wheel counterclockwise causes the trailer to turn to the right and clockwise causes the trailer to turn to the left; just the opposite from the above. Most of us aren't accustomed to this interface and have some difficulty using it, at least initially. It is probably safe to suggest that the human factors aspect of the interface to the steering mechanism in your car wasn't designed for backing up with a trailer attached. (The trick to adapting the interface is to put you hand on the bottom of the steering wheel instead of the top.)

In any event, as in the steering mechanism for a car, a common approach in OOP is to "hide the implementation" and "expose the interface" through encapsulation.

Inheritance Example

Another important aspect of OOP is inheritance. Let's form an analogy with the teenager who is building a hotrod. That teenager doesn't normally start with a large chunk of steel and carve an engine out of it. Rather, the teenager will usually start with an existing engine and make improvements on it. In OOP lingo, that teenager extends the existing engine, derives from the existing engine, inherits from the existing engine, or subclasses the existing engine.

Just like in "souping up" an engine for a hotrod, a very

Page 9: Basic Java Handout

common practice in OOP is to create new improved objects using new definitions that extend existing definitions. In fact, one of the major arguments in favor of OOP is that it provides a formal mechanism which encourages the reuse of existing programming elements. One of the mottos of OOP is: reuse, don't reinvent.

Polymorphism Example

A third important aspect of OOP is polymorphism. This is a greek word meaning something like one name, many forms. This is a little more difficult to explain in non-programming terminology. However, we will stretch our imagination a little and say that polymorphism is somewhat akin to the automatic transmission in your car. In our Honda, for example, the automatic transmission has four different methods or functions known collectively as Drive (in addition to the functions of Reverse, Park, and Neutral).

As an operator of the automobile, We simply select Drive (meaning go forward). Depending on various conditions at runtime, the automatic transmission system decides which version of the Drive function to use in every specific situation. The specific version of the function that is used is based on the current conditions. This is somewhat analogous to what we will later refer to as runtime polymorphism.

We also believe it is true that    our Honda has only one method which we refer to as Reverse. Once We select Reverse, that one method gets used. There is no automatic selection among multiple reverse methods. Therefore, our Honda exhibits polymorphic behavior when going in the forward direction, but exhibits non-polymorphic behavior when going backwards.

Page 10: Basic Java Handout

Summary

The world is object-oriented, and the object-oriented programming paradigm attempts to express computer programs in ways that model how people perceive the world.

Object-Oriented Programming Vocabulary

OOP involves a whole new vocabulary (or jargon) which is different from or supplemental to the vocabulary of procedural programming.

For example the object-oriented programmer defines an abstract data type by encapsulating its implementation and its interface into a class.

One or more instances of the class can then be instantiated.

An instance of a class is known as an object.

Every object has state and behavior where the state is determined by the current values stored in the instance variables and the behavior is determined by the instance methods of the class from which the object was instantiated.

Inherited abstract data types are derived classes or subclasses of base classes or superclasses. We extend superclasses to create subclasses.

Within the program the programmer instantiates objects (creates instances of classes) and sends messages to the objects by invoking the class's methods (or member functions).

If a program is "object oriented", it uses encapsulation, inheritance, and polymorphism. It defines abstract data types, encapsulates those abstract data types into classes, instantiates objects, and sends messages to the objects.

Page 11: Basic Java Handout

To make things even more confusing, almost every item or action used in the OOP jargon has evolved to be described by several different terms. For example, we can cause an object to change its state by sending it a message, invoking its methods, or calling its member functions. The term being used often depends on the author who wrote the specific book that you happen to be reading at the time.

Hopefully most of this terminology will become clear as we pursue this lesson.

The Overall Characteristics of an Object-Oriented Program

An object-oriented program has three explicit characteristics and one implicit characteristic. The three explicit characteristics are encapsulation, inheritance, and polymorphism. The implicit characteristic is abstraction.

The implicit characteristic of abstraction is used to specify new abstract data types (ADT).

Encapsulation is used to gather an ADT's data representation and its behavior into one encapsulated entity (to convert from the abstract to the concrete). You might think of this as being similar to converting an idea for an invention into a set of blueprints from which it can be built, or converting a set of written specifications for a widget to a set of drawings that can be used by the machine shop to build the widget.

Automotive engineers encapsulated the specifications for the steering mechanism of our car into an object where they exposed the interface (steering wheel) and hid the implementation (levers, bolts, etc.). In all likelihood, the steering mechanism object contains a number of other more-specialized embedded objects, each of which has state and behavior and has interface and implementation. The

Page 12: Basic Java Handout

interfaces to those embedded objects aren't exposed to us, but they are exposed to the other parts of the steering mechanism that use them.

Inheritance is used to derive a new data type from an existing one. (reuse, don't reinvent.)

The teenager building the hotrod doesn't reinvent the engine, rather he extended an existing engine to produce a new type of engine that will run faster.

Polymorphism is used to customize the behavior of an instance of a type (an object) based on existing conditions.

The automatic transmission in our car modifies its behavior at runtime on the basis of existing conditions.

What is An Object

Before getting into a detailed discussion of encapsulation, inheritance, and polymorphism, let's consider some basic questions.

1 What are the objects in OOP?

2 What should be the objects in the design of an object-oriented program?

3 What is it about OOP that sets it apart from and possibly makes it better than traditional procedural programming?

This lesson will concentrate primarily on the first and third questions, and will provide a very brief introduction to object-oriented design near the end.

Simply stated, and taking a very liberal view:

An object is an instance of a data type.

Page 13: Basic Java Handout

The following C++ code fragment declares two objects. The first object is an instance of a simple integer variable named ndays. (Some authors would not agree that an instance of an integer is actually an object, but this author is taking a very liberal view at this point for purposes of illustration.)

The second object is an instance of an abstract data type where the object is named cdt and the abstract data type is named Date.

  void f(){  ...    int ndays; //an instance of an int    //an instance of abstract data type identified as Date    Date cdt;   ... }

You probably already know, or can surmise, where the integer data type comes from. It is a type which, along with float, long, double, etc., is intrinsic to C, C++, and Java. In other words, it is one of the primitive types of the language.

It is assumed that you don't know about the abstract data type named Date. During this lesson, you will learn, in concept at least, how to define new data types and how to create instances of them (objects).

So, what are the objects? Again, taking a very liberal view, objects are the variables that you declare using

Page 14: Basic Java Handout

either data types which are intrinsic to the programming language, or new data types that you invent.

Many authors would not use the term object for variables of the primitive or intrinsic types, but would reserve the term object for variables of newly-defined types which are not intrinsic to the language. This author generally agrees with that philosophy. Usually in this lesson, when we use the word object, we will be referring to a variable of a type which is not intrinsic to the language. The intrinsic types have been included up to this point simply for illustration, in an attempt to bridge the gap and remove some of the mystery from the subject.

Abstraction

The implicit characteristic of an object-oriented program is Abstraction. Abstraction is the specification of an abstract data type, which includes a specification of the type's data representation and behavior. In particular,

1 what kind of data can be stored in an entity of the new type, and

2 what are all the ways that that data can be manipulated.

For our purposes, an abstract data type is a new type (not intrinsic to the language). It is not one of the primitive data types that are built into the programming language (such as int, long, float, etc.).

The distinction in the previous paragraph is very important. The data representation and behavior of the intrinsic or primitive types is already known to the compiler and cannot be modified by the programmer.

The representation and behavior of an abstract type is

Page 15: Basic Java Handout

not known to the compiler until it is specified by the programmer and presented to the compiler in an appropriate manner.

How do we present the specification of an abstract type to the compiler? Java and C++ programmers define the data representation and the behavior of a new type (present the specification to the compiler) using the keyword class (C++ programmers can also use the keywords struct and union).

In other words, in Java and C++, the keyword class is used to convert the specification of a new type into something that the compiler can work with; a set of plans as it were.

Other languages may use different mechanisms to present the specification of the abstract type to the compiler.

Once the new type is defined, one or more objects of that type can be brought into being (instantiated, caused to occupy memory).

Once instantiated, the object is said to have state and behavior. The state of an object is determined by the current values of its data (instance variables) and the behavior of an object is determined by its methods (member functions or instance methods).

For example, again taking some liberties, if we view a GUI button as an object, it is fairly easy to visualize state and behavior.

A GUI button can usually manifest any of a number of different states: size, position, depressed image, not depressed image, caption, etc. Each of these states is

Page 16: Basic Java Handout

determined by data stored in the instance variables of the button object at any given point in time. (The combination of one or more instance variables that determine a particular state are often referred to as a property of the object.)

Similarly, it is not too difficult to visualize the behavior of a GUI button. When you click it with the mouse, that usually causes some specific action to take place.

In fact, if you dig deeply enough into GUI programming tools, you will probably find that there is a class of button of which each individual button is an instance (object).

Each individual button object has instance variables, the values of which define the state of the button at any given time.

Every instance of the button class has certain fundamental behavior (respond to a click event, respond to a mouse dragover, etc.) which can be used to trigger some higher level action.

Sample Class Definition

We have probably reached the point in this discussion where we should provide a real example so that you can cast some of these concepts into the real world.

The boldface portion of the following Java program creates an abstract data type by expressing its data representation and behavior using the class keyword. The compiler knows nothing about this new data type (at least not until it is defined by the programmer). In case you are interested, this Java program displays the date 4/8/37 as a string on the console screen.

import java.util.*;

Page 17: Basic Java Handout

//define a new type using keyword classclass MyDateClass {     int month, day, year; // instance variables of the class

    //instance method to store data    void setDate(int mo, int da, int yr)         {        month = mo;        day = da;        year = yr;    }//end method setDate()

    String getDate()//instance method to get data    {        return "" + month + "/" + day + "/" + year;    }// end method getDate()

}//end class MyDateClass definition

//Driver program followsclass java1 { //define the controlling class    public static void main(String[] args){ //define main        MyDateClass obj = new MyDateClass(); //instantiate obj        obj.setDate(4,8,37); //store data in instance variables        //get and display instance variables        System.out.println( obj.getDate() );    }//end main}//end java1 class

This abstract data type named MyDateClass has month, day,

Page 18: Basic Java Handout

and year data members (instance variables).

The behavior of the new type is defined by two instance methods. One can be used to store a date in an object of the new type. The other can be used to retrieve a stored date from the object.

The new type could be expanded to incorporate other behaviors by providing additional methods.

Having defined the new type, we can (and do) create instances of the type (objects) and deal with those objects much as we would deal with any other variables created from the primitive data types.

Encapsulation

The first of the three major characteristics of an object-oriented program is encapsulation. If abstraction is the design or specification of a new type, then encapsulation is its definition and implementation.

A programmer encapsulates the data representation and behavior of an abstract data type into a class, thereby defining its implementation and interface.

According to good object-oriented programming practice, an encapsulated design usually hides its implementation from the class user and reveals only its interface. This is accomplished in different ways with different languages as described below.

Just as most of us don't usually need to care about how the steering mechanism of a car is implemented, a user of a class should not need to care about the details of implementation -- only that it works as advertised. Of course this assumes that the user of the class has access to good documentation describing the class.

Page 19: Basic Java Handout

For a properly designed class, the class designer should be able to change the implementation -- perhaps changing the date representation to a long integer count of days since January 1, 1970 in the above program -- and the using programs should not be affected by the change.

Various object-oriented programming languages provide the ability to control access to the members of a class. For example, both C++ and Java use the keywords public, private, and protected to control access to the individual members of a class. To a first approximation, at least, you can probably guess what public and private mean. The protected keyword is used to provide inherited classes with special access privileges to the members of their base classes. (Java has some subtle complexities, related to access within a package which won't be discussed here.)

In general, the interface of a class which is visible to the user of the class consists of the public methods. The class user stores, reads, and modifies values in the data representation by invoking those methods with respect to a specific instance (object) of the class (sometimes referred to as sending a message to the object asking it to change its state).

Normally, if the class is properly designed, (the implementation is hid) the user cannot modify the values contained in the instance variables of the object without going through the prescribed interface (normally you cannot cause your car to change direction without turning the steering wheel).

The class interface in the above example program consists of a set method and a get method. The set method

Page 20: Basic Java Handout

is used to store new data into the instance variables of an object of the class. The get method is used to retrieve or fetch the values stored in the instance variables of an object of the class.

Note however that because of the complexity introduced by the package concept in Java, and because of the desire to keep this program as simple as possible, no attempt was made to hide the implementation. The primary purpose of this program was to provide a first look at classes and it is not a well-designed program from an object-oriented programming viewpoint.  

As an aside, methods whose names begin with set and get have a special significance in Java. In particular, the introspection capability of the Java Beans API considers these names to represent design patterns for manipulating the properties of an object.

An object-oriented design is not a good design by default. In an attempt to produce good designs, experienced object-oriented programmers generally agree on certain design standards for classes. For example, the data members (instance variables) are usually private. The interface usually consists only of methods and includes few if any data members.

One exception to this general rule is that often data members which are intended to be used as symbolic constants are made public and defined in such a way that their values cannot be modified.

The methods in the interface should control access to, or provide a pathway to, the private instance variables. The

Page 21: Basic Java Handout

interface should be generic in that it is not bound to any particular implementation. Hence, the class author should be able to change the implementation without affecting the using programs so long as the interface doesn't change. In practice, this means that the signatures of the interface methods should not change, and that the arguments should continue to have the same meaning.

So far, we have dealt only with instance variables and instance methods. We also need to understand the concept of class variables and class methods which will be discussed in the next section.

Page 22: Basic Java Handout

Instance and Class Variables

Instance Variables

Instance variables are those data members of a class that are defined such that every individual instance of the class (object) has its own set of variables, totally independent of the variables associated with all other objects of the same or different classes.

In other words, each object has its own memory space where its own set of variables is stored. Because instance variables are bound to an object, they can be accessed only by way of the object to which they are bound.

Assuming that access to an instance variable is not prohibited by access control mechanisms (such as the use of the keyword private), it is usually accessed by joining the name of the object (or the name of a pointer to the object) to the name of the instance variable using the appropriate joining operator. The joining operator for Java is a simple period (sometimes called the dot operator).

The joining operator for C++ depends on whether the instance variable is being accessed using the name of the object or the name of a pointer to the object. When the name of the object is used, the joining operator is a simple period. When the name of a pointer to the object is used, the pointer operator (-) is used.

Other languages may use different methods for accessing the instance variables of an object.

Class Variables

Class variables are those data members of a class that

Page 23: Basic Java Handout

are shared among all objects of the class. It's not too far-fetched to think of them as quasi-global variables whose accessibility is restricted only to objects of a particular class, or to the class itself. In other words, only one copy of a class variable exists in memory and all objects of the class can access that copy.

An important characteristic of class variables is that they can also be accessed without the requirement to instantiate an object of the type. In this case, they are usually accessed using the name of the class joined to the name of the variable using the appropriate joining operator. The joining operator for Java is a simple period. The joining operator for C++ is the scope resolution operator which is two colons with no space in between (::).

In Java and C++, class variables are designated as such using the static keyword. (Designation of a class variable in C++ also involves a requirement to re-declare the variable outside the class definition.)

Also in Java and C++, member variables declared without the use of the static keyword are instance variables. In other words, by default, all member variables of a class are instance variables unless you designate them as class variables using the static keyword.

Page 24: Basic Java Handout

Instance and Class Methods

Note the following very important statements:

The methods of a class have direct access to the member variables of the same class regardless of their access control designation such as public, private, or protected (except that class methods can usually access only class variables). 

There is no requirement for the code in a method of the class to use either the name of an object or the name of the class to access the member variables of the same class.

The methods of a class come in two varieties: instance methods and class methods. As with instance and class variables, those methods designated static are class methods in Java and C++. Methods not designated static are instance methods.

Instance Methods

An instance method can only be invoked by way of an object of the class. In that sense, an instance method is bound to an object. However, unlike an instance variable, an object normally doesn't have its own separate copy of an instance method. It would be wasteful of memory resources to provide a separate copy of every instance method for every object of a class.

It is very important to understand that when an instance method is invoked on a particular object, and when the code in that method needs to access an instance variable of the class, it will access the particular copy of the

Page 25: Basic Java Handout

instance variable belonging to the object on which it was invoked. It is this ability to temporarily bind the method to the instance variables of the object on which the method is invoked that causes it to behave as an instance method.

The this Pointer or Reference

Instance methods in Java and C++ (and perhaps other object-oriented languages as well) exhibit another interesting characteristic. In particular, whenever an instance method is invoked, a pointer variable or reference variable named this comes into existence automatically. This reference variable refers to the object on which the method was invoked, and can be used by the code in the method for any purpose that a reference to that object might be needed.

Class Methods

Class methods can only access other class members (class variables or other class methods). They cannot access instance variables or instance methods.

The most important thing about class methods is that they can be accessed using the name of the class without a requirement to instantiate an object of the class. As with class variables, class methods can be accessed by joining the name of the class to the name of the method using the appropriate joining operator.

Page 26: Basic Java Handout

Sample Program

Much of what we have been discussing can probably be better understood when seen in the context of an actual program.

The following sample program illustrates the use of class and instance variables along with class and instance methods in a Java program. This is not an attempt to teach the Java programming language at this point. Rather, it is simply an attempt to illustrate OOP concepts using an actual Java program as the vehicle. As before, because of the access control complexity caused by the package concept in Java, and the desire to keep this sample program as simple as possible, no attempt was made to hide the implementation.

A - Instance variable contains 5B - Class variable contains 10C - Class variable contains 10

When compiled and executed, this program will produce the following output on the standard output device. You might want to remember this place so that you can refer to it as you examine the program.

Before we take a look at the complete program, lets examine some of the interesting code fragments that make up the program.

The first interesting code fragment shows the declaration of two member variables of the class. One is a class variable named classVariable and the other is an instance variable named instanceVariable.  

  int instanceVariable;     //declare an

Page 27: Basic Java Handout

instance variable  static int classVariable; //declare a class variable

These are typical variable-declaration statements in Java and C++ consisting of the name of the type followed by the name of the variable. The important thing to note in the context of this discussion is the use of the statickeyword in the declaration of the class variable.

The next code fragment shows the definitions of two methods (with the bodies of the methods deleted for brevity). One of these methods is a class method named classMethod and the other is an instance method named instanceMethod.

  void instanceMethod(){//define an instance method    //body of method deleted for brevity  }//end instanceMethod()      static void classMethod(){//define a class method    //body of method deleted for brevity  }//end classMethod()

Again, these are typical method or member function definitions for Java and C++ consisting of the name of the return type (where void means that nothing is returned) followed by the name of the method, followed by the formal argument list (which happens to be empty in this case). The body of the method is then enclosed within a matching pair of curly braces { }.

Again, the important thing to note in the context of this discussion is the use of the static keyword in the definition of the class method.

Page 28: Basic Java Handout

The next code fragment is a single statement taken from the body of one of the methods. This statement causes output to be displayed on the standard output device.

This single statement incorporates classes, class variables, instance methods, and overloaded operators, and illustrates some of the syntactical complexity that can be encountered in object-oriented programming.

System.out.println(    "A - Instance variable contains " + instanceVariable);

This is a Java statement. A completely different syntax would be required to achieve the same result in C++.

Note first that this statement has three elements joined with periods. The first element is the word System which is the name of one of the classes in the standard Java class library. As background information, the System class is automatically loaded whenever a Java application is started.

The name of the System class is joined to the word out using a period. The word out is the name of a member variable of the System class.

The member variable named out is a public class variable. This makes it possible to access the variable using the name of the class and the name of the variable joined by the period.

Note that the class variable named out is also joined to the word println using the period as the joining operator. The variable out is not only a class variable, it is also a reference variable (as opposed to a primitive variable) and it contains a reference to an object of the PrintStream class.

Page 29: Basic Java Handout

The PrintStream class has an instance method named println(). In fact, there are ten overloaded versions of the println() method in the PrintStream class. The behavior of the version used here is to cause its string argument to be displayed on the standard output device.

Now consider the string argument to the println method as shown below:

("A - Instance variable contains " + instanceVariable)

In Java (and C++ as well), literal strings are enclosed in quotation marks. You will note that not everything in this argument is enclosed in quotation marks. Note in particular the plus sign near the middle of the argument.

In Java, the plus sign is overloaded so that in addition to being used as an arithmetic addition operator, it is also used to concatenate strings.

An overloaded operator exhibits different behavior depending of the types of its operands.

Furthermore, the behavior of the overloaded plus operator also includes the ability to coerce its right operand into a string representation if it isn't already a string. In this case, the right operand is not a string, but rather is the instance variable named instanceVariable. Thus the behavior of the overloaded plus operator is to first convert the value of instanceVariable to a string representation and than to concatenate it to the left operand.

Some object-oriented languages such as C++ allow the programmer to overload almost all of the operators so as to define the behavior of those operators when used with

Page 30: Basic Java Handout

operands of new abstract data types. However, Java does not provide that capability. In this case, the plus operator is intrinsically overloaded by the system.

Now let's take another look at the same two methods as before, this time preserving the bodies of the methods for further examination.

void instanceMethod(){//define an instance method      System.out.println(      "A - Instance variable contains "             + instanceVariable);      System.out.println(      "B - Class variable contains "             + classVariable); }//end instanceMethod()

static void classMethod(){//define a class method System.out.println( "C - Class variable contains " + classVariable); }//end classMethod()

Here we see the code in the body of the methods accessing the member variables of the class. Recall that one of the member variables is an instance variable named instanceVariable and the other member variable is a class variable named classVariable.

The instance method named instanceMethod is able to access and display both the instance variable and the class variable while the class method named classMethod is only allowed to access and display the class variable. Class methods cannot access instance variables.

Page 31: Basic Java Handout

Now consider the contents of the main method as shown below. Both Java and C++ applications (not applets) require a main method or function as the controlling method of the application. In our simple application, we will use code in the main method to instantiate an object and to access both the instance method and the class method.

//instantiate an object of the class Oop01Oop01 obj = new Oop01();  

Recall that in order to access an instance method, it is necessary to access it via an object of the class. The next code fragment is the code in the main method that instantiates an object named obj of the class named Oop01.

This is a typical Java statement for instantiating an object and is similar to one form of statement that can be used to instantiate an object in C++. (C++ provides other forms as well.)

This statement uses the new operator to request that the operating system provide memory "from the heap" to store one copy of an object of type Oop01.

If the required memory is successfully allocated, the address of that block of memory will be assigned to the reference variable named obj. If unsuccessful, the Java runtime system will throw an exception. This is a type of exception which can either be ignored, or can be caught and processed by the program. If ignored, it will cause the runtime system to shut down the program. (Exception handling is discussed later in this lesson.)

Both Java and C++ support exception handling, but do so in slightly different ways.

Page 32: Basic Java Handout

Once we have access to an object of the class (or more correctly access to a reference variable which refers to an object of the class), we can use that reference variable to access the public member variables and to invoke the public methods of the class. This is illustrated in the following code fragment.

The two statements in the following code fragment use the reference variable named obj along with the period to access the instance variable and the instance method of the object. Recall that the instance variables and the instance methods can be accessed only via an object of the class.  

//access instance variable via the objectobj.instanceVariable = 5;//access instance method via the objectobj.instanceMethod();

Equally important is the fact that the class variable and the class method can be accessed without the requirement to use an object of the class. The two statements in the following code fragment simply use the name of the class to access the class variable and the class method of the class.  

//access class variable via the classOop01.classVariable = 10;//access class method via the classOop01.classMethod();    

Class variables and class methods can be accessed either via an object of the class, or via the name of the class alone. However, this sample program does not illustrate accessing class variables and methods using an object of

Page 33: Basic Java Handout

the class.

Finally, we put it all together in the Java application shown below.

/*File Oop01.java Illustrates instance and class variables along with instance and class methods.

The output from this program is:

A - Instance variable contains 5B - Class variable contains 10C - Class variable contains 10**********************************************************/

class Oop01{ //define controlling class    int instanceVariable;      //declare an instance variable    static int classVariable; //declare a class variable     void instanceMethod(){//define an instance method      System.out.println(        "A - Instance variable contains " + instanceVariable);      System.out.println(              "B - Class variable contains " + classVariable);    }//end instanceMethod()   

Page 34: Basic Java Handout

    static void classMethod(){//define a class method      System.out.println(              "C - Class variable contains " + classVariable);    }//end classMethod()        public static void main(String[] args){      //instantiate an object of the class Oop01      Oop01 obj = new Oop01();       //access instance variable via the object      obj.instanceVariable = 5;      //access class variable via the class      Oop01.classVariable = 10;      //access instance method via the object      obj.instanceMethod();          //access class method via the class      Oop01.classMethod();          }//end main()}//end class Oop01

Messages

Methods are sometimes called member functions (particularly in books on C++).

A message is simply the invocation of a method or member function.

The program "sends a message" to an object telling it to invoke the method and sometimes provides parameters for the method to use.

Someone recently wrote that an object-oriented program

Page 35: Basic Java Handout

consists simply of a bunch of objects laying around sending messages to one another. This might be a slight exaggeration, but is not too far from the truth.

Constructors, Destructors, and Garbage Collection

The allocation, reclamation, and reuse of dynamic memory from the heap is an important aspect of most object-oriented programs, and some non-object-oriented programs as well. The next few sections discuss how these requirements are met with respect to objects in Java and C++. Other object-oriented language use other techniques to accomplish the same objectives:

1 to allocate memory when it is needed by the program,

2 to reclaim that memory when it is no longer needed, and

3 to reuse it as appropriate.

Failure to deal with this important issue results in a condition often referred to as "memory leakage."

Constructors

Both Java and C++ and possibly other object-oriented languages as well, support the notion of a constructor. The following Java code fragment shows a constructor at work.  

//instantiate an object of the class Oop01 in JavaOop01 obj = new Oop01(); 

A constructor is a special method of a class that is used to instantiate (and optionally initialize) a new object of the

Page 36: Basic Java Handout

class type. In the above statement, the invocation of the constructor method is highlighted in boldface. Constructors can be overloaded just like other methods in Java and C++.  

Method overloading will be discussed in more detail in a later section on polymorphism. Briefly, method overloading means that two or more methods can share the same name provided that they have different argument lists. When the program is compiled, the compiler determines which version of the method to use in that instance on the basis of the actual parameters being passed to the method.

In this particular statement, the new operator is used to allocate dynamic memory from the heap, and the constructor is used to construct the object in that memory space. The address of the memory containing the object is returned and assigned to the reference variable named obj. If the memory cannot be allocated, an exception will be thrown.

In Java and C++, if you do not define a constructor when you define a new class, a default constructor that takes no parameters is defined on your behalf. This is often referred to as the default constructor or the noarg constructor.

It is also possible for you to define a constructor for your class which takes no arguments and which performs some special action when it is invoked. Defining a constructor is only slightly different from defining any other method in Java or C++ (it must have the same

Page 37: Basic Java Handout

name as the class, does not have a return type, and must not have a return statement).

Although you are free to cause your constructor to perform just about any action that you want, the intended purpose of a constructor is to perform some form of initialization (open a file, initialize instance variable values, etc.) If you provide such a noarg constructor, it will be invoked in place of the default constructor when you invoke the constructor as shown in the above code fragment with no arguments. The constructor shown above is a Java constructor. The invocation of a constructor in C++ is even simpler. An example is shown below:

Oop01 obj; //instantiate object of class Oop01 in C++

C++ provides other formats for invoking the constructor in addition to that shown above.

It is also possible for you to define one or more overloaded versions of the constructor that do take parameters. These are commonly called parameterized constructors. Typically you will include code in the body of the constructor to use the arguments passed as parameters for some sort of initialization, but again, you can write the code to perform just about any action that you want.

The following code fragment shows the important parts of a Java program, similar to the previous one which has been modified to use a parameterized constructor.

Oop02(int iV, int cV){ //parameterized constructor    instanceVariable = iV; //initialize the instance variable

Page 38: Basic Java Handout

    classVariable = cV;        //initialize the class variable}//end parameterized constructor    ...        public static void main(String[] args){    //instantiate an object of the class Oop02    Oop02 obj = new Oop02(2,3);

This code fragment shows the parameterized constructor method named Oop02 and then shows the statement used in the main method to instantiate and initialize an object of the class Oop02 named obj. As you can see, the parameterized constructor in Java looks just like a method except that it has no return type or return statement.

Destructors

A destructor is a special method typically used to perform cleanup after an object is no longer needed by the program. C++ supports destructors, but Java does not support destructors. Other object-oriented languages may or may not support destructors.

In C++, you can optionally define a destructor for a class. It looks much like any other method except that it cannot take parameters, does not have a return type, must not have a return statement, cannot be overloaded, and has the same name as the class except that it has a tilde (~) as a prefix to the name.

In C++, if you define a destructor for a class, it will be automatically invoked whenever an object of that class goes out of scope. Typically destructors are used to perform cleanup of some sort, and are often used to return dynamic memory to the operating system when

Page 39: Basic Java Handout

the object goes out of scope and that memory is no longer needed by the program. The code in the destructor can perform other actions as well, such as closing files, etc., or can do just about anything that you want it to do.

Garbage Collection

Java supports another mechanism for returning memory to the operating system when it is no longer needed by an object: garbage collection. The garbage collector is a part of the runtime system that runs in a low-priority thread reclaiming memory that is no longer needed by objects used by the program. An object becomes eligible for garbage collection in Java when there are no longer any reference variables that reference the object.

In Java, you can have one or more reference variables which reference the same object. That object will not become eligible for garbage collection until all of those reference variables go out of scope, are assigned to a different object, or are assigned a value of null.

Inheritance

The first major characteristic of an object-oriented program is encapsulation which was discussed above. The second of the three major characteristics is inheritance, with polymorphism occupying the third slot. Now let's take a look at inheritance.

A class can normally inherit the attributes and characteristics of another class (although inheritance can be blocked using different methods in different languages).

The original class is often called the base class or the

Page 40: Basic Java Handout

superclass, and the new class is often called the derived class or the subclass. Inheritance is often referred to as extending the base class or superclass.

Inheritance is hierarchical. In other words, a class may be the subclass of one class and the superclass of another class.

The derived class inherits the data representation and behavior of the base class except where the derived class modifies the behavior by overriding methods. The derived class can also add new data representation and behavior that is unique to its own purpose.

(The teenager building a hotrod may override the old two-barrel carburetor by replacing it with a new four-barrel model, and may also add a blower and other speed-enhancing widgets that were not a part of the original engine design.)

A program can usually instantiate objects of a base class as well as of a class which is derived from the base class. (It is also possible to block instantiation of the base class in some cases by defining it as an abstract base class.) If the base class is an abstract base class -- one that exists only to be derived from -- the program may not instantiate objects of the base class but can instantiate objects of classes derived from the base class.

The Java and C++ inheritance mechanisms allow you build an orderly hierarchy of classes. (In C++, because of multiple inheritance, it is also possible to build hierarchies that are not so orderly.) Java does not support multiple inheritance.

When several of your abstract data types have characteristics in common, you can design their

Page 41: Basic Java Handout

commonalities into a single base class and separate their unique characteristics into unique derived classes. This is one of the purposes of inheritance.

For example, suppose you are building a program dealing with airships. All airships have altitude and range parameters in common. Therefore, you could build a base Airship class containing data and methods having to do with range and altitude.

From this base class, you might derive a Balloon class and an Airplane class.

The Balloon class might add variables and methods dealing with passenger capacity and what makes it go up (helium, hydrogen, or hot air). Objects of the Balloon class would then be able to deal with altitude, range, passenger capacity, and what makes it go up.

The Airplane class might add variables and methods dealing with engine type (jet or propeller) and cargo capacity. Objects of the Airplane class could then deal with altitude, range, engine type, and cargo capacity.

Having created this hierarchy of classes, you could instantiate objects of type Airship, Balloon, or Airplane with the objects of each type having variables and methods to deal with those special characteristics of the flying machine indicated by the name of the class. (Although there isn't any requirement to do so, hopefully your will use descriptive names for your classes.)

You may have noticed that in this hierarchical class structure, inheritance causes the structure to grow in a direction from most general to less general. This is typical.

Single and Multiple Inheritance

Page 42: Basic Java Handout

C++, and perhaps other object-oriented languages as well, allow for multiple inheritance. This means that a new class can be derived from more than one base class. This has advantages in some cases, but can lead to difficulties in other cases.

The designers of the Java language chose not to support multiple inheritance. Instead they provided a different mechanism called an interface which can often be used to achieve the same end result as multiple inheritance with fewer potential problems. This topic is much too specific to discuss in detail here. It is mentioned simply to alert you to the fact that an object-oriented language that you choose may, or may not support multiple inheritance, and if not, may provide some alternative mechanism to achieve the same end result.

The ISA Relationship

You will sometimes hear people speak of the ISA relationship when discussing OOP. The source of this terminology is more fundamental than you may at first suspect.

Object-oriented designers often strive to use inheritance to model relationships where a derived class "is a kind of" the base class. For example, a car "is a kind of" vehicle. A programmer "is a kind of" employee which in turn "is a kind of" person.

This relationship is called the ISA relationship. It's that simple.

Polymorphism

The three required characteristics of an object-oriented language are encapsulation, inheritance, and polymorphism.

Page 43: Basic Java Handout

Polymorphism (from the Greek, meaning "many forms", or something similar) is the quality that allows one name to be used for more than one (hopefully related) but technically different purpose.

The purpose of polymorphism as it applies to OOP is to allow one name to be used to specify a general class of actions. Within a general class of actions, the specific action to apply in any particular instance is determined by the type of data involved.

More generally, the concept of polymorphism is the idea of "one interface, multiple methods". Polymorphism exists when functions or operators are overloaded or overridden to cause them to perform operations not implicitly recognized by the compiler. (Java does not support operator overloading but it does support the overloading and overriding of methods.)

Overloading Methods as a Form of Polymorphism

Perhaps the best-known simple example of polymorphism is the ability to replace the three C functions,

1 abs()

2 labs()

3 fabs()

by a single C++ or Java function called ABS()(or whatever name you choose to call it).

C requires three separate functions to return the absolute value of each of the three data types: int, long, and float. With C++ (and with Java), you can overload functions so that the absolute value of any of the three

Page 44: Basic Java Handout

data types can be obtained by calling a function having the same name for every data type. This is accomplished through function or method overloading. Function overloading provides a type of polymorphism often referred to as compile-time polymorphism. (Note that some authors do not consider function overloading to be a true or pure form of polymorphism.)

Overloading Operators as a Form of Polymorphism

Polymorphism is not necessarily new to Java, C++ and other modern languages. For example some programming languages that have been around for quite a while interpret the plus operator to be an arithmetic operator when applied to numeric data and to be a concatenation operator when applied to string data. (Actually that is the one form of operator overloading that is also supported by Java.) This is clearly an example of polymorphic behavior, and has been around since the early days of programming. However, that form of polymorphic behavior has been intrinsic to the language and could not be modified or controlled by the programmer.

C++ provides the opportunity, and (with one or two exceptions) the responsibility for the programmer to define the behavior of (almost) any operator that may be applied to an object of a new class. We refer to this as operator overloading. One operator (the assignment operator and possibly a few others) has a default behavior when applied to objects of a new class. The default behavior of the assignment operator is to make an identical bitwise copy of the object on the right and store it in the object on the left. Even this default behavior can be, and often is, overloaded to provide different behavior for the assignment operator relative to

Page 45: Basic Java Handout

objects of a new class.

There are about four or five operators that cannot be overloaded in C++. Beyond these, the C++ programmer can define the behavior of any operator when the operator is applied to an object of a new class. (Note however, that the programmer cannot modify the behavior of operators as applied to variables of the intrinsic or primitive types.)

This is an extremely valuable capability when used wisely. For example, in a program that deals extensively with vectors in 3D space, the programmer might choose to overload a subset of the arithmetic operators with respect to objects of a new vector class so as to provide a complete vector algebra for objects of that class.

Each object of the class could represent a vector in 3D space, and the plus sign, for example, could be applied to two such objects to produce a third object which would represent the sum of the two vectors represented by the operands.

Unfortunately, Java does not support operator overloading. There is probably little or nothing that can be accomplished with overloaded operators that cannot also be accomplished with overloaded methods, but in many cases, overloaded operators will provide a much cleaner and more intuitive syntax.

Overriding Methods as a Form of Polymorphism

Note that this section discusses the word override as opposed to the word overload. Overriding a method is an entirely different thing from overloading a method.

Previous sections have discussed overloading methods

Page 46: Basic Java Handout

and overloading operators. Polymorphism also exists when a derived class customizes the behavior of methods defined in the base class to meet the special requirements of the derived class. This is known as overriding methods and leads to runtime polymorphism.

Both Java and C++ support the notion of overriding a method in a base class to cause it to behave differently relative to objects of the derived class. In other words, a method named joe that is defined in the base class and is overridden in the derived class would behave differently depending on whether it is invoked on an object of the base class or on an object of the derived class.

Many people find runtime polymorphism to be one of the most difficult concepts of OOP to understand. Hopefully after this explanation, you won't fall in that category.

In both Java and C++, a pointer or reference variable of a base-class type can be used to point to or reference an object of any class derived from that base class.

If an overridden method is invoked using that base-class pointer or reference variable, the system will be able to determine, at runtime, which version of the method to use based on the true type of the object, and not on the type of pointer or reference variable used to invoke the method.

Therefore, it is possible to make selection decisions at runtime among a family of overridden methods as to which method to invoke based on which type of derived object is being pointed to by the base-class pointer when the overridden method is invoked on the base-class pointer. (Note that function overriding in C++ is somewhat more complex than in Java.)

Page 47: Basic Java Handout

This is illustrated in the following small, but non-trivial Java application. As a baseline, the application first invokes an overridden method named joe() an a base-class reference to a base-class object and then invokes the overridden method named joe() on a derived-class reference to a derived-class object.

In the first case, the base-class version of joe() is actually invoked. In the second case, the derived-class version of joe() is invoked. No surprises here.

Then the application invokes the overridden method named joe() on a base-class reference which actually refers to a derived-class object. When this is done, it is the version of the method defined in the derived class and not the version defined in the base class that is actually invoked. This is the essence of runtime polymorphism.

/*File Polymorph01.java

Illustrates runtime polymorphism with overridden methodsAssigns a derived class object to a base class reference and then invokes an overridden method on the base class reference.  As expected, the overridden method in the derived class is actually executed.

Output from the program is:  Executing base class version of method joe 1Executing derived class version of method joe 2Executing derived class version of method joe 3*************************************************

Page 48: Basic Java Handout

*********/

class Polymorph01{  static public void main(String[] args){    //base class ref to base class object     Base baseRef = new Base();     baseRef.joe(1); //invoke method named joe()          //derived class ref to derived class object          Derived derRef = new Derived();    derRef.joe(2); //invoke method named joe()

    //base class ref to derived class object        baseRef = derRef;    //invoke method named joe() on base ref to     // derived object    baseRef.joe(3);      }//end main}//end class Polymorph01

class Base{  void joe(int dataIn){    System.out.println(             "Executing base class version of method joe "                                                  + dataIn);  }//end joe()}//end class Base

class Derived extends Base{  void joe(int dataIn){    System.out.println(          "Executing derived class version of

Page 49: Basic Java Handout

method joe "                                                  + dataIn);  }//end joe()}//end class Derived

Inheritance and method overriding are used extensively in almost all Java programming. Even the simplest "Hello World" Java applet requires that the Applet class be extended and the paint() method be overridden.

Although it is possible to write some significant C++ programs without becoming involved in any form of OOP, those C++ programs that make use of commercial class libraries for such tasks as creation of data structures, building GUI interfaces, etc., also make extensive use of inheritance and method overriding.

Compile-Time and Run-Time Polymorphism

Many authors recognize two types of polymorphism:

1 compile-time polymorphism

2 run-time polymorphism.

On the other hand, some authors only recognize run-time polymorphism as being the true and pure form of polymorphism.

In C++, the programmer must be concerned about the difference and program accordingly (only virtual functions can be overridden). Generally speaking, in Java, the programmer need not make much of a distinction between the two because all methods can be overridden unless they are declared final.

The implementation of polymorphism in both Java and C++ essentially consists of providing multiple functions or methods with the same name, and calling the correct

Page 50: Basic Java Handout

one at the appropriate time on the basis of the type of data involved..

Compile-Time Polymorphism

If the construction is such that it is clear at compile time which version of two or more functions having the same name should be called in a specific instance, this is referred to as early binding, static binding, or compile-time polymorphism.

For example, function overloading and operator overloading are forms of compile-time polymorphism because the compiler knows when the program is compiled which of several versions of the same function name should be invoked in each instance.

Run-Time Polymorphism

As shown earlier, it is also possible to override and invoke a method in such a way that it is not known at compile time which version of the function is to be called in a particular instance. That determination cannot be made until the program is actually executed. This is often referred to as late binding, dynamic binding, or run-time polymorphism.

Exception Handling

While exception handling may not be considered by everyone as part and parcel of OOP, Java requires it, C++ supports it, and it can probably be expected that any object-oriented language that is not currently supporting it will do so in the future. Therefore, a section on exception handling is being included here to introduce you to the subject in a general sense.

Introduction to Exception Handling

Page 51: Basic Java Handout

Stated in simple terms, exception-handling capability makes it possible for you to monitor for exceptional conditions within your program, and to transfer control to special exception-handling code designed by you whenever an exceptional condition is detected. This is accomplished using the keywords: try, throw, throws, catch, and finally.

You try to execute the statements contained within a block surrounded by braces.

If your code (or the runtime system) detects an exceptional condition within that block, your code (or the runtime system) throws an exception object of a specific type.

Your code can then catch and process the exception object using code that you have designed, or your code can pass it up to the next level in the method-invocation hierarchy for handling there.

In Java, you can then optionally execute a block of code designated by finally which is normally used to perform some type of cleanup which is needed whether or not an exception occurs.

As indicated above, you can design your code to detect exceptional conditions and to throw an exception object. There are also situations where an exceptional condition will be detected by the runtime system which automatically throws an exception and attempts to transfer control to special exception-handling code which you write (cases where you don't provide the code to throw the exception object). In this case, you are responsible only for the code in the catch block and optionally, in Java, for the code in the finally block.

Page 52: Basic Java Handout

Although Java and C++ provide similar exception handling capabilities, the manner in which exception handling is implemented is different between the two languages. Therefore, the remainder of this section will concentrate on exception handling in Java, for those parts of the discussion which need to be language specific.

Our discussion will attempt to briefly touch on following topics, not necessarily in this order:

1 What is an exception?

2 In concept, how do you throw and catch exceptions?

3 What do you do with an exception once you have caught it?

4 How do you make use of the exception class hierarchy provided by the development environment?

Exception Hierarchy, An Overview

  "An exception is an event that occurs during the execution of a program that disrupts the normal flow of instructions."

When an exceptional condition causes an exception to be thrown in Java, that exception is an object derived, either directly, or indirectly from the class Throwable. In C++, it is also possible to throw exceptions of primitive types such as int.

The runtime system and many different methods in many different classes automatically throw exceptions in Java. Very few exceptions are automatically thrown in C++. Whereas Java requires you to program using exception handling, C++ makes it optional. However, once you

Page 53: Basic Java Handout

begin using proprietary class libraries in C++, the optional nature of exception handling disappears rather quickly.

In both languages, you can define and throw exception objects of your own design (but in Java you must inherit your exception class, either directly, or indirectly from the class Throwable).

The Throwable class in Java has two subclasses:

1 Error

2 Exception

Paraphrasing David Flanagan and Java in a Nutshell, an Error indicates that a non-recoverable error has occurred that should not be caught. Errors usually cause the Java interpreter to display a message and exit.

Still paraphrasing Flanagan, an Exception indicates an abnormal condition that must be properly handled to prevent program termination.

Of the many possible exceptions that can be automatically thrown in Java, there is a subset for which catching and processing is optional. The compiler will allow you to simply ignore the exceptions in this subset. If one of the exceptions which you ignore actually occurs, it will be caught by the runtime system, and the program will be terminated.

The remaining exceptions that can automatically be thrown in Java must be recognized by your code in order for your program to compile.

Recognition can consist of either

1 catching and processing the exception, or

Page 54: Basic Java Handout

2 passing it up to the next level in the method-invocation hierarchy.

Within this category, if one of the methods called by your method throws an exception, your method must either catch and process it, or pass it up to the next level in the method-invocation hierarchy.

If your method passes an exception up to the next level in the invocation hierarchy, this must be declared along with the method signature using the throws keyword.

If your code catches and processes an exception, the processing code can be as elaborate or as simple as you want to make it. In fact, simply ignoring it after you catch it will satisfy the compiler and allow your program to compile. This may, or may not be a good idea, depending on the type of the exception.

All exception objects inherit the methods of the Throwable class in Java, as well as the methods of any intermediate classes in the inheritance class hierarchy. Various methods are available to assist you in examining an exception object to extract the diagnostic information contained therein. Sometimes this information can be useful to your code in determining how to deal with the exceptional condition.

Advantages of Using Exception Handling

Exception handling provides the following advantages over "traditional" error management techniques:

1 Propagating Errors Up the Call Stack

2 Grouping Error Types and Error Differentiation

Propagating Errors Up the Call Stack

Page 55: Basic Java Handout

Sometimes it is desirable to propagate exception handling up the call stack and let the corrective action be taken at a higher level.

For example, you might provide a class with methods which implements a stack data structure. One of the methods of your class might be to pop an element off the stack.

What should the methods in your stack class do if a using program attempts to pop an element off an empty stack.? That decision might best be left to the user of your stack class and you might simply propagate the notification up to the calling method and let that method take the corrective action.

Grouping Error Types and Error Differentiation

The following statements describe certain aspects of exception handling:

1 Exceptional conditions throw objects.

2 Objects are instances of classes.

3 Classes may be inherited in Java.

As a result of the above, a natural hierarchy can be created which causes exceptions to be grouped in logical ways.

For example, going back to the stack example, you might create an exception class which applies to all exceptional conditions associated with an object of your stack class. From this, you might inherit other classes which pertain to specific exceptional conditions such a push exceptions, pop exceptions, initialization exceptions, etc.

If your code throws an exception object of one of the

Page 56: Basic Java Handout

specific types, that object can be caught

1 either by an exception event handler designed to catch on the basis of the group of exceptions, or

2 one designed to catch on the basis of one of the specialized exceptions.

This capability to handle exceptions on an organized hierarchical basis is very powerful

Core Java Classes, Input and Output Streams

Introduction

"A stream is a flowing sequence of characters."

Usually the task is to move data from memory to an external device or vice versa, but not necessarily. Streams can also be used to move data from one part of memory to another part of memory just as well.

It has been said that through the use of streams, it is the responsibility of the computer to move bytes from one place to another without regard for the meaning associated with those bytes.

It is the responsibility of the programmer to assign meaning to the bytes.

For example, a group of 32 bytes could represent 32 pieces of graphic data, or 8 integer values; the stream I/O system doesn't usually know and doesn't care.

Only the programmer and the user know and care what the 32 bytes are meant to represent.

In other words, a stream is usually considered to be an

Page 57: Basic Java Handout

abstraction for the capability to move bytes from a source to a sink.

We have previously seen examples of moving bytes from the keyboard (standard input device) to the computer's memory, and have seen examples of moving bytes from the computer's memory to the screen (standard output device).

We have also touched on the need to move bytes between disk files and the computer's memory.

The package named java.io contains a set of input and output stream classes that can be used to read and write data.

The InputStream class and OutputStream class are abstract superclasses that define the behavior for sequential input and output streams in Java.

The java.io package also provides specialized InputStream and OutputStream subclasses that are used for specialized types of input and output.

We will examine each of the classes, discuss how to use them, and how to subclass them for your own purposes.

Getting Started with I/O Streams

You are already familiar with the use of standard input, standard output, and standard error as provided by the System class.

For example, we have been using the following code fragments since the beginning of the Introductory course:  

System.out.println("my output string");

Page 58: Basic Java Handout

While (System.in.read() != -1) ...  System.out refers to an output stream managed by the System class that implements the standard output system.

System.out is an instance (an object) of the PrintStream class defined in the java.io package. The PrintStream class is a subclass of OutputStream.

The OutputStream Class

The OutputStream class is an abstract class which is the superclass of all output streams. It defines the basic output methods that all output streams provide. The following methods are defined in the OutputStream class.   close() - Closes the stream.  flush() - Flushes the stream.  write(int) - Writes a byte.  write(byte[]) - Writes an array of bytes.  write(byte[], int, int) - Writes a sub array of bytes.

The PrintStream Class

The Java specification, which is available on-line at JavaSoft, http://java.sun.com/ provides the following description for the PrintStream class:

A PrintStream adds functionality to another output stream -- namely, the ability to print representations

Page 59: Basic Java Handout

of various data values conveniently. 

Two other features are provided as well. Unlike other output streams, a PrintStream never throws an IOException; instead, exceptional situations merely set an internal flag that can be tested by the checkError method. 

Optionally, a PrintStream can be created so as to "autoflush"; this means that after an array of bytes is written, or after a single byte equal to '\n' is written, the flush method is automatically invoked.

The following methods are included in the list of methods available to objects of the PrintStream class of which the out object in the System class is an instance.

These are the methods of the System.out stream object .

checkError() - Flushes the print stream and returns whether or not there was  an error on the output stream.  close() - Closes the stream.  flush() - Flushes the stream. 

print(various argument types) - Prints the argument. 

println(various argument types) - Prints the argument.  println(String) Prints a string followed by a newline. 

write(int) - Writes a byte.  write(byte[], int, int) - Writes a sub array of bytes.

The println(String) method which we have used extensively in example programs in previous lessons is highlighted in boldface above. There are many other available

Page 60: Basic Java Handout

methods as well.

Recall that when we first used System.out.println(String), we explained that we were invoking the println() method of the out object which is a class variable of the System class.

Since the out object is of type PrintStream, all of the methods listed above are available to the out object.

Because it is a class variable, we can access it and its methods without first instantiating an object of the System class.

Java in a Nutshell indicates that the PrintStream class extends a class known as FilterOutputStream. We will deal with filtering later in this lesson.

Note that the System class is not part of java.io. Rather, it is part of java.lang.

The hierarchy relative to the object named out is

Object is the class from which all other classes are derived 

o OutputStream is a subclass of Object. 

FilterOutputStream is a subclass of OutputStream. 

PrintStream is a subclass of FilterOutputStream. 

System contains a class variable named out of type PrintStream. 

All classes in Java are subclasses of Object at some level. Each level of inheritance between the class named Object and the class variable named out adds methods and variables. The object named out contains all the methods

Page 61: Basic Java Handout

and variables contributed by all of its ancestors.

Standard Input

Now let's examine the following commonly-used code fragment with an eye toward the hierarchy.   While (System.in.read() != -1) ...

Here, we are invoking the read() method of the object referred to by in which is a class variable of the System class. The System class has three class variables:

1 err which is of type PrintStream

2 out which is also of type PrintStream

3 in which is of type InputStream

As seen in an earlier lesson, the System class also has about a dozen class methods which can be invoked without a requirement to instantiate an object of the class.

The InputStream class (of which the object referenced by in is an instance) is a subclass of the Object class and has considerably fewer methods than the PrintStream class (of which the object referenced by out is an instance).

The InputStream contains three overloaded public versions of read(); the one shown above and two which deal with arrays of type byte. All three throw IOException.

Peter Norton's Guide to Java Programming indicates that the form of read() which takes no arguments attempts to read and return a single byte from the input stream, cast as an integer. If there is nothing more to be read, it

Page 62: Basic Java Handout

returns a -1. The fact that the byte is returned cast as an integer needs to be taken into account when using this method.

The following description of the read() method which takes no parameters comes from JavaSoft's Java Language specification

The general contract of read is that it reads one byte from the input stream. The byte is returned as an integer in the range 0 to 255 (0x00-0xff). If no byte is available because the stream is at end of file, the value -1 is returned. 

This method blocks until input data is available, end of file is detected, or an exception is thrown. 

If the byte cannot be read for any reason other than end of file, an IOException is thrown. In particular, an IOException is thrown if the input stream has been closed

Similar material regarding the other overloaded versions of the read() method is also available in the Java Language Specification.

The hierarchy for the object in is (approximately)

Object is the class from which all other classes are derived 

o InputStream is an abstract subclass of the class Object 

in is a class variable of type InputStream 

While we know that it is not possible to instantiate objects of abstract classes (such as InputStream), this

Page 63: Basic Java Handout

structure suggests that it is possible to define class variables (such as in) which reference abstract classes, which in turn causes the class methods of the abstract class to become available by way of the class variable.

InputStream is the superclass of all input streams and it defines the basic input methods that all input stream classes provide.

Hierarchy Diagrams for I/O Streams

Most of the other classes in the java.io package derive from two classes: InputStream and OutputStream (also see the comment in the Preface section regarding readers and writers)

The InputStream class defines methods for

1 reading bytes or arrays of bytes

2 marking locations in the stream

3 skipping bytes of input

4 finding out the number of bytes available for reading

5 resetting the current position within the stream.

OutputStream defines methods for writing bytes or arrays of bytes to the stream.

Input and output streams are automatically opened when you instantiate an object of the proper type. Several example programs will be provided later which show the opening of input and output streams.

You can close an input stream or an output stream by using the close() method. Otherwise, it will be closed when the stream object is garbage collected.

Recall that objects become eligible for garbage

Page 64: Basic Java Handout

collection when they are no longer referenced by an object reference variable but there is generally no guarantee that garbage collection will occur before the program terminates.

Both InputStream and OutputStream have several subclasses that implement specific input and output functions.

The hierarchy structure for InputStream is shown in the first of the following two diagrams.

The hierarchy structure for OutputStream is shown in the second diagram.

Object        InputStream                FileInputStream                PipedInputStream                FilterInputStream (abstract)                        DataInputStream                        BufferedInputStream                        LineNumberInputStream                        PushbackInputStream                ByteArrayInputStream

Page 65: Basic Java Handout

                SequenceInputStream                StringBufferInputStream.

Object        OutputStream                FileOutputStream                PipedOutputStream                FilterOutputStream (abstract)                        DataOutputStream                        BufferedOutputStream                        PrintStream                ByteArrayOutputStream

Miscellaneous Classes

The java.io package contains other classes in addition to the stream classes.

File

Provides a platform-independent definition of file and

Page 66: Basic Java Handout

directory names. Also provides methods useful for performing a number of utility operations on files. For example, you can create a File object for a file on the native file system and then query the object for information about that file (such as its full pathname).

FileDescriptor

Platform independent representation of a low-level handle to an open file or an open socket. According to the Java Language Specification   A FileDescriptor is an opaque representation of a connection to an actual file in a file system, or to a network socket, or to another source or sink of bytes. The main practical use for a file descriptor is to create a FileInputStream or FileOutputStream to contain it..

RandomAccessFile

Allows reading and writing of arbitrary bytes, text, and primitive Java data types from or to any specified location in a file. Not a subclass of InputStream or OtputStream. Rather RandomAccessFile is an entirely independent method for reading and writing data from and to files. A large number of methods are provided.

You may have noticed that unlike other languages, thus far, we have not made mention of an ability to append data to an existing file. In order to append data to an existing file in Java, you must treat it as a random access file.

Interfaces

The java.io package defines three interfaces which are implemented by a variety of classes.

Page 67: Basic Java Handout

DataInput

Declares the methods required for streams that can read character data or Java primitive data types in a machine-independent format.

DataOutput

Declares the methods required for streams that can write character data or Java primitive data types in a machine-independent format.

FilenameFilter

Declares the accept() method that must be implemented by any object that filters filenames (selects a subset of filenames from a list of filenames).

Reading and Writing Files using Streams

To perform file I/O in Java, you must instantiate a stream object of the appropriate type and link it to a device.

As you can see from the following program, writing and reading sequential files in Java is fairly straightforward.  

/* File files01.java                      This application illustrates writing and then reading a file one byte at a time.

The instantiation of a file stream object is illustrated using two different approaches:1.  Using a literal string containing the name of the file.2.  Using an object of type File containing the name of the file.

Page 68: Basic Java Handout

Also illustrates use of the methods of the File class toinquire about the properties of the file:  absolute path and length.

The output from the program is:

Start the program and write a fileGet info on, read, and print the filePath is C:\BALDWIN\Java\SampProg\Java\junk.txtLength 4DickEnd of program**********************************************************/

import java.io.*;

class files01{  public static void main(String[] args)  {    System.out.println(                    "Start the program and write a file");    try{    //Instantiate and initialize an output file stream     // object using a string containing the name of the     // file.    FileOutputStream outFile = 

Page 69: Basic Java Handout

                          new FileOutputStream("junk.txt");      //Write four bytes to the file and close it    outFile.write('D');    outFile.write('i');    outFile.write('c');    outFile.write('k');    outFile.close();  }catch(IOException e){}

    System.out.println(                  "Get info on, read, and print the file");    //Instantiate an object of type file containing the name  // of the file.  File junkFile = new File("junk.txt");    //Use the File object to get info about the file  System.out.println(                 "Path is " + junkFile.getAbsolutePath());  System.out.println("Length " + junkFile.length() );    //Now read and print the data in the file  try{    //Instantiate and initialize the stream object using 

Page 70: Basic Java Handout

    // the File object.    FileInputStream inFile = new FileInputStream(junkFile);    int data;      //Read and print until eof indicated by -1.  read()     // method returns integer.  Must cast as char to print.    // Otherwise, the numeric value of the byte is     // displayed.    while( (data = inFile.read()) != -1)      System.out.print((char)data);    inFile.close();  }catch(IOException e){}  System.out.println(); //new line  System.out.println("End of program");  }// end main

}//end class files01 definition

Using Filtered Streams

We are going to take a look at filtered streams at this point because that information will be useful later.

The filtered stream classes make it possible for you to apply I/O filtering to data being processed by an object of an unfiltered stream class. For example, you could create a custom filter object to read a file and convert all the characters to upper case.

Filtered stream classes are subclasses of the abstract classes named FilterInputStream and FilterOutputStream.

Page 71: Basic Java Handout

There are several standard filtered streams available, and you can create your own. Those which are in the standard java.io package are:

1 DataInputStream and DataOutputStream

2 BufferedInputStream and BufferedOutputStream

3 LineNumberInputStream

4 PushbackInputStream

5 PrintStream

The characteristics of each of these classes were discussed earlier.

To use a filtered stream class, you must associate an object of the filtered stream class with an object of the unfiltered stream class that will handle your I/O. You do this by instantiating an object of the filtered class by passing an object of the unfiltered class to the constructor for the filtered class.

You can instantiate the object of the unfiltered class beforehand, or you can simply call the constructor for the unfiltered class as a parameter to the constructor for the filtered class (create it as an anonymous object).

Having done this, you then have access to all the methods of the filtered class to use in your I/O efforts.

The following sample application is a rewrite of the previous application named files01.java. In the previous application, it was necessary to perform I/O one byte at a time. In this rewrite, The DataInputStream and DataOutputStream classes are associated with the FileInputStream and FileOutputStream classes. This makes it possible to use the methods of DataInputStream and

Page 72: Basic Java Handout

DataOutputStream to control the I/O process.

This in turn makes it possible to perform the I/O one string at a time rather than one byte at a time. Numerous other methods are also available to perform the I/O in different ways.

Note that this program uses deprecated methods. The program named SampProg151 in the Review section at the end of the lesson shows how to replicate this program with no deprecated methods.  

/* File files02.java                      This application is a modification of the application namedfiles01.  The purpose is to illustrate the use of filteredI/O classes to write and then read a file, one string at atime.

Objects of types DataOutputStream and DataInputStream are instantiated using objects of types FileOutputStream andFileInputStream as parameters to the constructor.  This makes all of the methods for objects of types DataOutputStream and DataInputStream available to write and read the file.

Page 73: Basic Java Handout

The program was tested using JDK 1.1.3 under Win95.

The output from the program is:

Start the program and write a fileGet info about, read, and print the filePath is C:\BALDWIN\Java\SampProg\Java\junk.txtLength 13DickBaldwinEnd of program**********************************************************/

import java.io.*;

class files02{  public static void main(String[] args)  {    System.out.println(                    "Start the program and write a file");    try{

      //Instantiate and initialize a DataOutputStream       // object using a FileOutputStream object as a       // parameter to the constructor. This makes it       // possible to write to the file

Page 74: Basic Java Handout

using the methods      // of the DataOutputStream class.      DataOutputStream dataOut =         new DataOutputStream(                        new FileOutputStream("junk.txt"));        //Write two strings to the file and close it      dataOut.writeBytes("Dick\n");      dataOut.writeBytes("Baldwin\n");      dataOut.close();    }catch(IOException e){}

    System.out.println(              "Get info about, read, and print the file");      //Instantiate an object of type file containing the     // name of the file.  Same as app named files01.java.    File junkFile = new File("junk.txt");      //Use the File object to get info about the file.     // Same as files01.java.    System.out.println(                 "Path is " + junkFile.getAbsolutePath());    System.out.println("Length " +

Page 75: Basic Java Handout

junkFile.length() );      //Now read and print the data in the file    try{      //Instantiate a DataInputStream object on the       // FileInputStream object which uses the File object      // named junkFile to open the stream and link to       // the file.                  //Note that the compiler reports readLine() as a      // deprecated method and suggests using methods       // from the reader class instead.            DataInputStream inData =         new DataInputStream(new FileInputStream(junkFile));

      String data; //temp holding area        //Read and print strings until eof is indicated by       // null.        while( (data = inData.readLine()) != null)        System.out.println(data);      inData.close();

Page 76: Basic Java Handout

    }catch(IOException e){}    System.out.println("End of program");  }// end main}//end class files02 definition

Reading and Writing Memory Buffers using Streams

The unfiltered classes ByteArrayInputStream and StringBufferInputStream make it possible for you to read data from memory buffer areas as though you were reading from an external device.

ByteArrayOutputStream can be used to write data into a memory buffer as though it were an external device.

ByteArrayInputStream and ByteArrayOutputStream will allow you to read and write 8-bit data. When you create these streams, you specify an existing byte array and then use the read() and write() methods to read from or write data to the array in memory.

StringBufferInputStream allows you to to read data from a String object. When you create a StringBufferInputStream object, you specify an existing String object as the source of the data and then use the read() methods to read from that object.

The following program illustrates the use of a StringBufferInputStream object to read the contents of a String object. Note that even though this class is named StringBufferInputStream, it is not designed to read the contents of objects of type StringBuffer.

Note that the following program uses deprecated code. The program named SampProg152.java in the Review section shows how to replicate this program without using any deprecated code.

Page 77: Basic Java Handout

 

/* File stream02.javaThis application illustrates the use of a StringBufferInputStream object to read the contents of anobject of type String.

Note that even though this class is called StringBufferInputStream it does not read the contents ofobjects of type StringBuffer.  Rather, the data source must be an object of type String.

The output from the program is:

Start the program and create a String object.Create stream object of type StringBufferInputStream.Read and display the contents of the String object.This is an object of type String.End of program**********************************************************/import java.io.*;  class stream02{//controlling class  public static void main(String[] args)  {

Page 78: Basic Java Handout

    System.out.println(         "Start the program and create a String object.");    String myString = "This is an object of type String.";            System.out.println("Create stream object of type " +                              "StringBufferInputStream.");                                  //Note that StringBufferInputStream is deprecated.  The    // documentation recommends using the StringReader    // class instead.    StringBufferInputStream myStream =                     new StringBufferInputStream(myString);

    System.out.println("Read and display the contents " +                                 "of the String object.");          for(int cnt = 0; cnt < myString.length(); cnt++)            System.out.print((char)myStream.read());                System.out.println("\nEnd of program");  }// end main

Page 79: Basic Java Handout

}//end class stream02 definition

Reading and Writing Random Access Files

The previous discussions have been concerned with sequential input/output. That is, input and output where the bytes are transferred as a sequential stream of bytes. This is a particularly appropriate form of I/O for communication with other computers via the network, etc.

However, when working with disk files, it is often desirable to be able to treat the data in the file as an an "array" of bytes and to be able to access those bytes anywhere within the array. This can be accomplished using the random access capabilities afforded by Java

Note that unlike other languages, the classes that we have been studying do not allow for appending data to the end of a file. In order to append data to the end of a file in Java, you must treat that file as a random access file.

Random access of file data in Java is supported by the RandomAccessFile class.   Using Random Access Files

The RandomAccessFile class can be used both for reading and writing. It implements the DataInput and DataOutput interfaces.

As with the sequential FileInputStream and FileOutputStream classes, you specify a file to be opened by name when you instantiate an object of class RandomAccessFile. You can specify the file name either by a literal string or by passing a File object which you have previously

Page 80: Basic Java Handout

instantiated.

Unlike with the sequential classes, when you instantiate an object of RandomAccessFile, you must indicate whether you will just be reading the file, or also writing to it. You must be able to read a file before you can write to it.

The syntax for instantiating a RandomAccessFile object is as follows:

new RandomAccessFile(name, mode)

As mentioned earlier, the name can be specified using either a literal string or an object of type File. The mode is a literal string which can be either of two possibilities:

1 "r" means open for reading only

2 "rw" means open for both reading and writing

Once the file is opened you can use the various forms of the read___() and write___() methods to read and write the data in the file.

Simply being able to use the read and write methods to read or write the data in the file wouldn't be very interesting except for the availability of some additional methods. In particular, as in other languages which support random file I/O, RandomAccessFile supports the notion of a file pointer.

The file pointer points to the current location in the file. It points to the beginning of the file (value of 0) when the object is first instantiated. When you use the normal read and write methods, the value of the pointer is adjusted by the number of bytes actually read or written.

In addition, there are three methods available to

Page 81: Basic Java Handout

explicitly manipulate the file pointer:

1 skipBytes() Moves the file pointer forward the specified number of bytes.

2 seek() Positions the file pointer just before the specified byte.

3 getFilePointer() Returns the current byte location of the file pointer.

Random Access Files and Filters

As with sequential file I/O, we often want to be able to apply filtering to the data when we read and write a file on a random basis. Because RandomAccessFile doesn't inherit from the InputStream or OutputStream classes, you can't apply the same filters to objects of RandomAccessFile that you apply to the sequential streams.

However, because RandomAccessFile implements the DataInput and DataOutput interfaces, you can create a filter that works for either DataInput or DataOutput and it will work on those sequential access files that implement DataInput or DataOutput as well as any RandomAccessFile.

Reader and Writer Classes

The Reader and Writer classes were added to JDK 1.2 to support internationalization.  Briefly, the stream I/O capability that was supported prior to that release didn't support the use of 16-bit Unicode characters.  Rather, only the bottom 8 bits were handled by the streams.

The Reader and Writer classes make it possible to work with character streams rather than byte streams.  To a large extent, these character-stream classes mirror the byte stream classes, so if you know how to use one, it isn't too difficult to figure out how to use the other.  The web is full of discussions regarding the pros and cons of

Page 82: Basic Java Handout

this situation, so we won't discuss it further at this point.  Rather, we simply going to provide a sample program that will show you how to upgrade the previous program named files02.java to cause it to use character streams instead of byte streams.

To understand the differences, you should compare the code in this program with the code in files02.java.

Some of the code in the original program had nothing to do with the difference between byte streams and character streams, so that code was omitted from this version.

A listing of the program follows.  We have highlighted the new and important parts of this version in boldface to make it easier for you to compare this version with the original version.

/* File files04.java This program is an upgrade to the program namedfiles02.  The purpose is to convert the original programthat used byte streams for input and output to one thatuses unicode character streams for input and output.

To understand the differences, you should compare thecode in this program with the code in files02.java.

Some of the code in the original program had nothing to

Page 83: Basic Java Handout

do with the difference between byte streams and characterstreams, so that code was omitted from this version.

The output from the program is:

Start the program and write a fileRead and print the fileDickBaldwinEnd of program

The program was tested using JDK 1.1.6 under Win95.**********************************************************/

import java.io.*;

class files04{  public static void main(String[] args)  {    System.out.println(                    "Start the program and write a file");    try{      //Open an output character stream using the Writer      // classes.      PrintWriter dataOut =          new PrintWriter(new

Page 84: Basic Java Handout

FileWriter("junk.txt"),true);

      dataOut.println("Dick");      dataOut.println("Baldwin");        dataOut.close();

      System.out.println("Read and print the file");      //Open an input character stream using the Reader      // classes.      BufferedReader inData =            new BufferedReader(new FileReader("junk.txt"));

      String data; //temp holding area      while( (data = inData.readLine()) != null)        System.out.println(data);      inData.close();    }catch(IOException e){}    System.out.println("End of program");  }// end main}//end class files04 definition

Hopefully, this sample program will provide you with enough information to be able to convert your thinking and your programs from byte streams to character streams.

Event Handling in JDK    The Event Class

Introduction

Page 85: Basic Java Handout

Many Java books intermingle their discussion of events with detailed discussions of other aspects of the user interface making it difficult to filter out and understand events and event handling in their own right. The handling of events in Java is a significant technology issue, almost completely independent of other aspects of the user interface.

What is an Event

Windows' Response to User Activity

When a computer is running under Windows, the Windows program or operating system (whichever you prefer to call it) is constantly monitoring the activities of the user. (The same is also true of other operating systems which support a Graphical User Interface).

The user may be moving the mouse, pressing a mouse button, pressing keys on the keyboard, touching a touch-screen, etc. As the user performs these actions, the operating system (OS) responds by sending a stream of messages to the applications that are running. These messages contain information about the actions of the user to which the application might need to respond.

In other words, if the user clicks the mouse on a button, this will result in the OS sending a message to the program. The Calvert book describes how to interpret these messages and cause the program to provide an appropriate response.

Where Does Java Fit In

When we write and execute a Java application or applet, we really aren't executing our program at the level described by Calvert.

Rather, the Java runtime system is a program running at

Page 86: Basic Java Handout

that level.

For example, we could execute a Java application by entering the following command at the operating system prompt:

1 java MyProgram MyOptionalCommandLineArgument

As you can see, the program that we are actually executing is a program named java. This causes the Java runtime system to begin execution.

Our Java application is simply a command-line argument to that program.

The first command-line argument (the name of a Java class file) is passed to the program named java.

Additional command-line arguments (if any) are passed to the Java application.

The Java runtime system causes our Java application to execute under its direct control.

Similarly, when we execute an applet, there is already a program being executed which we commonly refer to an a browser. Applets execute under control of the browser.

During the remainder of this lesson, when we refer to the Java runtime system, we will be referring to either the program executed by invoking "java" at the command line, or that portion of the browser which controls the execution of Java applets, whichever is appropriate to the discussion at hand.

One of the beneficial results of this scheme is that it makes event programming a lot easier for the Java programmer than might otherwise be the case.

Page 87: Basic Java Handout

In particular, whenever there is user activity, the OS continues to send the stream of complex messages mentioned earlier in response to that activity. However, those messages are not sent directly to our Java application or applet. Instead, they are sent to the Java runtime system which performs some significant preprocessing on our behalf.

Encapsulating User Activities into Event Objects

The primary preprocessing performed by the Java runtime system is

1 to interpret and collect the information in the messages, and

2 encapsulate it into objects of the Event class.

The Event class is contained in the java.awt package. This is such an important class that we are going to study it in detail, using information taken from the Java API documents from JavaSoft.

The Event Class

The API describes the Event class as follows:

1 "Event is a platform-independent class that encapsulates user events from the local Graphical User Interface (GUI) platform."

We have tended to use the terminology "user activity" rather than "user events" to keep from having too many interpretations of the word event floating around.

In other words, this class is used to encapsulate the many messages generated by the operating system into objects which our Java applications and applets can more-easily handle.

Page 88: Basic Java Handout

Event Extends Object

The Event class begins with the following declaration:

1 public class java.awt.Event extends java.lang.Object

Thus, the Event class inherits directly from Object, which as you know, is the highest level in the Java class hierarchy.

The declaration for the Event class can be separated into the following parts:

1 Fields, instance variables, data members, (or whatever you choose to call them)

2 Constants for use with the id field

3 Constants for use with the key field

4 Constants for use with the modifiers field

5 Constructors

6 Methods

We will discuss each of these parts of the Event declaration separately.

Fields

The following fields or instance variables are declared in the Event class:     public Object arg;    public int clickCount;    public Event evt;    public int id;    public int key;    public int modifiers;    public Object target;    public long when;    public int x; 

Page 89: Basic Java Handout

    public int y;An understanding of these fields will be very important for the following reason:

Whenever the user engages in some activity, the operating system will send a message to the Java runtime system which will encapsulate the information regarding that activity into an object of type Event and make that object available to our program (we will discuss shortly how it is made available).

It will be the responsibility of our program to interpret that information and respond in an appropriate way with the user.

Again, the following information regarding the fields was taken from the Java API Documentation.

1 arg: An arbitrary argument of the event. The value of this field depends on the type of event.

2 clickCount: For MOUSE_DOWN events, this field indicates the number of consecutive clicks. For other events, it is zero.

3 evt: The next event. This field is set when putting events into a linked list.

4 id:The type of the event.

5 key: The key that was pressed in a keyboard event.

6 modifiers: The state of the modifier keys.

7 target: The target component. This indicates the component over which the event occurred or with which the event is associated.

8 when: The time stamp of the event.

Page 90: Basic Java Handout

9 x: The x coordinate of the event.

10 y: The y coordinate of the event.

Most of these fields are generally self-explanatory (with the possible exception of arg, evt, and target).

Some of the information in the fields, such as id, key, and modifiers, is encoded as a series of integer values.

It isn't necessary for us to know the actual numeric value to use the information, although those values are available in the API Documentation.

A symbolic constant has been defined in the class definition for each of the possible values for these fields. If we prefer, we can write code using the symbolic constants rather than the actual numeric values.

The x and y coordinate information fields describe the coordinates of the mouse, or other pointing device, when the event occurred.

The target field contains a reference to the object that generated the event. In other words, it will be the name of the reference variable by which your program identifies that object. This will become clearer later when we actually see the target field in use in a sample program.

The arg field is an object of type Object and can contain a variety of different kinds of information, "depending on the type of event."

To learn more about the makeup of this object for any particular event, you will need to examine the specifications for the actual component involved in the event. This information can be found in the API Documentation under the java.AWT.Component class.

Page 91: Basic Java Handout

For example, according to the API Documentation, if the component involved in the event is an object of the Button class, "its object is the string label of the button."

In other words, if a button is involved in an event, the label appearing on the button will be encapsulated as a string in the arg field of the Event object that is created by the Java runtime system.

Since this instance variable is of type Object, your program will need to downcast it to the proper type before using it. The program can then use the information for whatever purpose it might be needed.

Page 92: Basic Java Handout

Preview of Event Handling

A subsequent lesson will deal with event handling in detail. However, at this point, we need to provide an overview to tie all of this together. We will discuss this overview now and then resume our discussion of the parts of Event class declaration.

When programming in a GUI system, all meaningful user activity is associated with some object which appears on some sort of visual display. (In this lesson, we will tend to limit our discussion to Windows-like systems. No Newtons yet please.)

There are at least two ways that user activity can become associated with an object in a typical system:

1 Point to an object and do something.

2 Do something at the keyboard while an object has the focus.

Most of you are already familiar with these types of user activities, although you may never have stopped to analyze what you were doing.

The first way to associate an object with a user activity is straightforward. Typically, it involves pointing to the object with a pointing device (such as a mouse) and then signaling an action, such as pressing a button on the mouse, selecting a string in a list, selecting a menu item, etc.

The second way to associate an object with a user activity is a little more indirect, and might require some additional explanation.

In a GUI system, one object on the display device (and only one object) has the focus at any given time. This is

Page 93: Basic Java Handout

usually visually obvious. The object will be of a different color, have a halo, be blinking, or something to set it apart from the remaining objects on the display.

For example in a Windows system, when a text-entry object has the focus, it contains a blinking I-beam cursor. When it doesn't have the focus, it does not have such a cursor.

There are usually a variety of ways to cause an object to have the focus. Probably the most common are to click on the object with the mouse, or to use the tab key to cycle the focus through a series of objects until it reaches the desired object.

When an object "has the focus", that is the only object that will accept keyboard input. Therefore, causing an object to have the focus is preparatory to associating keyboard activity with that object.

Simply pointing to an object with the mouse and clicking on it is often all that is required to associate mouse activity with an object.

Back then to our original premise, when programming in a GUI system, all meaningful user activity is associated with some object.

Page 94: Basic Java Handout

The Component Class

Now let's get more specific. When programming in Java, all such objects are instances of classes which inherit directly or indirectly from the Component class.

The Component class has many methods, all of which are available to objects of classes derived from Component. The particular method of interest to us right now is a method named handleEvent().

This is where we finally learn how it all fits together.

1 The user engages in some meaningful activity.

2 The OS sends a message to the Java runtime system containing information about that activity.

3 The Java runtime system encapsulates that information in an object of type Event.

And the next step is, (and this is an absolutely critical step in your understanding of how it all fits together)

1 The runtime system makes a call to the handleEvent()method of the object associated with the user activity, passing the Event object as a parameter.

At that point, the handleEvent() method can do one of three things:

1 Deal with the event in its entirety leaving nothing more to be done.

2 Deal with the event on some sort of partial basis leaving additional work to be done.

3 Not deal with the event at all.

In the first case, when the needs of the event resulting from the user activity have been completely taken care

Page 95: Basic Java Handout

of, handleEvent() should return true as a signal to the runtime system that nothing further is required.

In the second and third cases, handleEvent() should return false as a signal to the runtime system that additional work is required.

In this latter case, the runtime system identifies the object, if any, which contains the original object associated with the event. (Later when we study the construction of the GUI, you will learn how one object can be contained within another object.)

If such a container object can be identified, the runtime system calls the handleEvent() method of the container object to see if it wants to deal with the event.. The handleEvent() method of the container can respond in the same three ways.

This process continues until either the event is taken care of, or there are no more containers in the hierarchy.

At that point, the runtime system executes some form on default behavior relative to the event which probably means ignoring it completely.

You are all familiar with the fact that you can sometimes click on an object in a GUI and your click will be completely ignored. (Try clicking on a label object sometime.) Your click is ignored because the programmer elected not to have the program respond to that particular user activity.

Hopefully, this will help you to tie it all together in your mind.

This has been a very cursory overview of event handling in Java. In a subsequent lesson, we will discuss event

Page 96: Basic Java Handout

handling in detail and learn about many different types of events, and what it really means to handle an event.

In the meantime, let's resume our study of the Event class, from which the objects are instantiated that make the whole thing possible.

Constructors

Our next step on the road to understanding objects of the Event class is to look at the available constructors. There are three overloaded constructors for the Event class as shown below:

    public Event(Object  target, int  id, Object  arg);    public Event(Object  target, long  when, int id,                int  x, int  y, int  key, int  modifiers);    public Event(Object  target, long  when, int id,               int  x, int  y, int  key,              int  modifiers, Object  arg);

The availability of these constructors suggests some interesting possibilities.

Recall that in the earlier discussion, We said that the Java runtime system responds to a message from the OS by creating an object of type Event and passing it as a parameter to the method named handleEvent() for the object associated with the event.

So far, We haven't said anything about you writing code that instantiates objects of type Event. However, since the constructors exist and are accessible, there is nothing to stop you from doing so.

Access to the constructors suggests that the code in a java application has the capability to instantiate and

Page 97: Basic Java Handout

dispatch objects of type Event just as though they were instantiated by the runtime system in response to user activity.

We already know enough to be able to instantiate an an object of type Event, because we understand (or can figure out) how to provide the necessary arguments for the constructors shown above.

We don't know yet how to dispatch the object, but we will learn how to do that later.

Then we can create some really cool effects. (The potential for practical jokes is almost endless for programs that appear to have a mind of their own insofar as the GUI is concerned.)

1 As another aside, have you ever tried switching the hourglass cursor with the pointer cursor in a program and then observing others trying to use the program, even when they know that the cursors have been switched. That experiment will clearly demonstrate the power of visual icons as a communication medium.

Methods

That brings us to the last section in the declaration of the Event class: methods.

The Event class provides six methods as listed below. Therefore, objects of the class have these instance methods in addition to methods that they inherit from the Object class.

    public boolean controlDown();      public boolean metaDown();      protected String paramString(); 

Page 98: Basic Java Handout

    public boolean shiftDown();    public String toString();     public void translate(int  dX, int  dY);

Methods for modifier Keys

Three of these methods have to do with the modifier keys

1 control

2 shift

3 meta

but as mentioned earlier, the Alt key is not included.

If you use the Event object to invoke these methods, the boolean return value will tell you if the corresponding modifier key was being held down when the event occurred. These are convenience methods which make it possible for you to easily determine something that you can also determine using the bitwise and operation described earlier.

The paramString() Method

Here is the official word on this method, straight from the API Documentation:

1 "Returns the parameter string representing this event. This string is useful for debugging."

Although we haven't discussed applets in any detail yet, there is a param tag that can be used in the HTML file that invokes an applet..

Page 99: Basic Java Handout

The translate() Method

The official word on this method (from the API Documentation) is:

public void translate(int dx, int dy) 

     Translates this event so that its x and y position      are increased by dx and dy respectively. 

     Parameters:           dX - the amount to translate the x coordinate           dY - the amount to translate the y coordinateThis method could be useful in any number of situations involving graphics.

The toString() Method

This is a very common method that we have encountered on numerous prior occasions. When this method is invoked on an object of type Event, some information about the object will be returned as a string.

Summary

So there you have it.

The user does something that that may be meaningful to the program.

The OS sends a message to the Java runtime system containing information about the users activity.

The runtime system encapsulates the information in an object of type Event and passes it as a parameter to the handleEvent() method for the object on which the activity was performed or which was associated with the activity.

The handleEvent() method either processes the event and returns true, or doesn't process the event and returns

Page 100: Basic Java Handout

false.

If the handleEvent() method returns false, the runtime system attempts to invoke the same method on the object which contains (is the parent of) the original object.

This process continues until the event is either handled within the Java program, or given back to the runtime system for default handling.

Along the way, if the Java program decides to process the event, there are a number of symbolic constants and several methods that can be used to interpret the information encapsulated in the object.

Some, but probably not all of the information encapsulated in the object is likely to be used in the processing of the event.

Not all of the fields in the Event object are germane to every type of event. For example, when the user clicks on an "OK" button, the x and y coordinates of the mouse pointer are usually not of great importance.

The AWT Package, An Overview

Introduction

This lesson is primarily a preview of what you can expect to find in several lessons immediately following this one. This and the next several lessons concentrate on the package java.awt where most of the functionality exists for providing the user interface to your application or applet.

1 Note that it was the AWT portion of Java that experienced the most significant changes in the release of the Java Development Kit, version 1.1.

Page 101: Basic Java Handout

Much of what you may have learned earlier about version 1.0 was replaced using new concepts. These lessons will concentrate on the use of JDK 1.1 rather than JDK 1.0.

The user interface of a modern computer program involves techniques to activate many of the human senses. We use icons, text boxes, images, sound, boardroom graphics, etc.

This and the next several lessons will concentrate on those aspects of the interface that we commonly refer to as the Graphical User Interface (GUI). We will leave other aspects of the interface, such as sound, to be covered in subsequent lessons.

Many of the sample programs in the earlier lessons on event handling made use of simple GUI forms without providing much of an explanation as to what was going on. The next few lessons will attempt to rectify that situation by explaining many aspects of creating a Graphical User Interface.

Package java.awt Classes

As mentioned above, much of the material in this and the next several lessons will be based on the classes of the package java.awt.

There were more than fifty classes defined in package java.awt. Of that total, we will be mainly concerned with the ones discussed in the following sections. The classes are grouped in the general order that we will be studying them and each grouping will usually be presented as a separate lesson. However, some groups are so large that it may be necessary to break the group up into more than one lesson.

We will also be making heavy use of the classes in the

Page 102: Basic Java Handout

java.awt.event package, but you are already familiar with most of those classes from your study of the previous lessons on event handling in JDK 1.1.

Arranging Components in Containers

We can place our components in their containers using absolute position coordinates, or we can use any of several different layout managers to do the job. Using layout managers is considered by many to be the safer approach because this approach tends to automatically compensate for differences in screen resolution between platforms.

The different layout managers are defined in classes having the following names:

1 BorderLayout

2 CardLayout

3 FlowLayout

4 GridBagLayout

5 GridBagConstraints

6 GridLayout

In addition to the layout manager classes, there is a class named GridBagConstraints that is used to work with the GridBagLayout class as well as a class named Insets that is used to work with other classes.

The Container Classes

The following hierarchy diagram shows where the container classes Panel, Window, and Frame fit into the overall inheritance hierarchy. We will discuss these three classes as a group, and also discuss their relationship with their superclasses: Container, Component, and Object.

Page 103: Basic Java Handout

  java.lang.Object    |    +----java.awt.Component            |            +----java.awt.Container                   |                   +----java.awt.Panel                    |                    +----java.awt.Window                            |                            +----java.awt.FrameGenerally, these classes are used to contain components or instances of other classes.

The Non-Text Input Components

The components in the next group are generally used to allow the user to input (non-text) information to the program, although in some circumstances they could also be used to output information to the user as well. Non-text in this context means that the user can input information without the requirement to use the keys on the keyboard.

All of these classes extend the class Component.

1 Button

2 Checkbox

3 Choice

Page 104: Basic Java Handout

4 List

The class named CheckboxGroup does not extend Component, but extends Object instead. As the name suggests, objects of this class can be used to group Checkbox components so that they behave in a mutually exclusive fashion.

The AWT Package, Placing Components in Containers, Absolute Coordinates

Introduction

This is one in a series of lessons that concentrates on the package java.awt which contains most of the functionality for providing the user interface to your Java application or applet.

We can place components in containers using absolute position and size coordinates, or we can use any of several different layout managers to do the job.

Using layout managers is considered by many to be the safer approach because this approach is designed to automatically compensate for differences in screen resolution and component size/shape between platforms.

The different layout managers are defined in classes having the following names:

1 BorderLayout

2 CardLayout

3 FlowLayout

4 GridLayout

5 GridBagLayout

In addition to the layout manager classes, there is a class

Page 105: Basic Java Handout

named GridBagConstraints that is used to work with the GridBagLayout class as well as a class named Insets that is used to work with other layout manager classes.

In addition to using the standard layout manager classes, we can create our own custom layout manager.

This lesson will discuss the placement of components into a container using absolute coordinates. Subsequent lessons will discuss the other possibilities listed above.

Absolute Positioning and Size

The Component class of JDK 1.1 provides the methods setBounds(int,int,int,int) and setBounds(Rectangle) that allow you to specify the location and size of a component in absolute coordinates measured in pixels.

A description of these two methods, as extracted from the JDK 1.1.3 documentation follows:  

 public void setBounds(int x,                       int y,                       int width,                       int height)

Moves and resizes this component. The new location of the top-left  corner is specified by x and y, and the new size is specified  by width and height.  Parameters:  x - The new x-coordinate of this component.  y - The new y-coordinate of this component.  width - The new width of this component. 

Page 106: Basic Java Handout

height - The new height of this component. 

.

 public void setBounds(Rectangle r)Moves and resizes this component to conform to the new bounding  rectangle r. This component's new position is specified  by r.x and r.y, and its new size is specified by r.width and r.height  Parameters:  r - The new bounding rectangle for this component. 

As you can see from the above, the location and size of the component are specified by the location and size of a bounding rectangle that can in turn be specified by four integer parameters, or can be specified as an object of class Rectangle..

Many authors will tell you that specifying the location and size of your components in absolute coordinates will make it more difficult to achieve satisfactory results on a variety of platforms and displays. Regardless of that, you probably need to know how to do it, and that is the subject of this lesson.

The following sample program illustrates the positioning and sizing of components on an absolute coordinate basis in JDK 1.1. Note that this program uses several new methods that did not exist in JDK 1.0.

Sample Program

The following application, named Layout01.java places a Button object and a Label object in a Frame object using

Page 107: Basic Java Handout

absolute coordinates in pixels. The program is designed for simplicity and therefore does not contain any event handlers. With no event handlers, the Close button on the Frame object is not operational, so you will have to terminate the program using some other method.

Discussion

The program shows how to use the new methods in JDK 1.1 to set the size and position of components in a Frame object using absolute coordinates.

The program also illustrates some of the potential problems associated with the use of absolute coordinates.

A Button and a yellow Label are placed in a Frame object. Note that the specified location and size of the components may cause the two objects to overlap. This is one of the potential problems with the use of absolute coordinates. Note also that the initial height of the Frame object may clip off the bottom of the Label. Of course, problems of this sort could be avoided, on one platform at least, by careful design.

If the Frame is resized by the user, the Button and the Label remain fixed in size and position. The Frame can be resized to the point where the two components are no longer visible. Hopefully, a user would know not to do that.

Also, the specified size of the Label may not be sufficient to display the entire initial text string placed in the label. Again, this could be avoided, on one platform, through more careful design. Getting it right on one platform, however, doesn't guarantee that it will be right on other platforms as well.

Page 108: Basic Java Handout

The program was tested using JDK 1.1 running under Win95.

Interesting Code Fragments

The following code fragments from the program are particularly interesting.

Create and Size the Button Object

The following two statements       Button myButton = new Button("Button");    myButton.setBounds(new Rectangle(25,50,100,75));

result in the following actions.

1 Create a Button object with the caption "Button"

2 Specify that the button is to be located at x = 25 and y = 50, measured in pixels from the upper left-hand corner of the containing object. Positive y is measured going down the screen. The reference point on the button is the upper left-hand corner of the button.

3 Specify that the button is to be 100 pixels wide and 75 pixels high

Note that at the point in the program where these two statements are executed, the containing object hasn't yet been identified. Thus, setBounds() provides absolute coordinate information for whatever container the Button is eventually placed in.

The setBounds() method is a method of the Component class that is inherited by all subclasses of Component including Button.

Page 109: Basic Java Handout

The method specifies that the component is to be located and sized according to a bounding rectangle whose sides are parallel to the x and y axes.

As shown earlier, there are two overloaded versions of setBounds(). One version allows the location and size of the box to specified directly as four integer parameters (x, y, width, height).

The other version, which is the version used above, requires the location and size of the box to be specified by an object of type Rectangle that is passed as a parameter to the method. This is the most flexible approach because the Rectangle class has about seven different constructors that can be used to create the bounding box.

Create and Size the Label Object

The next interesting code fragment creates a Label component with a yellow background, again using the setBounds() method to specify its location and size. This code places the upper left-hand corner of the Label object at a coordinate position of 100 by 100 pixels, and causes its width to be 100 pixels and its height to be 75 pixels.      Label myLabel = new Label(                      " ");    myLabel.setBounds(new Rectangle(100,100,100,75));    myLabel.setBackground(Color.yellow);

Page 110: Basic Java Handout

The setBackground(Color c) method is also a method of the Component class that is inherited by subclasses of Component. This method requires an object of the Color class as a parameter. There are many different ways to create the Color object, the simplest of which is simply to refer to one of the class constants that are defined in the Color class using syntax such as   Public final static Color yellowRecall that variables declared as static in a class can be accessed using the name of the class and the name of the variable. Making the variable final causes it to be a constant.

About thirteen different colors can be specified in this way. If you need a color not included in this list, you can use one of the overloaded constructors to specify your color using specified contributions of red, green, and blue. The Color class provides many different methods for dealing with colors.

Create the Frame Object

The next interesting code fragment creates a Frame object with the title "                                  " Frame is the type of object that users of the Windows operating system would probably consider to be a typical "Window". It is resizable, has a minimize button, a maximize button, a control box button, and a close button. The default layout for a frame is BorderLayout which we will be studying later.

    Frame myFrame = new Frame(

Page 111: Basic Java Handout

                     " ");    myFrame.setLayout(null);

In this particular example, we don't want to accept the default layout. Rather, we want to be able to specify the location and size of our components in absolute coordinates . Therefore, we will override the default layout with a specification of a null layout as a parameter to the setLayout() method.

The setLayout() method is a method of the Container class, of which the Frame class is a subclass. The setLayout() method requires an object of the LayoutManager class or null (indicating no layout manager) as a parameter.

Add the Components to the Frame

The next interesting code fragment causes the two previously defined components to become part of the composite visual object through use of the add() method of the class Container. This method is inherited by the Frame class which is a subclass of Container.

As of 3/6/97, there are five overloaded versions of the add() method. We are using the version that requires an object of type Component as a parameter. Since our Button and Label objects are subclasses of the Component class, they qualify as parameters allowing us to use the following code:

    myFrame.add(myButton);    myFrame.add(

Page 112: Basic Java Handout

myLabel);

Size the Frame and Make It Visible

Once we reach this point, all that is left to cause our GUI to appear on the screen at program startup is to establish the size of the Frame object in pixels, and to make it visible. We accomplish this with the following two statements:       myFrame.setSize(250,150);    myFrame.setVisible(true);

A complete listing of the program is provided in the next section.

Program Listing

The complete listing of the program with additional comments follows.   /*File Layout01.java                                                10/27/97 to improve the layout on the page.

This program is designed to be compiled and run under JDK 1.1

The program shows how to use the new methods in JDK 1.1 to set the size and position of components in a Frame object using absolute coordinates.

Page 113: Basic Java Handout

The program also illustrates some of the problems associated with the use of absolute coordinates.

A button and a yellow label are placed in a Frame object.  Note that the two objects may overlap, and that the initialheight of the Frame object may clip off the bottom of the Label.

Note also that if the Frame is resized by the user, the Button and the Label remain fixed in size and position.  The Frame can be resized to the point where the two components are no longer visible.

Note also that the specified size of the Label may not besufficient to display all of the initial text placed in thelabel.

For simplicity, no event handler is provided for the Buttonand no event handler is provided for the "Close" button on the Frame. Therefore, it is necessary to terminate the program using some other method.

Page 114: Basic Java Handout

The program was tested using JDK 1.1.3 running under Win95.*///=======================================================//

import java.awt.*;import java.awt.event.*;//=======================================================//public class Layout01 {  public static void main(String[] args){    //instantiate a Graphical User Interface object    GUI gui = new GUI();  }//end main}//end class Layout01//=======================================================//

//The following class is used to instantiate a graphical // user interface object.class GUI {  public GUI(){//constructor    //Create a Button object with the specified caption and    // the specified size and location within its container    // (in pixels).    Button myButton = new Button("Button");    //Arguments are x,y,width,height

Page 115: Basic Java Handout

    myButton.setBounds(new Rectangle(25,50,100,75));        //Create a Label object with the specified initial text    // and the specified size and location within its     // container (in pixels).  Make it yellow so that its     // outline will be visible.        Label myLabel = new Label(                            "                                  ");    //Arguments are x,y,width,height    myLabel.setBounds(new Rectangle(100,100,100,75));        myLabel.setBackground(Color.yellow);

    //Create a Frame object with the specified title, and     // with no layout manager so that size and location of     // components shown above will be effective.    Frame myFrame = new Frame(                            "                                  ");    //Note the following null argument.    myFrame.setLayout(null);

    //Add the two components to the Frame, set its size in    // pixels, and make it visible.        myFrame.add(myButton);    myFrame.add(myLabel);    myFrame.setSize(250,150);    myFrame.setVisible(true);  }//end constructor}//end class GUI definition

Page 116: Basic Java Handout

//=======================================================//

The AWT Package, The Container, Panel, Window, and Frame Classes

Introduction

This series of lessons is concentrating on package java.awt where most of the functionality exists for providing the user interface to your application or applet.

We have learned how to handle events in both JDK 1.0.2 and JDK 1.1. We have learned how to use the layout managers in JDK 1.1. These two topics form the basis for the design and implementation of a Graphical User Interface.

The next step is to take a look at the variety of components that are available to combine with layout and event handling to produce an effective Graphical User Interface.

The available components are defined by classes in the package java.awt. Our approach will be to group those classes into categories and study the material on a category basis. As of this writing, it looks as if the categories will be:

1 The Container Classes

2 The Non-Text Input Classes

3 Text Input and Output Classes

4 The Scrollbar Classes

5 The Dialog Class

Page 117: Basic Java Handout

6 The Canvas Class

7 Menus

8 Graphics - Shapes, Fonts, Images

9 The PrintJob Class

10 The Toolkit Class

This lesson will concentrate on the Container classes.

Arranging Components in Containers

We have learned that we can place our components in their containers using absolute position coordinates, or we can use any of several different layout managers to do the job. Using layout managers is considered by many to be the safer approach because this approach tends to automatically compensate for differences in screen resolution and component appearance between platforms.

In our previous studies of layout managers, we made extensive use of Container classes. However, since our emphasis was on layout, we simply took the containers for granted and didn't provide much in the way of discussion relative to the containers themselves.

We will rectify that situation in this lesson and learn more about the Container classes.

The Container Classes

The following hierarchy diagram shows where the Container classes Panel, Window, and Frame fit into the overall inheritance hierarchy. We will discuss these three classes as a group, and also discuss their relationship with their superclasses Container, Component, and Object. java.lang.Object 

Page 118: Basic Java Handout

   |    +----java.awt.Component            |            +----java.awt.Container                   |                   +----java.awt.Panel                    |                    +----java.awt.Window                            |                            +----java.awt.FrameGenerally, the Container classes are used to contain components or instances of other classes.

The Container Class

As indicated in the hierarchy diagram above, the Container class extends the Component class, which in turn extends the Object class. We will discuss these three starting with the Object class and working our way down to the Container class.

The Object Class

We have discussed the Object class and the Component class in previous lessons. The Object class is a member of the java.lang package, and is the root of the class hierarchy. Every class has Object as a superclass.

All objects, including arrays, implement the methods of the Object class. In keeping with the general concepts of inheritance in Object-Oriented Programming, the methods provided by the Object class are general-purpose in nature.

Page 119: Basic Java Handout

The Component Class

The Component class extends the Object class, and is the superclass of many of the classes used to produce Graphical User Interfaces.

Component has no public constructors so it cannot be instantiated. However, it can be extended which provides a new capability of JDK 1.1 known as Lightweight Components which will be the topic of a subsequent lesson.

The Container Class

The Container class extends Component. As with Component, there are no public constructors for the class. Therefore, you cannot instantiate objects of the Container class. However, you can extend the class giving rise to Lightweight Components as mentioned earlier.

As we will see, the Panel class, the Window class, and the Frame class are subclasses of Container and inherit the methods defined in Container.

During our studies of layout managers, we saw sample programs which used the add() method of the Container class to place other components into objects subclassed from Container.

According to the JDK 1.1 documentation:

"Components added to a container are tracked in a list. The order of the list will define the components' front-to-back stacking order within the container. If no index is specified when adding a component to a container, it will be added to the end of the list (and hence to the bottom of the stacking order)."

The list of methods includes five overloaded versions of the add() method. During our studies of the layout managers, we learned that the different layout managers

Page 120: Basic Java Handout

require the use of different versions of the add() method for placing components into container objects.

The Container class is also the home of the setLayout() method which is used to specify the layout manager for a particular container and the validate() method which is used to cause changes to a layout to take effect. We have used these two methods in numerous sample programs in previous lessons.

The Panel Class

The Panel class inherits from the Container class and can be used to produce a completely generic container. The constructors are:

1 Panel() -- Creates a new panel with a default FlowLayout manager.

2 Panel(LayoutManager) -- Creates a new panel with the specified layout manager.

The default layout manager for a Panel object is FlowLayout. It is also possible to specify a different layout manger for the object when it is instantiated, and it is possible to accept the default initially and change it later using the setLayout() method.

Panel has one method: addNotify(), which is used to creates the Panel's peer. Briefly, the peer is the platform-dependent manifestation of the platform-independent object.

Normally a panel has no visual manifestation in its own right.. However, it is possible to make a panel visible by setting its background color to something other than the default. The following sample program causes three Panel objects to have background colors of yellow, red, and blue in order to make them visible for purposes of illustration.

Page 121: Basic Java Handout

Sample Program for Panels

This sample program is designed to be compiled and run under JDK 1.1

This program illustrates the use of Panel objects to create a composite top-level Graphical User Interface object. Three Panel objects are added to a Frame object using the add() method.

The layout manager for the Frame object is specified to be FlowLayout using the setLayout() method.

The background colors of the three panels are set to yellow, red, and blue so that they will be visible in the Frame object.

One component is placed on each of the Panel objects using the add() method.

1 A TextField object is placed on the yellow Panel object.

2 A Label object is placed on the red Panel object.

3 A Button object is placed on the blue Panel object.

None of these components are active, meaning that event Listener objects are not instantiated and registered for the components. For example, clicking the button does not result in the processing of an event and nothing happens other than the default visual effect of pressing a button.

If you compile and run this program (and make certain that the Frame is sufficiently wide) you should see three Panel objects lined up across the top of the Frame object. The color of the panels going from left to right should be yellow, red, and blue. The yellow panel should contain a TextField object, the red panel should contain a Label object, and the blue panel should contain a Button object.

Page 122: Basic Java Handout

If the Frame object is not sufficiently wide to accommodate the three panels across the top, they will automatically rearrange themselves in the standard fashion for a FlowLayout manager.

A windowClosing() event listener object is instantiated and registered on the frame to terminate the program when the frame is closed.

The Window Class

As shown in the earlier hierarchy diagram, the Window class extends the Container class. It is a top-level window with no borders and no menubar. The JDK documentation indicates that it could be used, for example, to implement a pop-up menu.

The default layout for a Window object is BorderLayout. Windows are capable of generating the following window events:

1 WindowOpened,

2 WindowClosed.

The definition of the constructor is as follows:

public Window(Frame parent) 

Constructs a new Window initialized to an invisible state. It behaves as a modal dialog in that it will block input to other windows when shown. 

Parameters: parent - the owner of the dialog 

"Window is rarely used directly; its subclasses Frame and Dialog are more commonly useful." -- Java in a Nutshell, by David Flanagan."Generally you won't create Window objects directly.

Page 123: Basic Java Handout

Instead, you will use a subclass of Window called Frame, described next." -- Java, the Complete Reference, by Herbert Schildt and Patrick Naughton."The Window class is a lot like Panel except that it creates its own top-level window, as opposed to being contained by any other Panel. Most users of the Window class will more than likely use the Frame subclass, described below, which has several convenience methods to deal with resizing, window titles, cursors, and menu bars. That said, let's skip ahead to the Frame class." -- The Java Handbook, by Patrick Naughton.

With all that good advice, let's take Mr. Naughton's advice specifically, and skip ahead to the Frame class which is our next topic of discussion.

The Frame Class

Unless you just started reading these lessons at this paragraph, you will not be a stranger to the use of the Frame class.

We particularly like to use the Frame class for sample programs because it is easy to instantiate, and equally important, it is easy to terminate.

The Frame class extends the Window class. A Frame object is an (optionally) resizable top-level window with

1 a title,

2 a minimize box,

3 a maximize box,

4 a close box, and

5 a control box.

Page 124: Basic Java Handout

The default layout for a Frame object is BorderLayout.

Frames are capable of generating the following types of window events:

1 WindowOpened

2 WindowClosing

3 WindowClosed

4 WindowIconified

5 WindowDeiconified

6 WindowActivated

7 WindowDeactivated

The WindowClosing event, highlighted in the earlier program, is the event that we have used to terminate many sample programs. This event occurs whenever the user clicks the close box on the Frame object.

Also, as of that date, it had two overloaded public constructors:

1 Frame() -- Constructs a new Frame that is initially invisible.

2 Frame(String) -- Constructs a new, initially invisible Frame with the specified title.

You will recall that all of our sample programs have used the setVisible(true) method to cause the initially invisible Frame object become visible.

Sample Program for Frame Class

This program is designed to be compiled and run under JDK 1.1

This program illustrates use of the Frame class and some

Page 125: Basic Java Handout

of its methods. The program instantiates a Frame object with three buttons labeled:

1 Get Title

2 Hand Cursor

3 Default Cursor

When the user clicks the Get Title button, the title of the Frame object is retrieved using the getTitle() method of the Frame class and displayed on the screen using a System.out.println statement.

When the user clicks the Hand Cursor button, the shape of the cursor is changed to the familiar hand-shaped cursor using the setCursor() method.

When the user clicks the Default Cursor, the shape of the cursor is changed back to the default cursor for the system.

Note that in the two latter cases, you must move the mouse pointer away from the button to see the change in the cursor take place.

This is an extremely simple program in comparison with other programs already studied in these lessons.

All of the event Listener objects are instantiated and registered on the three Button objects and the "close" box using the abbreviated syntax of Inner Classes. If this looks foreign to you, you might want to go back and review that lesson.

A windowClosing() event listener object is instantiated and registered on the frame to terminate the program when the frame is closed.

The program was tested using JDK 1.1 running under

Page 126: Basic Java Handout

Win95.

Interesting Code Fragments from Sample Program for Frame Class

The following statement is typical of those used to instantiate the Button objects in the program.

Button titleButton = new Button("GetTitle");

The following code is typical of that used to

1 instantiate the Frame object,

2 set the layout manager to FlowLayout, and

3 add the three buttons to the Frame object.

. myFrame = new Frame(" ");myFrame.setLayout(new FlowLayout());

myFrame.add(titleButton);

The following code fragment is typical of that used to instantiate and register ActionListener objects on the three Button objects using the abbreviated syntax for Inner Classes.

titleButton.addActionListener(             new ActionListener(){               public void

Page 127: Basic Java Handout

actionPerformed(ActionEvent e){                 System.out.println(myFrame.getTitle());               }//end actionPerformed()             }//end ActionListener            );//end addActionListener()

The following code was used to instantiate and register a WindowListener object on the Frame object to terminate the program when the user clicks the "close" box on the Frame object.

myFrame.addWindowListener(                new WindowAdapter(){                  public void windowClosing(WindowEvent e){                    System.exit(0);//terminate the program                  }//end windowClosing()                }//end WindowAdapter              );//end addWindowListener.

Program Listing for Sample Program for Frame Class

A complete listing of the program follows:

Page 128: Basic Java Handout

/*File Container02.java                                    This program is designed to be compiled and run under JDK 1.1

This program illustrates use of the Frame class and someof its methods.

The program was tested using JDK 1.1.3 running under Win95.**********************************************************/

import java.awt.*;import java.awt.event.*;import java.util.*;//=======================================================//public class Container02 {  public static void main(String[] args){    //instantiate a Graphical User Interface object    GUI gui = new GUI();  }//end main}//end class Container02//=======================================================//

class GUI {  Frame myFrame;  public GUI(){//constructor

Page 129: Basic Java Handout

    //Instantiate three Button objects with the     // labels shown    Button titleButton = new Button("GetTitle");    Button handCursorButton = new Button("Hand Cursor");    Button defaultCursorButton = new Button(                                         "Default Cursor");        //Instantiate a Frame object with title shown.     // Specify FlowLayout mgr.    myFrame = new Frame("                                  ");    myFrame.setLayout(new FlowLayout());        //Add the three Button objects to the Frame object.    myFrame.add(titleButton);    myFrame.add(handCursorButton);    myFrame.add(defaultCursorButton);        //Set the Frame size and make it visible    myFrame.setSize(250,200);    myFrame.setVisible(true);    

    //Instantiate and register ActionListener objects on    // the three Button objects using the abbreviated     // syntax for Inner Classes.      //---------------------------------------------------//        titleButton.addActionListener(           new ActionListener(){             public void actionPerformed(ActionEvent e){

Page 130: Basic Java Handout

               System.out.println(myFrame.getTitle());             }//end actionPerformed()           }//end ActionListener         );//end addActionListener()    //---------------------------------------------------//        handCursorButton.addActionListener(           new ActionListener(){             public void actionPerformed(ActionEvent e){               myFrame.setCursor(                           new Cursor(Cursor.HAND_CURSOR));             }//end actionPerformed()           }//end ActionListener         );//end addActionListener()    //---------------------------------------------------//        defaultCursorButton.addActionListener(           new ActionListener(){             public void actionPerformed(ActionEvent e){               myFrame.setCursor(                        new Cursor(Cursor.DEFAULT_CURSOR));             }//end actionPerformed()           }//end ActionListener         );//end addActionListener()    //---------------------------------------------------//

    //Instantiate and register a WindowListener object     // on the Frame object to terminate the program when

Page 131: Basic Java Handout

    // the user clicks the "close" box on the Frame object.    myFrame.addWindowListener(           new WindowAdapter(){             public void windowClosing(WindowEvent e){               System.exit(0);//terminate the program             }//end windowClosing()           }//end WindowAdapter         );//end addWindowListener

  }//end constructor}//end class GUI definition

Event Handling in JDK , A First Look, Delegation Event Model

Introduction

There are many significant changes between JDK 1.0.2 and JDK 1.1. Perhaps the area of greatest change is in the event handling model. The old model has been completely replaced by a new model. There is little or no resemblance between the Delegation Model used in JDK 1.1 and the Inheritance Model used in JDK 1.0.2.

This lesson will provide a description of the new model along with sample programs that illustrate some aspects of the new model.

Subsequent lessons will deal with the new model in more detail, providing more complex sample programs.

In this and the following sections, we will describe how the new model maps to the AWT API. No attempt will be made to discuss the rationale for the change. You are referred to the JavaSoft site for discussions of that sort.

Page 132: Basic Java Handout

Please note that much of this information was taken from the documentation released with the various versions of JDK 1.1, and is the intellectual property of Sun Microsystems.

The material is being reproduced here for the sole purpose of assisting students in learning how to use the new event model.

A Quick Review of the 1.0 Event Model

The model for event processing in version 1.0 of the AWT is based on inheritance. In order for a program to catch and process GUI events, it must subclass GUI components and override either action() or handleEvent() methods.

Returning "true" from one of these methods consumes the event so it is not processed further. Otherwise the event is propagated sequentially up the GUI hierarchy until either it is consumed or the root of the hierarchy is reached. The result of this model is that programs have essentially two choices for structuring their event-handling code:

1 Each individual component can be subclassed to specifically handle its target events.

2 All events for an entire hierarchy (or subset thereof) can be handled by a particular container.

Although we indicated above that we would not discuss the rationale for making the change, there is one aspect of the change that is so compelling as to merit discussion here.

In the inheritance model from version 1.0, there is no filtering of events. Events are always delivered to components regardless of whether the components

Page 133: Basic Java Handout

actually handle them or not. This is a general performance problem, particularly with high-frequency events such as mouse moves. Sun predicts that all systems should see performance improvement as a result of this change with the most improvement being enjoyed by Solaris systems.

Design Goals of the JDK 1.1 Delegation Model

According to Sun, the primary design goals of the new model in the AWT are the following:  

Simple and easy to learn 

Support a clean separation between application and GUI code 

Facilitate the creation of robust event handling code which is less error-prone (strong compile-time checking) 

Flexible enough to enable varied application models for event flow and propagation 

For visual tool builders, enable run-time discovery of both events that a component generates as well as the events it may observe 

Support backward binary compatibility with the old model 

It will be up to you to decide if they have met their goals.

Simplified Overview of the New Delegation Model

First, we will provide an simplified overview of the new model including a sample program. Following that, we will embark on a detailed discussion of the new model. Hopefully the simplified discussion and the sample

Page 134: Basic Java Handout

program will help you to understand the material in the detailed discussion.

Also, the previous lesson on callbacks should have given you considerable background to help you understand this material. If you are not familiar with the material in those lessons, you should go back and review that material.

Events are now organized into a hierarchy of event classes.

The new model makes use of event sources and event listeners.

An event source is an object that has the ability to determine when an interesting event has occurred, and to notify listener objects of the occurrence of the event. Although you as the programmer establish the framework for such notification, the actual notification takes place automatically behind the scenes.

A listener object is an instance of a class (or instance of a subclass of a class) that implements a specific listener interface. A number of listener interfaces are defined where each interface declares the methods appropriate for a specific class of events. Thus, there is natural pairing of classes of events and interface definitions.

For example, there is a class of mouse events that includes most of the events normally associated with mouse action and there is a matching interface definition which is used to define a listener class for those events (actually this is the one case where two interfaces are defined to match up with a single event class).

A listener object can be registered on a source object to be notified of the occurrence of all events of the specific

Page 135: Basic Java Handout

class for which the listener object is designed.

Once a listener object is registered to be notified of those events, the occurrence of an event defined by the specified class will automatically invoke the matching method in the listener object. The code in the body of the method is designed by the programmer to perform the desired action when the event occurs.

Some event classes (such as the mouse events, for example) involve a number of different possible event types. A listener class which implements the matching interface for that event class must implement or define (provide a body for) all the methods declared in the interface. To prevent this from being burdensome, an intermediate set of classes, known as Adapter classes, is provided.

These Adapter classes implement the listener interfaces, and define the matching interface methods with empty methods. A listener class can then be defined which extends the Adapter class instead of implementing the interface. When this is done, the listener class need only override those methods of interest since the requirement to define all of the interface methods has already been satisfied by the Adapter class.

For example, in the sample program which follows, two different listener objects instantiated from two different listener classes are registered to receive all events involving the manipulation of a Frame object (opening, closing, minimizing, etc.).

One of the listener classes implements the WindowListener interface and hence must define all six methods of that interface.

Page 136: Basic Java Handout

The other listener class extends the WindowAdapter class which in turn implements the WindowListener interface. The WindowAdapter class defines all six methods as empty methods. Thus, this listener class can get by with overriding only two of the six methods of the interface.

Sample Program

This program was designed for simplicity. In this program, the code body in each of the methods is simple. In all cases but one, the code simply displays a message indicating that the method has been invoked. Obviously, in order for a program to be of much value, the body of code in the methods would have to be much more substantive, or at least would have to invoke other methods that are more substantive.

This program illustrates the use of Event Sources, Event Listeners, and Adapters in the Delegation Event Model.

Briefly, this application instantiates an object which creates a user interface consisting of a simple Frame object. This object is an Event Source which notifies two different Event Listener objects of Window events.

One of the Listener objects implements the WindowListener interface and defines all of the methods declared in that interface.

The other Listener object extends the Adapter class named WindowAdapter. As explained earlier, the purpose of Adapter classes (as used in this context) is to implement the Listener interfaces and to define all of the methods with empty methods. (Adapter classes are viewed in a broader context in the advanced lessons on the Reflection API.)

Classes which extend the Adapter classes can then

Page 137: Basic Java Handout

selectively override only those methods of interest. This Listener object overrides only two of the methods.

Note that this application does not terminate and return control to the operating system. You must forcefully terminate it.

This program was tested using JDK 1.1.3 under Win95.

The output produced by running the program is presented later in this lesson.

Interesting Code Fragments

The first interesting code fragment is the main() method of the controlling class which instantiates a Graphical User Interface (GUI) object. There are more compact (and more cryptic) ways to accomplish this objective, but for the time being, in order to achieve clarity, we will use this approach.  public class Event08 {//controlling class  public static void main(String[] args){    GUI gui = new GUI();//instantiate a GUInterface object  }//end main}//end class Event08

The GUI class is rather long, so we will break it up and discuss it in parts.

This class is used

1 to instantiate and display a user interface object,

Page 138: Basic Java Handout

2 to instantiate two Listener objects, and

3 to register those two objects for notification whenever a Window event occurs.

The class begins by defining its own constructor. The first interesting code in the constructor is the code to instantiate an object of type Frame, set its size, and give it a title.   Class GUI{  public GUI(){//constructor    //Create a new Frame object    Frame displayWindow = new Frame();    displayWindow.setSize(300,200);    displayWindow.setTitle("                                  ");

According to the JDK documentation:   A Frame is a top-level window with a title and a border. The default layout for a frame is BorderLayout. (We will learn more about layout managers later) 

Frames are capable of generating the following types of window events: 

WindowOpened 

WindowClosing 

Page 139: Basic Java Handout

WindowClosed 

WindowIconified 

WindowDeiconified 

WindowActivated 

WindowDeactivated. 

Stated differently, a Frame object is the type of GUI object that we might refer to as a window or a form in a typical GUI environment.

Next we will instantiate two Listener objects that will process Window events.

The class definitions, named Wproc1 and Wproc2, for these two classes will follow the discussion of the GUI class.

Note that we are passing a reference to the Frame object to the constructor for one of these classes. There is a better (and more cryptic) way to achieve the same objective without the need to pass the reference. Again, since this program was designed for clarity, we are doing it the obvious way. Another program later in the lesson shows the preferred way.  

    WProc1 winProcCmd1 = new WProc1(displayWindow);    WProc2 winProcCmd2 = new WProc2();

The next code fragment is extremely important. This is the code by which we register the listener objects for notification of Window events where the Frame object named displayWindow is the source of the events.

Page 140: Basic Java Handout

Pay close attention to the syntax of these two statements, because you will be using this syntax often. In subsequent lessons, we will dig deeper into the Delegation Event Model and teach you what is going on behind the scenes when you execute statements of this sort.

    displayWindow.addWindowListener(winProcCmd1);    displayWindow.addWindowListener(winProcCmd2);

The interpretation of this code fragment is that the two listener objects named winProcCmd1 and winProcCmd2 are added to a list of listener objects that are to be automatically notified whenever an event of the WindowEvent class occurs with respect to the Frame object named displayWindow.

These listener objects are notified by invoking the methods in the objects which match the specific type of the event (open window, close window, closing window, minimize window, etc.).

We wrap up the definition of our GUI class with a statement which causes the Frame object to become visible on the screen. Note that this statement also causes the windowActivated and windowOpened events to be generated.

    DisplayWindow.setVisible(true);  }//end

Page 141: Basic Java Handout

constructor}//end GUI class definition

At this point, we have examined the code that will create a Frame object and display it on the screen. Also we have examined the code that registered two Listener objects on the Frame object. However, at this point, the program cannot be compiled because the classes from which the two Listener objects are to be instantiated have not yet been defined. That will be our next assignment.

The code fragments that follow describe the two classes that can be used to instantiate Listener objects.

The first class definition that we will look at implements the WindowListener interface. This requires that all the methods declared in the interface be defined in this class. This class defines all of the methods. Each of the methods displays a descriptive message whenever it is invoked.

We will begin our discussion with the constructor. Note that the constructor for this class requires a reference to the Source object to be passed as a parameter. As mentioned earlier, this is not the preferred way to accomplish our objective, but it is the most straightforward and easy to understand. That is why we elected to use it here. The code in the constructor saves a reference to the Source object in an instance variable named displayWindowRef.

class WProc1 implements WindowListener{  Frame displayWindowRef;    WProc1(Frame

Page 142: Basic Java Handout

windowIn){//constructor    this.displayWindowRef = windowIn;  }//end constructor

It is important to note that this class implements the WindowListener interface. This means that it must define all of the methods that are declared in that interface.

If you examine the complete program listing that is presented later, you will see that there is one method definition in this class definition for each of the methods that are declared in the WindowListener interface.

The definition of all the interface methods are very similar, so We are not going to show them all here. We will show the one that requires the reference to the source object that was discussed above.

This is our definition of the windowClosing() event handler method. As you can see, this method starts out by displaying a message. However, it then invokes the dispose() method on the Frame object, and that is the reason that a reference to the Frame object was required to be passed in as a parameter.

Invoking the dispose() method causes a WindowClosed event to be generated.  

  public void windowClosing(WindowEvent e){    System.out.println("WProc1 windowClosing test msg");    displayWindowRef.dispose();//generate WindowClosed

Page 143: Basic Java Handout

  }//end windowClosing()

The next class does not implement the WindowListener interface, but rather extends the WindowAdapter class instead. Therefore, it can selectively override only those methods of interest.

In this case, only two of the methods of the WindowListener interface are overridden. These overridden methods display a message whenever they are invoked.

class WProc2 extends WindowAdapter{    public void windowIconified(WindowEvent e){    System.out.println(              "******** WProc2 windowIconified test msg");  }//end windowIconified()    public void windowDeiconified(WindowEvent e){    System.out.println(            "******** WProc2 windowDeiconified test msg");  }//end windowDeiconified()

}//end class WProc2

The output from running this program for a variety of user actions is shown below. You should be able to correlate the messages shown in the output with the event handler methods discussed above and the user

Page 144: Basic Java Handout

actions that caused those event handlers to be invoked.

This program was tested using JDK 1.1.3 under Win95.

When executed, this application places a simple empty Frame object on the screen.  

Starting the program produces the following output:WProc1 windowActivated test msgWproc1 windowOpened test msg

Pressing the minimize button on the Frame produces the following output:

WProc1 windowIconified test msg******** WProc2 windowIconified test msgWProc1 windowDeactivated test msg

Restoring the Frame after minimization produces the following output:

WProc1 windowActivated test msg

Page 145: Basic Java Handout

WProc1 windowDeiconified test msg******** WProc2 windowDeiconified test msgWProc1 windowActivated test msg

Closing the Frame by pressing the X-icon in the upper right of the Frame produces the following output.

WProc1 windowClosing test msgWProc1 windowDeactivated test msgWProc1 windowClosed test msg

More Detailed Overview of the Delegation Model

JDK 1.1 encapsulates events in a class hierarchy with the root class named java.util.EventObject.

The propagation of an event from a Source object to a Listener object involves invoking a method on the Listener object and passing an object which contains encapsulated information about the event. Note that each event class may include more than one actual type of event.

A Listener object is an instance of a class that implements a specific EventListener interface extended from the generic java.util.EventListener.

An EventListener interface declares one or more methods

Page 146: Basic Java Handout

which must be defined in the Listener class, and which are invoked by the event source in response to each specific event type handled by the interface.

The invoking of these methods is the mechanism by which the Source notifies the Listener of the occurrence of an event of a specific type.

An Event Source is an object which "originates" or "fires" events by invoking the methods of one or more Listener objects. The Source maintains a list containing a reference to all of the Listener objects that have registered to be notified of events of that class.

The programmer causes Listener objects to be added to this list using add<EventType>Listener method calls.

Placing references to Listener objects on the list is often referred to as registering specific Listeners to receive notification of specific events.

Once the list is populated (Listener objects are registered), the Source object uses that list to notify each Listener of the occurrence of an event of the specified type without further effort on the part of the programmer.

The Event Source is often a GUI component and the Listener is commonly an object of a class which implements the appropriate listener interface, but this is not a requirement. For example we will learn later how to cause a program to generate events without any physical involvement on the part of a user and a GUI component.

The Listener object could also be another AWT component which implements one or more Listener interfaces for the purpose of hooking GUI objects up to each other.

Page 147: Basic Java Handout

Event Hierarchy

As mentioned earlier, events in JDK 1.1 are not represented by a single Event class with numeric identifications as in JDK 1.0.2. Rather, each specific event type is a member of a class of event types and these classes form a hierarchy of event classes.

Since a single event class may be used to represent more than one event type (i.e. MouseEvent represents mouse up, mouse down, mouse drag, mouse move, etc), some event classes may also contain an "id" (unique within that class) which maps to its specific event types.

There are no public fields in the new event classes. Rather the data in the event is encapsulated and available only through the use of appropriate set...() and get...() methods.

The set methods only exist for attributes on an event that can be modified by a listener. If you continue with your studies in Java, you will learn that the set and get methods match a design pattern for Java Beans.

A concrete set of event classes is defined by the AWT. In addition, programmers may define their own event types by subclassing either java.util.EventObject or one of the AWT event classes.

Low-level vs. Semantic Events

The AWT provides two conceptual types of events:  

low-level events 

semantic events. 

Page 148: Basic Java Handout

A low-level event is one which represents a low-level input or window-system occurrence on a visual component on the screen. As of February 1997, JDK 1.1 defined the following low-level event classes: 

java.util.EventObject 

o java.awt.AWTEvent 

java.awt.event.ComponentEvent (component resized, moved,etc.) 

java.awt.event.FocusEvent (component got focus, lost focus) 

java.awt.event.InputEvent 

java.awt.event.KeyEvent (component got key-press, key-release,etc.) 

java.awt.event.MouseEvent (component got mouse-down, mouse-move,etc.) 

java.awt.event.ContainerEvent 

java.awt.event.WindowEvent 

As indicated earlier, some of the event classes encompass several different event types. Generally, there are corresponding Listener interfaces for each of the event classes, and corresponding interface methods for each of the different event types in each event class.

Semantic events are defined at a higher-level to encapsulate the semantics of a user interface

Page 149: Basic Java Handout

component's model. As of February 1997, the semantic event classes defined by the JDK 1.1 version of the AWT were as follows:

java.util.EventObject 

o java.awt.AWTEvent 

java.awt.event.ActionEvent ("do a command") 

java.awt.event.AdjustmentEvent ("value was adjusted") 

java.awt.event.ItemEvent ("item state has changed") 

java.awt.event.TextEvent ("the value of the text object changed") 

The semantic events are not tied to specific screen-based component classes, but may apply across a set of components which implement a similar semantic model. For example, a Button object will fire an "action" event when it is pressed and a List object will fire an "action" event when an item is double-clicked.

Even though the above discussion seems to tie these event classes to user actions on screen components (because that is the norm), you need to remember that there is nothing to prevent you from having your code generate events of these types completely independent of such user actions. For example, you can easily cause an ActionEvent to be generated and attributed to some component whenever a software timer expires. We will learn how to do this sort of thing in subsequent lessons.

Event Listeners

Page 150: Basic Java Handout

An EventListener interface will typically have a separate method for each distinct event type that the event class represents. For example, the FocusEventListener interface defines two methods, focusGained() and focusLost(), one for each event type that the FocusEvent class represents.

As of February 1997, the low-level listener interfaces defined by the JDK 1.1 version of the AWT were as follows:

java.util.EventListener 

o

java.awt.event.ComponentListener 

o

java.awt.event.ContainerListener 

o

java.awt.event.FocusListener 

o

java.awt.event.KeyListener 

o

java.awt.event.MouseListener 

Page 151: Basic Java Handout

o

java.awt.event.MouseMotionListener 

o

java.awt.event.WindowListener 

If you match this up with the previous list of low-level event classes, you will see that there is a listener interface defined for each of the "leaf" classes in the hierarchy of event classes. (In fact, there are two different listener interfaces defined for the MouseEvent class. This will be discussed further at the appropriate point in time.)

The semantic listener interfaces defined by the AWT are as follows:

java.util.EventListener 

o

java.awt.event.ActionListener 

o

java.awt.event.AdjustmentListener 

o

java.awt.event.ItemListener 

Page 152: Basic Java Handout

o

java.awt.event.TextListener 

There is a one-to-one correspondence between semantic listener interfaces and semantic event classes.

Event Sources

All AWT event sources support a multicast model for listeners. This means that multiple listeners can be added and removed from a single source. In other words, notification of the occurrence of the same event can be sent to one or more listener objects.

According to JDK 1.1 documentation,

"The API makes no guarantees about the order in which the events are delivered to a set of registered listeners for a given event on a given source. Additionally, any event which allows its properties to be modified (via setXXX() methods) will be explicitly copied such that each listener receives a replica of the original event. If the order in which events are delivered to listeners is a factor for your program, you should chain the listeners off a single listener which is registered on the source (the fact that the event data is encapsulated in a single object makes propagating the event extremely simple)."

(An example program showing how you might do the type of chaining described above is presented in the Advanced tutorial in the lessons on the Reflection API.)

As before, a distinction is drawn between low-level and semantic events. The source for low-level events will normally be one of the visual component classes (Button,

Page 153: Basic Java Handout

Scrollbar, etc.) because the event is bound to the actual component on the screen (but counterfeit events can be generated).

As of February 1997, JDK 1.1 defined low-level listeners on the following components.  

java.awt.Component 

o

addComponentListener(ComponentListener l) 

o

addFocusListener(FocusListener l) 

o

addKeyListener(KeyListener l) 

o

addMouseListener(MouseListener l) 

o

addMouseMotionListener(MouseMotionListener l) 

java.awt.Container 

o

Page 154: Basic Java Handout

addContainerListener(ContainerListener l) 

java.awt.Dialog 

o

addWindowListener(WindowListener l) 

java.awt.Frame 

o

addWindowListener(WindowListener l) 

It is important to note that to determine all of the specific event types that can be communicated from a source object to a listener object, you must take inheritance into account. For example, as you will see in a sample program later in this lesson, a source object can detect mouse events on a Frame object and notify a MouseListener object of the occurrence of those events even though the above list does not show a MouseListener on a Frame. This is possible because a Frame object indirectly extends the Component class, and MouseListener is defined for the Component class.

  java.awt.Button 

o addActionListener(ActionListener l) 

java.awt.Choice (implements java.awt.ItemSelectable) 

o addItemListener(ItemListener l) 

Page 155: Basic Java Handout

java.awt.Checkbox (implements java.awt.ItemSelectable) 

o addItemListener(ItemListener l) 

java.awt.CheckboxMenuItem (implements java.awt.ItemSelectable) 

o addItemListener(ItemListener l) 

java.awt.List (implements java.awt.ItemSelectable) 

o addActionListener(ActionListener l) 

o addItemListener(ItemListener l) 

java.awt.MenuItem 

o addActionListener(ActionListener l) 

java.awt.Scrollbar (implements java.awt.Adjustable) 

o

addAdjustmentListener(AdjustmentListener l) 

java.awt.TextArea 

o addTextListener(TextListener l) 

java.awt.TextField 

Page 156: Basic Java Handout

o addActionListener(ActionListener l) 

o addTextListener(TextListener l) 

The nature of semantic event types can be inferred by noticing that in some cases, different types of components support the same type of semantic event. For example, four different types of components are identified in the above list that can register and service action events.

A single ActionEvent listener object could be registered to be notified of action events on one or more components of all of these types. Of course, it would then be necessary for the code in that event handler to determine which source was responsible for generating the event.

An important difference between low level events and semantic events has to do with where the classes that define those events plug into the class hierarchy. Low level events plug in further down the class hierarchy and inherit more methods that can be used to process the event object than is the case with semantic events.

Adapters

Many EventListener interfaces are designed to listen to multiple event classes. For example, . the MouseListener listens to mouse-down, mouse-up, mouse-enter, etc. The interface declares a method for each of these subtypes.

When you implement an interface, you are required to define all of the methods that are declared in the interface, even if you define them with empty methods. In some cases, the requirement to define all the methods declared in an interface can be burdensome.

Page 157: Basic Java Handout

For this reason (and possibly for some other reasons as well), the AWT provides a set of abstract adapter classes which match up with the defined interfaces. Each adapter class implements one interface and defines all of the methods declared by that interface as empty methods, thus satisfying the requirement to define all of the methods.

You can then define your listener classes by extending the adapter classes instead of implementing the listener interfaces.. This allows you the freedom to override only those methods of the interface which interest you.

Again, recall that the methods declared within an interface correspond to the individual event types contained within a corresponding event class, and the Source object notifies your Listener object of the occurrence of an event of a specific type by invoking your interface method.

The Adapter classes provided by the JDK 1.1 version of the AWT were as follows:  

java.awt.event.ComponentAdapter 

java.awt.event.FocusAdapter 

java.awt.event.Key

Page 158: Basic Java Handout

Adapter 

java.awt.event.MouseAdapter 

java.awt.event.MouseMotionAdapter 

java.awt.event.WindowAdapter 

Filtering for Performance

Since listeners are registered to handle specific event types, they are notified only of the occurrence of those event types and are not required to deal with event types for which they are not registered. That was not the case in JDK 1.0.2 where all events passed through a common set of event handler code whether those events were of interest or not.

This filtering of events should improve performance, especially with high frequency events, such as mouse-moves.

According to the JDK 1.1 documentation,

"All platforms should see some performance improvement from reduced event traffic, but the Solaris implementation should gain exceptional improvement since it's a network-based window system." 

Page 159: Basic Java Handout

Another Sample Program

The previous program did not terminate when the user closed the window. The following program does terminate when the user closes the window by executing a System.exit(0) statement in the closing event handler..

The previous program implemented an Event Source object which notified two different Listener objects of the occurrence of an event in the Window class.

The following program implements an Event Source object which notifies one Listener object of the occurrence of an event in the Window class and notifies another Listener object of the occurrence of an event in the Mouse class.

As mentioned earlier, this program implements a MouseListener interface on a Frame object, which is possible because the Frame class indirectly extends the Component class, and addMouseListener() is defined on the Component class.

If you compile and execute this program, whenever you click the mouse inside the Frame, you should see the coordinates of the mouse pointer displayed above the mouse pointer.

Event09 Interesting Code Fragments

The first interesting code fragment is the definition of the controlling class. The main() method for this class instantiates a GUI object where all the real work is done.

  public class Event09 {  public static void main(String[] args){    GUI gui = new

Page 160: Basic Java Handout

GUI();//instantiate a GUI  }//end main}//end class Event09

Early in the Introductory course, in the lesson that introduced Applets, we discussed the relationship between the paint() method and the repaint() method. If you have forgotten that discussion, you will need to go back and review it.

In this program, we are going to override the paint() method to make it possible for us to draw coordinate information on the screen. We also discussed drawing on the screen in the lesson on Applets, so you might need to refer back to that also. (We will have a lot more to say about drawing on the screen when we get into graphics later.)

In order to override the paint() method, we need to extend the Frame class to produce our own version of the Frame class where we have the ability to override the paint() method. The following code fragment extends Frame into MyFrame and overrides the paint() method.  

class MyFrame extends Frame{  int clickX;  int clickY;    public void paint(Graphics g){    g.drawString(             "" + clickX + ", " + clickY, clickX, clickY);  }//end paint()

Page 161: Basic Java Handout

}//end class MyFrame

For future reference, note that this class contains a couple of instance variables that will be used to store X and Y coordinate information.

The overridden version of the paint() method causes the coordinate values stored in clickX and clickY to be displayed in the client area of the Frame object at the location specified by the values of those two instance variables.

If you review the particulars of the drawString() method, you will see that it needs three parameters. The first parameter is the string to draw on the screen. The next two parameters are the coordinate values in pixels where the string is to be drawn.

As is normally the case, coordinate values are specified relative to the upper left-hand corner of the object being drawn on. The above overridden version of the drawString() method converts the coordinate values to a string, and draws that string at the location specified by the coordinate values.

As before, the GUI class is rather long. Therefore, we will break it up and discuss it in sections.

The first fragment that we will discuss is the constructor. The important thing to note here is that we are not instantiating an object of type Frame. Rather, we are instantiating an object of type MyFrame which is our extended version of Frame.

Other than that, this is pretty standard stuff by now.

class GUI {  public

Page 162: Basic Java Handout

GUI(){//constructor    //Create a new Frame object, set size, title, etc.    MyFrame displayWindow = new MyFrame();    displayWindow.setSize(300,300);    displayWindow.setTitle(" ");    displayWindow.setVisible(true);

The next code fragment uses standard syntax to instantiate and register two different Listener objects on the MyFrame object. The first is a WindowListener object that will terminate the program when the user closes the MyFrame object.

The second is a MouseListener object that will process mouse events on the MyFrame object.

It is typical to register listener objects as anonymous objects in those cases where a specific reference to the listener object is not otherwise needed.

    displayWindow.addWindowListener(new WProc1());    displayWindow.addMouseListener(                             new MouseProc(displayWindow));

Page 163: Basic Java Handout

  }//end constructor}//end class GUI definition

As you can see above, that ends the definition of the GUI class. That brings us to the definition of Listener classes for the WindowListener and the MouseListener interfaces.

We will begin with the MouseListener class. Note that this class extends the MouseAdapter class and does not directly implement the MouseListener interface. This saves us the trouble of having to create empty methods for event types that we are not interested in.

Objects of this class that are registered on the Source will be notified whenever a mousePressed() event occurs on the Source. This will cause the mousePressed() method to be invoked which will display the coordinates of the mouse pointer when the mouse is pressed on the source object. Note that this class extends an adapter class.

When the mousePressed() method is invoked, it receives an object of type MouseEvent as a parameter. Different types of events encapsulate different types of information in the object that is passed as a parameter. This particular object contains a variety of information, including the coordinates of the mouse pointer when the event occurred.

The code in the overridden mousePressed() method extracts that coordinate information from the object and stores it in the instance variables named clickX and clickY of the Source object.

Then it invokes the repaint() method on the source object, causing the source object to be repainted on the screen. This causes the overridden paint() method discussed earlier to be invoked, which displays the new coordinate

Page 164: Basic Java Handout

information on the screen in the proper location.  

class MouseProc extends MouseAdapter{  MyFrame refToWin; //save a reference to the source here    MouseProc(MyFrame inWin){//constructor    refToWin = inWin;//save ref to window  }//end constructor

  public void mousePressed(MouseEvent e){    refToWin.clickX = e.getX();    refToWin.clickY = e.getY();        refToWin.repaint();  }//end mousePressed()}//end class MouseProc

Finally, we come to the class that is used to instantiate a listener object that terminates the program when the user closes the MyFrame object. You will be seeing this class over and over as you review the sample programs in upcoming lessons.

class WProc1 extends WindowAdapter{  public void windowClosing(WindowEvent e){    System.exit(0);  }//end windowClosing()

Page 165: Basic Java Handout

}//end class WProc1

Note that an improved version of this program is presented at the end of this lesson. The improved version does not require the passing a MyFrame object reference to the constructor for the WindowListener object. You should become familiar with the methodology used in the improved version as well as the methodology used in the following version.

Event09 Program Listing

/*File Event09.java                                    This program is designed to be compiled under JDK 1.1

Illustrates the use of Event Sources, Event Listeners, and Adapters in the Delegation Event Model.

This program instantiates a Listener object to process mouse events. When a mouse press occurs in a Frame object,the program gets the coordinates and then displays thosecoordinates near the point of the mouse press.

This program was tested using JDK 1.1.3 under Win95.**********************************************************/import java.awt.*;import java.awt.event.*;

public class Event09 {

Page 166: Basic Java Handout

  public static void main(String[] args){    GUI gui = new GUI();//instantiate a GUI  }//end main}//end class Event09//=======================================================//

//Subclass Frame in order to override the paint method.class MyFrame extends Frame{  int clickX;  int clickY;    public void paint(Graphics g){    g.drawString(             "" + clickX + ", " + clickY, clickX, clickY);  }//end paint()}//end class MyFrame//=======================================================//

//The following class is used to instantiate a // graphical user interface object.class GUI {  public GUI(){//constructor    //Create a new Frame object, set size, title, etc.    MyFrame displayWindow = new MyFrame();    displayWindow.setSize(300,300);    displayWindow.setTitle("                                  ");    displayWindow.setVisible(true);        //Instantiate and register an anonymous Listener 

Page 167: Basic Java Handout

    // object which will terminate the program when the     // user closes the Frame.    displayWindow.addWindowListener(new WProc1());        //Instantiate and register an anonymous Listener     // object that will process mouse events to determine    // and display the coordinates when the user presses    // the mouse button in the client area of the Frame.    displayWindow.addMouseListener(                             new MouseProc(displayWindow));  }//end constructor}//end class GUI definition//=======================================================//

//This listener class monitors for mouse presses and // displays the coordinates of the mouse pointer when the// mouse is pressed on the source object. Note that this// class extends is an adapter class.class MouseProc extends MouseAdapter{  MyFrame refToWin; //save a reference to the source here    MouseProc(MyFrame inWin){//constructor    refToWin = inWin;//save ref to window  }//end constructor

Page 168: Basic Java Handout

  //Override the mousePressed method to determine and   // display the coordinates when the mouse is pressed.  public void mousePressed(MouseEvent e){    //Get X and Y coordinates of mouse pointer and store    // in an instance variable of the Frame object    refToWin.clickX = e.getX();    refToWin.clickY = e.getY();        //Force the Frame object to be repainted in order to    // display the coordinate information.    refToWin.repaint();  }//end mousePressed()}//end class MouseProc//=======================================================//

//The following listener is used to terminate the program// when the user closes the frame.  Note that this class// extends an adapter class.class WProc1 extends WindowAdapter{  public void windowClosing(WindowEvent e){    System.exit(0);  }//end windowClosing()}//end class WProc1//================================

Page 169: Basic Java Handout

=======================//

Summary

The Delegation Event Model used in JDK 1.1 is radically different from the Inheritance Event Model used in JDK 1.0.2.

In the simplest case, you can handle low-level events in JDK 1.1 with the following steps. (Semantic events will be discussed in a subsequent lesson).

Step 1

Define a Listener class for a specific class of events by either implementing the listener interface which matches that class of events, or extending the corresponding adapter class.

Step 2

Define or override the interface methods in the Listener class, for each specific event type in the event class, to implement the desired behavior of the program upon occurrence of an event.

If you implement the listener interface, you must define all interface methods. If instead you extend the corresponding adapter class, you can override only those methods which tie to event types of interest.

Step 3

Define a class which instantiates an object of the Source class and the Listener class and registers the listener object on the source object for notification of the occurrence of events generated by the source object, using code such as the following:       displayWindow.addMouseListene

Page 170: Basic Java Handout

r(mouseProcCmd);

In this code fragment,

1 displayWindow is the object that generates the event,

2 mouseProcCmd is the name of the listener object, and

3 addMouseListener() is the method that registers the listener object to receive mouse events from the object named displayWindow.

This statement will cause the object named mouseProcCmd to be notified of all events generated by displayWindow which are part of the class of mouse events.

The notification takes the form of invoking a method in the mouseProcCmd object where there must be a corresponding method for each specific event type in the class of mouse events (but some of those methods can be empty shells if you have no interest in some of the event types).

Comments

As mentioned earlier, this is the procedure for the simplest cases. It is possible to make the situation more complicated. For example, an earlier sample program required a Source object to notify two different Listener objects of the occurrence of an event of the same class on a single screen object.

Another sample program required the Source object to notify two different Listener objects of the occurrence of events of two different classes on a single screen object.

It is also possible to cause a single Listener object to be registered to receive notification of the occurrence of events of a given class on more than one source object. In that case, it is normally necessary for the code in the

Page 171: Basic Java Handout

Listener object to crack open the event object to determine which screen object was responsible for the event (if it matters).

Also, the JDK 1.1 documentation indicates that it is possible to have event-style communication between objects that are not screen objects. Subsequent lessons will investigate a number of these possibilities.

JDK, Object Serialization

Introduction

In a nutshell, the Object Serialization capability of JDK 1.1 makes it possible to write objects to streams and read objects from streams without the requirement to decompose those objects into their component parts before writing, and without the requirement to reconstruct the object from its component parts after reading.

More specifically, according to the documentation for JDK 1.1:

"Object Serialization extends the core Java Input/Output classes with support for objects. Object Serialization supports the encoding of objects, and the objects reachable from them, into a stream of bytes; and it supports the complementary reconstruction of the object graph from the stream. Serialization is used for lightweight persistence and for communication via sockets or Remote Method Invocation (RMI). The default encoding of objects protects private and transient data, and supports the evolution of the classes. A class may implement its own external encoding and is then solely responsible for the external format."

Page 172: Basic Java Handout

While some aspects of Object Serialization such as evolution of classes and external encoding can be very complex, in its basic form, object serialization is easy to use.

Overview

Object serialization provides the capability to store and retrieve Java objects. This capability is provided on the basis of streams so that objects can be "stored" and "retrieved" from any medium that supports streams in Java. This includes disk files, communication links via sockets, stream buffers in memory, etc.

Providing this capability requires the ability to represent the state of objects in a serialized form that can be used to automatically reconstruct the objects.

In order for an object to be saved in a stream, the class of which it is an instance must support either the Serializable or the Externalizable Interface. This lesson will deal only with the Serializable Interface. The Externalizable interface extends the Serializable interface, adding the methods writeExternal() and readExternal() that you can use to gain more control over the serialization process.

According to the JDK 1.1 documentation:

"For Java objects, the serialized form must be able to identify and verify the Java class from which the object's contents were saved and to restore the contents to a new instance. For Serializable objects, the stream includes sufficient information to restore the fields in the stream to a compatible version of the class."

Those objects which are to be stored in and retrieved from a stream often contain references to other objects

Page 173: Basic Java Handout

(embedded objects). Those embedded objects must be stored and retrieved along with the parent object in order to maintain the relationship between objects. When an object is stored, all of the objects that are reachable from that object are stored as well.

A sample program will be presented later in this lesson which demonstrates the storage and retrieval of an object which contains another embedded object.

Writing an Object to a Stream

For the simple case of storing objects in a stream, we first instantiate an OutputStream to receive the bytes. In our later sample program, we will use a FileOutputStream.

Next, we need to instantiate an ObjectOutputStream object by invoking the constructor of the ObjectOutputStream class and passing the previously instantiated OutputStream object as a parameter.

Having done this, we can simply invoke the writeObject() method of the ObjectOutputStream class, passing the object that we want to store as a parameter.

In order to be able to pass the object to the writeObject() method, that object must belong to a class that implements the Serializable (or Externalizable) interface.

After storing all of our objects, we should use the flush() method to make certain that all of the objects have been inserted into the stream and are not still lingering in a buffer.

According to the JDK 1.1 documentation:

"The writeObject method serializes the specified object and traverses its references to other objects in

Page 174: Basic Java Handout

the object graph recursively to create a complete serialized representation of the graph. Within a stream, the first reference to any object results in the object being serialized or externalized and the assignment of a handle for that object. Subsequent references to that object are encoded as the handle. Using object handles preserves sharing and circular references that occur naturally in object graphs. Subsequent references to an object use only the handle allowing a very compact representation."

Note that the ObjectOutputStream class also provides write methods for primitive types such as writeChar(), writeByte, writeDouble, etc., to support the possibility that primitive types may need to be written into the stream along with objects.

Reading an Object from the Stream

Retrieving a stored object, or reading an object from a stream is just as straightforward as writing it to the stream.

First, we need to instantiate an InputStream. In the sample program later in this lesson, we will use a FileInputStream.

Then we instantiate an ObjectInputStream that reads from the InputStream. This is accomplished by invoking the constructor for the ObjectInputStream class and passing the InputStream as a parameter.

Having done this, we simply use the readObject() method of the ObjectInputStream class to read each object from the stream. This method returns an object of type Object, so we need to downcast it to the proper type of object before storing or attempting to manipulate it.

Page 175: Basic Java Handout

According to the JDK 1.1 documentation:

"The readObject method deserializes the next object in the stream and traverses its references to other objects recursively to create the complete graph of objects serialized."

Note that the ObjectInputStream class also provides read methods for primitive types such as readChar(), readByte, readDouble, etc., to support the possibility that primitive types may have been written into the stream along with objects.

Protecting Sensitive Information

If your objects contain sensitive information, you should read the JDK 1.1 documentation very carefully before writing the objects into a stream.

According to the documentation, one technique for avoiding security problems is to mark sensitive fields as private transient. transient and static fields are not serialized or deserialized. This will prevent the sensitive data from actually entering the stream.

Also according to the documentation:

"Particularly sensitive classes should not be serialized at all. To accomplish this, the object should not implement either the Serializable or Externalizable interfaces."

Since object serialization is implemented as a stream process which inherently supports the application of filters, it is also possible to provide encryption and decryption filters.

Sample Program

The next section discusses the particulars of a sample

Page 176: Basic Java Handout

program that illustrates much of what has been discussed above. A listing of the program follows the discussion.

Interesting Code Fragments

This application

1 opens and writes three objects to an output file,

2 closes the file,

3 opens the file as an input file,

4 reads the three objects, and

5 displays their contents.

The three objects written to the output file are:

1 A String object

2 A Date object

3 A composite object of a new serializable class named MyOuterClass which contains an embedded object of another new serializable class named MyEmbeddedClass.

The following code fragment shows the class definition for MyEmbeddedClass. This class contains one private instance variable and one public instance method. The private instance variable is a simple String object. The public instance method is a showEmbeddedData() method that displays the private instance variable.

Note that this class implements the Serializable interface.

class MyEmbeddedClass implements Serializable{    private String

Page 177: Basic Java Handout

myEmbeddedString = "I am a " +                "Private Instance Variable in the Embedded Object";    public void showEmbeddedData(){        System.out.println(myEmbeddedString);    }//end showEmbeddedData }//end class MyEmbeddedClass

The next fragment shows the class definition for the class named MyOuterClass. This class contains two private instance variables and a public instance method named ShowAllData().

The first instance variable is a simple String object. The second instance variable is an embedded object of the class discussed above (MyEmbeddedClass) which also contains a private instance variable and a public instance method.

The public instance method in an object of this class is a showAllData() method that displays the private String variable in the object and invokes the public showEmbeddedData() method of the private embedded object to cause the private instance variable in that object to also be displayed.

Note that the class implements the Serializable interface.

class MyOuterClass implements Serializable{    private String myOuterString = "I am a " +

Page 178: Basic Java Handout

            "Private Instance Variable in the Outer Object";    MyEmbeddedClass myEmbeddedObject = new MyEmbeddedClass();

    public void showAllData(){        System.out.println(myOuterString);        myEmbeddedObject.showEmbeddedData();    }//end showAllData()   

}//end class MyOuterClass

The controlling class for the application is shown in the next fragment. It is very simple. All that it does is to instantiate an object of the MyProcess class where all of the work is done..

class ObjSer01{//controlling class    static public void main(String[] args){    MyProcess myProcess = new MyProcess();        }//end main()}//end class ObjSer01

The following fragment shows the beginning of the MyProcess class. The constructor for this class contains the code to illustrate object serialization.

The constructor begins by opening an ObjectOutputStream as discussed earlier, and invoking the writeObject() method to write three objects to that stream. The objects

Page 179: Basic Java Handout

written to the stream are a String object, a Date object, and an object of type MyOuterClass described above. Then the constructor flushes and closes the stream.

class MyProcess{    MyProcess(){//constructor        try{            FileOutputStream fout = new FileOutputStream("tmp");            ObjectOutputStream outStream    =                                                            new ObjectOutputStream(fout);            //write a String object            outStream.writeObject("Today is ");            //write a Date object            outStream.writeObject(new Date());            //write a custom object            outStream.writeObject(new MyOuterClass());            outStream.flush();            outStream.close();

Than an ObjectInputStream linked to the file containing the three objects is instantiated as shown in the following fragment.

            FileInputStream fin = new FileInputStream("tmp");            ObjectInputStream inStream =   new ObjectInputStream(fin);

Then the application uses the readObject() method to read

Page 180: Basic Java Handout

the three objects from the stream. In each case the contents of the objects are displayed after they are read. This is illustrated in the following fragment. Note that we omitted the exception handling code from this fragment in the interest of brevity.

                //read String object                String stringObj = (String)inStream.readObject();                //display the String object                System.out.print(stringObj);

                //read the Date object                Date dateObj = (Date)inStream.readObject();                //display the Date object                System.out.println(dateObj);

                //read the custom object                MyOuterClass myCustomObject =                                               (MyOuterClass)inStream.readObject();                //display the custom object                myCustomObject.showAllData();

The important point is that all three objects were written as objects and read as objects. No effort was required on the part of the programmer to decompose the objects for

Page 181: Basic Java Handout

writing or to reconstruct the objects after reading.

The output from running the program in one particular case is shown in the comments at the beginning of the program.

Program Listing

A listing of the program follows.

/*File ObjSer01.java,                                    Rev 12/17/98Designed to be compiled and run under JDK 1.1 or a laterversion.This application discusses the object serialization capability in JDK 1.1.

This application writes three objects to an output file, closes the file, opens the file, reads the objects, and displays their contents.

The three objects written to the output file are: - A String object - A Date object - A composite object of a new serializable class named       MyOuterClass which contains an embedded object of       another new serializable class named MyEmbeddedClass.

The object of the class named MyOuterClass contains two private instance variables and a public instance

Page 182: Basic Java Handout

method named ShowAllData.

The first private instance variable is a simple String object.

The second private instance variable is an embedded objectof another new serializable class named MyEmbeddedClass.

The embedded object also contains a private instance variable of type String and a public instance method namedshowEmbeddedData().

The application then closes the file and opens it for reading.It reads and displays all three objects.

The important point is that all three objects are written as objects and read as objects.    No effort was required onthe part of the programmer to decompose the objects for writing or to reconstruct the objects after reading.

The output from running the program in one particular casewas:Today is Thu Dec 17 09:28:58 CST            I am a Private Instance Variable in the Outer ObjectI am a Private Instance Variable in the Embedded

Page 183: Basic Java Handout

Object

This program was tested using JDK 1.1 under Win95. Itwas also tested using JDK 1.2 under Win95.**********************************************************/import java.io.*;import java.util.*;//=======================================================///*Objects of the following serializable class contain one     private instance variable and one public instance method.    The private instance variable is a simple String object.    The public instance method is a show method that displays    the private instance variable.*/class MyEmbeddedClass implements Serializable{    private String myEmbeddedString = "I am a " +                "Private Instance Variable in the Embedded Object";    public void showEmbeddedData(){        System.out.println(myEmbeddedString);    }//end showEmbeddedData    }//end class MyEmbeddedClass//=======================================================//

Page 184: Basic Java Handout

/*Objects of the following serializable class contain two private instance variables and one public instance method. The first instance variable is a simple String object. The second instance variable is an embedded object of a new serializable class which also contains a private instance variable and a public instance method.

The public instance method in an object of this class is a show method that displays the private String variable in the object and invokes the public show method of the private embedded object to cause the private instance variable in that object to also be displayed.

Note that the class implements the Serializable interface.*/class MyOuterClass implements Serializable{    private String myOuterString = "I am a " +            "Private Instance Variable in the Outer Object";    MyEmbeddedClass myEmbeddedObject = new MyEmbeddedClass();

public void showAllData(){        System.out.println(myOuterString);        myEmbeddedObject.showEmbeddedData();    }//end showAllData()   

Page 185: Basic Java Handout

}//end class MyOuterClass//=======================================================//

//Controlling Classclass ObjSer01{    static public void main(String[] args){    MyProcess myProcess = new MyProcess();        }//end main()}//end class ObjSer01//=======================================================//class MyProcess{    MyProcess(){//constructor        try{            FileOutputStream fout = new FileOutputStream("tmp");            ObjectOutputStream    outStream    =                                                              new ObjectOutputStream(fout);            //write a String object            outStream.writeObject("Today is ");            //write a Date object            outStream.writeObject(new Date());            //write a custom object            outStream.writeObject(new MyOuterClass());            outStream.flush();            outStream.close();                        FileInputStream fin = new FileInputStream("tmp");

Page 186: Basic Java Handout

            ObjectInputStream inStream =                                                                 new ObjectInputStream(fin);            try{                //read String object                String stringObj = (String)inStream.readObject();                //display the String object                System.out.print(stringObj);

                //read the Date object                Date dateObj = (Date)inStream.readObject();                //display the Date object                System.out.println(dateObj);

                //read the custom object                MyOuterClass myCustomObject =                                               (MyOuterClass)inStream.readObject();                //display the custom object                myCustomObject.showAllData();                            }catch(ClassNotFoundException e){                System.out.println(e);            }//end catch block            inStream.close();            }catch(IOException e){System.out.println(e);}    }//end constructor}//end class MyProcess//=======================================================//

Page 187: Basic Java Handout

JDBC, Introduction to JDBC and Database Access

Introduction

Although JDBC capability is available for both JDK 1.1 and JDK 1.2, this lesson will concentrate on the use of JDBC with JDK 1.2. Comments in the listing of the sample program near the end of the lesson also explain how to run it under JDK 1.1.

Interesting Code Fragments

This section highlights code fragments that are important in gaining an understanding of how to use JDBC to access a remote database server and to manipulate the data stored in the database. The first fragment is provided simply to remind you of the requirement to import the java.sql package.

import java.sql.*;

The next fragment shows the beginning of the main() method and the declaration of a two local variables that will be used later.

    public static void main(String args[]) {        try {            Statement stmt;            ResultSet rs;

The next fragment shows the first critical step in the use of JDBC: registration of the JDBC driver for the database engine that you intend to use. This statement loads the driver class and makes the driver available for use later when it is needed to open a connection to the database server. When the driver is loaded into memory, it registers itself with the java.sql.DriverManager class as an

Page 188: Basic Java Handout

available database driver.

            Class.forName("com.imaginary.sql.msql.MsqlDriver");

There are other ways to accomplish this registration as well. The FAQ that is available with the mSQL JDBC drivers suggests that the driver be registered using a statement such as the following when the program is started:

java -Djdbc.drivers=com.imaginary.sql.msql.MsqlDriver Jdbc01

The advantage is that it further disconnects the program from a specific database engine. In theory, JDBC programs that you write should be compatible with any modern SQL database engine.

Another approach uses the registerDriver() method to register the JDBC driver software.

mSQL and other similar database engines behave as servers on a network. They are identified by a URL much as other types of servers (such as HTTP servers and FTP servers) are identified. The next fragment defines the URL for the database server that we used in this sample program.

This fragment actually shows two statements. One statement can be used to access the database when it is running on a remote TCP/IP server named webserver. The other statement can be used to access the database when it is running in a separate process on the same machine (localhost). Although we    haven't mentioned this earlier, this sample program will run on a single machine

Page 189: Basic Java Handout

with the database server program running in one process and the sample program running in another process.

Note that in these statements, the "//" shown to the right of "msql:" form part of the URL. They are not comment indicators.

            String url = "jdbc:msql://webserver:1114/JunkDB";//            String url = "jdbc:msql://localhost:1114/JunkDB";

The second critical statement in the use of JDBC, as shown in the next fragment, gets a connection to the database.

            Connection con = DriverManager.getConnection(url,                                                                "baldwin", "");

The DriverManager class provides the basic services for managing a set of JDBC drivers. The DriverManager class will attempt to load the driver classes referenced in the "jdbc.drivers" system property (recall the expression shown earlier that can be used to set this property when the program is started).

A program can also explicitly load JDBC drivers at any time using the forName() method shown earlier in this sample program. There is also a static method of the DriverManager class named registerDriver() that can be used for this purpose.

Page 190: Basic Java Handout

getConnection() is a static method of the DriverManager class. When getConnection() is called, the DriverManager will attempt to locate a suitable driver from among those loaded at initialization and those loaded explicitly using the same classloader as the current applet or application. (Note that DriverManager can use the first two terms of the URL (jdbc:msql) to identify a suitable driver.)

There are several overloaded versions of getConnection(). The following is a description of the version used in the above fragment.

public static Connection getConnection(String url,                                                                String user,                                                                String password)                                                                throws SQLException

Attempts to establish a connection to the given database URL. The DriverManager attempts to select an appropriate driver from the set of registered JDBC drivers.

Parameters:    url - a database url of the form jdbc:subprotocol:subname    user - the database user on

Page 191: Basic Java Handout

whose behalf the Connection                   is being made    password - the user's password

Returns:    a Connection to the URLThrows:    SQLException - if a database access error occurs

If the attempt to get a connection to the database server is successful, the method returns an object of type Connection. In this program, a reference to the Connection object is stored in the reference variable named con.

If the attempt is not successful, an exception of type SQLException is thrown. Each SQLException object provides several kinds of information:

1 A string describing the error. This is used as the Java Exception message, available via the method getMessage().

2 A "SQLstate" string, which follows the XOPEN SQLstate conventions. The values of the SQLState string are described in the XOPEN SQL specification. This information is available via the getSQLState() method.

3 An integer error code that is specific to each vendor. Normally this will be the actual error code returned by the underlying database. This information is available via the getErrorCode() method.

4 A chain to a next Exception. This can be used to provide additional error information by invoking the

Page 192: Basic Java Handout

getNextException() method.

For example, you might use code such as the following in the exception handler to obtain and display the information encapsulated in a SQLException object.

catch(SQLException ex) {    while (ex != null) {        System.out.println("Message:  " + ex.getMessage ());        System.out.println("SQLState:    " + ex.getSQLState ());        System.out.println("ErrorCode: " + ex.getErrorCode ());        ex = ex.getNextException();        System.out.println("");    }//end while loop}//end catch block

The code in the next fragment is not critical to the use of JDBC. This code simply displays the URL and Connection objects.

            System.out.println("URL: " + url);            System.out.println("Connection: " + con);

The next fragment shows the third critical step in the use of JDBC.

            stmt = con.createStatement();

Recall that con is a reference to an object of type

Page 193: Basic Java Handout

Connection. A Connection object defines a connection (session) with a specific database. SQL statements are executed and results are returned within the context of a connection.

Here we are concerned with the createStatement() method of the Connection class. This method creates a Statement object for sending SQL statements to the database.

According to the JavaSoft documentation, a Statement object is "The object used for executing a static SQL statement and obtaining the results produced by it."

The results are returned in the form of a ResultSet object. Only one ResultSet per Statement can be open at any point in time. Therefore, if the reading of one ResultSet is interleaved with the reading of another, each must have been generated by different Statement objects. All Statement executeXXX methods (such as executeUpdate()) implicitly close a statement's current ResultSet if an open one exists.

The Statement class provides many methods that are used to manipulate the data in the database. One of those methods is executeUpdate(). This method has a single String parameter, which must be a valid SQL statement. It is used to execute SQL INSERT, UPDATE or DELETE statements. In addition, other SQL statements that return nothing can be executed using this method.

This sample program will create a table named myTable. However, if a table having that name already exists in the database, the attempt to create the table will throw an exception, which if not caught, will terminate the program. As a precaution, the following fragment uses the executeUpdate() method to delete a table having that

Page 194: Basic Java Handout

name if it exists. If a table having that name doesn't already exist, the attempt to delete the table throws an exception. The exception handler for this exception simply displays some text and continues with the normal flow of the program.

The next fragment illustrates the fourth critical step in the use of JDBC: use of a Statement object to manipulate the database.

Since this fragment contains the first statement in the program that attempts to use JDBC to manipulate the database, the single statement in the fragment used for that purpose is highlighted in boldface.

            try{                stmt.executeUpdate("DROP TABLE myTable");            }catch(Exception e){                System.out.print(e);                System.out.println("No existing table to delete");            }//end catch

As you can surmise from the above discussion and code, the SQL DROP statement causes the table to be deleted from the database.

The next fragment uses the executeUpdate() method to create a table named myTable. we don't plan to provide an extensive discussion of the SQL statements used in this program. Suffice it to say that this table will contain two columns. The first column is named test_id and contains data of type int. The second column is named

Page 195: Basic Java Handout

test_val and contains a string up to 15 characters in length.

            stmt.executeUpdate("CREATE TABLE myTable ("                            + "test_id int,test_val char(15) not null)");

The next fragment uses the executeUpdate() method to insert data into five new rows in the table. You should be able examine the syntax of the SQL statements and surmise what is going on here.

            stmt.executeUpdate("INSERT INTO myTable ("                                      + "test_id, test_val) VALUES(1,'One')");            stmt.executeUpdate("INSERT INTO myTable ("                                      + "test_id, test_val) VALUES(2,'Two')");            stmt.executeUpdate("INSERT INTO myTable ("                                  + "test_id, test_val) VALUES(3,'Three')");            stmt.executeUpdate("INSERT INTO myTable ("                                    + "test_id, test_val) VALUES(4,'Four')");            stmt.executeUpdate("INSERT INTO myTable ("                                    + "test_id,

Page 196: Basic Java Handout

test_val) VALUES(5,'Five')");

The next fragment gets another Statement object initialized as shown. Refer to the JDK 1.2 documentation for the createStatement() method and the ResultSet class for a description of the parameters passed to the method in this case. The ResultSet class provides about eight symbolic constants that can be used as parameters to this method. The values of the parameters exercise control over the behavior of the ResultSet object returned by later queries based on the Statement object.

            stmt = con.createStatement(ResultSet.                                                              TYPE_SCROLL_INSENSITIVE,                                                              ResultSet.CONCUR_READ_ONLY);

The executeQuery() method of the Statement class executes an SQL statement that returns a single ResultSet object. The parameter to the method is a String that typically represents a static SQL SELECT statement. The ResultSet object that is returned contains the data produced by the query;

            rs = stmt.executeQuery(                              "SELECT * from myTable ORDER BY test_id");

A ResultSet object provides access to a table of data. The object maintains a cursor pointing to its current row of data. Initially the cursor is positioned before the first row. The next() method moves the cursor to the next row

Page 197: Basic Java Handout

(similar to an iterator or an enumerator in Java).

The getXXX methods (such as getString()) retrieve column values for the current row. You can retrieve values using either the index number of the column or the name of the column. In general, using the column index is more efficient. Columns are numbered beginning with 1 (not with 0).

For the getXXX methods, the JDBC driver attempts to convert the underlying data to the specified Java type and returns a suitable Java value.

A ResultSet is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.

The next fragment uses several methods of the ResultSet class in a while loop to display all of the data in the ResultSet object produced by the earlier query.

            System.out.println("Display all results:");            while(rs.next()) {                int theInt= rs.getInt("test_id");                String str = rs.getString("test_val");                System.out.println("\ttest_id= " + theInt   + "\tstr = " + str);            }//end while loop

The next fragment uses the absolute() method of the ResultSet class to move the cursor to row 2 in the result

Page 198: Basic Java Handout

table and then displays the data in the two columns of that row. Row numbers begin with 1 (not with 0).

            System.out.println("Display row number 2:");            if( rs.absolute(2) ) {                int theInt= rs.getInt("test_id");                String str = rs.getString("test_val");                System.out.println("\ttest_id= " + theInt   + "\tstr = " + str);            }//end if

The final fragment, which illustrates the fifth critical step in the use of JDBC,deletes the table and closes the connection to the database.

            stmt.executeUpdate("DROP TABLE myTable");            con.close();              

This fragment is followed by an exception handler (not shown) which ends the program.

Program Listing

A complete listing of the program with additional comments follows. This listing also contains some information about the differences between JDK 1.1 and JDK 1.2 insofar as JDBC is concerned.

/*File Jdbc01.java,       

The purpose of this program is to test the ability to useJDBC to access a remote mSQL

Page 199: Basic Java Handout

database server.

The remote TCP/IP server named webserver provides access to a database server program named mSQL.    The mSQL database server program was started and a database named JunkDB was created on that database server using a consolecommand before this program was run.

This program accesses the database named JunkDB, creates atable named myTable, puts five rows of data into the table,displays the data, and then deletes the table.   

As a precaution, before attempting to create the new table,the program attempts to delete a table having the same name.    If a table having the same name already exists as residue from a previous run, it is deleted.    If it doesn'talready exist when the attempt is made to delete it, an exception is thrown.    This exception is simply caught and

Page 200: Basic Java Handout

ignored.

There are major differences between the versions of JDBCthat support JDK 1.1 and JDK 1.2. By removing and addingcomment indicators, this program can be made to operateproperly under either version of the JDK/JDBC combination.This assumes that you have both versions of JDBC for mSQLproperly installed on your classpath.

.    However, the functionality of the JDBCinterface is described in the JavaSoft documentation foreither JDK 1.1 or JDK 1.2 in the java.sql package.

Note that it is necessary to manually start the mSQL database server running on the remote server machine.

The JDK 1.1 version of the program, created by removing andadding comment indicators as shown in the source codeproduced the following output:

Page 201: Basic Java Handout

    URL: jdbc:msql://webserver:1114/JunkDBConnection: com.imaginary.sql.msql.MsqlConnection@1cc8bejava.sql.SQLException: :Unknown table "myTable"No existing table to deleteDisplay all results:    test_id= 1    str = One    test_id= 2    str = Two    test_id= 3    str = Three    test_id= 4    str = Four    test_id= 5    str = Five        The JDK 1.2 version, also created by removing and addingcomment indicators as shown in the source code produced thefollowing output. Note the missing characters "un" in the display of the exception that should read "unknown table".This could lead to considerable confusion.    URL: jdbc:msql://webserver:1114/JunkDBConnection: com.imaginary.sql.msql.MsqlConn

Page 202: Basic Java Handout

[email protected]: known table "myTable"No existing table to deleteDisplay all results:    test_id= 1    str = One    test_id= 2    str = Two    test_id= 3    str = Three    test_id= 4    str = Four    test_id= 5    str = FiveDisplay row number 2:    test_id= 2    str = Two    **********************************************************/import java.sql.*;

public class Jdbc01 {    public static void main(String args[]) {        try {            Statement stmt;            ResultSet rs;                        //Register the JDBC driver            Class.forName("com.imaginary.sql.msql.MsqlDriver");                        //Define URL of database server for database named             // JunkDB by selecting one of the following            // statements.    we believe that port 1114 is the

Page 203: Basic Java Handout

            // standard database server port, but we are not            // certain.    This value along with the user name and            // some other information is specified in a file             // named msql.conf in the Hughes directory which is            // the installation directory for the mSQL database.            String url = "jdbc:msql://webserver:1114/JunkDB";//            String url = "jdbc:msql://localhost:1114/JunkDB";

                        //Get a connection to the database            Connection con = DriverManager.getConnection(url,  "baldwin", "");            //Display URL and connection information            System.out.println("URL: " + url);            System.out.println("Connection: " + con);                        //Get a Statement object            stmt =

Page 204: Basic Java Handout

con.createStatement();                        //As a precaution, delete myTable if it already             // exists as residue from a previous run.    Otherwise,            // if the table already exists and an attempt is made            // to create it, an exception will be thrown.            try{                stmt.executeUpdate("DROP TABLE myTable");            }catch(Exception e){                System.out.print(e);                System.out.println("No existing table to delete");            }//end catch

            //Create a table in the database named myTable.            stmt.executeUpdate("CREATE TABLE myTable ("                            + "test_id int,test_val char(15) not null)");                        //Insert some values into the table            stmt.executeUpdate("INSERT INTO myTable ("                                      + "test_id, test_val) VALUES(1,'One')");            stmt.executeUpdate("INSERT INTO myTable ("

Page 205: Basic Java Handout

                                      + "test_id, test_val) VALUES(2,'Two')");            stmt.executeUpdate("INSERT INTO myTable ("                                  + "test_id, test_val) VALUES(3,'Three')");            stmt.executeUpdate("INSERT INTO myTable ("                                    + "test_id, test_val) VALUES(4,'Four')");            stmt.executeUpdate("INSERT INTO myTable ("                                    + "test_id, test_val) VALUES(5,'Five')");

            //Get another statement object.    This version is             // compatible with either JDK 1.1 or JDK 1.2, but             // does not support the rs.absolute(2) statement used            // later in the JDK 1.2 version.            stmt = con.createStatement();

/*            //Get another statement object initialized as shown.            // This version is compatible with JDK 1.2 but is not            // compatible with JDK 1.1. This version is required

Page 206: Basic Java Handout

            // to support the rs.absolute(2) statement later.            stmt = con.createStatement(ResultSet.                                                              TYPE_SCROLL_INSENSITIVE,                                                              ResultSet.CONCUR_READ_ONLY);*/            //Query the database, storing the result in an object            // of type ResultSet            rs = stmt.executeQuery(                              "SELECT * from myTable ORDER BY test_id");

            //Use the methods of class ResultSet in a loop            // to display all of the data in the database.            System.out.println("Display all results:");            while(rs.next()) {                int theInt= rs.getInt("test_id");                String str = rs.getString("test_val");                System.out.println("\ttest_id= " + theInt   + "\tstr = " + str);            }//end while loop

/*

Page 207: Basic Java Handout

            //This block of code only works under JDK 1.2.                // The absolute() method is not supported by JDK 1.1.            System.out.println("Display row number 2:");            if( rs.absolute(2) ) {                int theInt= rs.getInt("test_id");                String str = rs.getString("test_val");                System.out.println("\ttest_id= " + theInt   + "\tstr = " + str);            }//end if            //End block supported only by JDK 1.2.    */            //Delete the table and close the connection to the            // database                        stmt.executeUpdate("DROP TABLE myTable");            con.close();        }catch( Exception e ) {            e.printStackTrace();        }//end catch    }//end main}//end class Jdbc01

Network Programming - General Information

Introduction

Background Information

Page 208: Basic Java Handout

For our purposes, a network is a group of computers and other devices that are connected in some fashion so as to be able to exchange data.

Each of the devices on the network can be thought of as a node, and each node has a unique address. The manner in which addresses are assigned will vary from one type of network to another, but in all cases, the address of each device must be unique so as to distinguish it from the other devices.

Addresses are numeric quantities that are easy for computers to work with, but are not easy for humans to remember. Therefore, some networks also provide names that humans can more easily remember than numbers.

Modern networks transfer data using a concept known as packet switching. This means that the data are encapsulated into packets which are transferred from the source to the destination. At the destination, it is necessary to extract the data from one or more packets and use it to reconstruct the original message.

Communication Protocol

In order for two or more computers connected to a network to be able to exchange data in an orderly manner, they must adhere to a mutually acceptable communication protocol. The protocol defines the rules by which they communicate.

Teaching your children to say please and thank you involves teaching them something about a protocol. If they occasionally forget to say please, however, they will probably get the cookie anyway.

If a computer protocol requires the participating computers to say please, and they forget to say please,

Page 209: Basic Java Handout

they probably won't get the cookie.

There are many protocols available. For example, the HTTP protocol defines how web browsers and servers communicate and the SMTP protocol defines how email is transferred (we will write programs that implement part of the HTTP and SMTP protocols).

Note here that we have been discussing application protocols that operate at the surface level. We will also be making mention of lower-level protocols that operate below the application level. Fortunately, as high-level Java programmers, we don't have to be too concerned about the lower-level protocols. We'll let the systems people worry about them.

Network Layers

Networks are logically separated into layers ranging from the Application Layer at the top to the Physical Layer at the bottom. The technical details of network layering are beyond the scope of this lesson. Fortunately, you will be able to write useful network programs using Java without understanding the details of network layering.

The Application Layer is the layer that delivers data to the user. The layers below that are involved with getting data from the Application Layer at one end of the conversation to the Application Layer at the other end. For the most part, we will be concerned only with the Application Layer.

Clients and Servers

In these lessons, we will be concerned with networked communications that involve client computers and a server computers. How do we know which is which? For the purposes of our studies, it will be sufficient to say that

Page 210: Basic Java Handout

the client always initiates the conversation, and the server waits and listens for a client to initiate a conversation.

IP, TCP, and UDP

We need to know something about the following acronyms:

1 IP

2 TCP

3 UDP

IP

IP, which stands for Internet Protocol, is the protocol that will be involved below the Application Layer to move our data between a client and a server. Beyond knowing that it exists, we probably don't need to concern ourselves with the fact that IP is being used

In fact, in some situations, some other protocol may be used to move our data between a client and a server. As long as it works, we really don't care too much.

In a nutshell, IP is a network protocol that moves packets of data from a source to a destination. As the name implies, this is the protocol normally used on the Internet.

TCP

It is sometimes important to be able to have confidence that all packets that make up a message arrive at the destination undamaged and in proper order.

The Transmission Control Protocol (TCP) was added to IP to give each end of a connection the ability to acknowledge receipt of IP packets and to request retransmission of lost packets. Also TCP makes it possible to put the packets back together at the destination in the same

Page 211: Basic Java Handout

order that they were sent.

Therefore, you will often hear people using both acronyms in the same breath, as in TCP/IP. The two work together to provide a reliable method of encapsulating a message into data packets, sending the packets to a destination, and reconstructing the message from the packets at the destination.

UDP

Sometimes it may not be important that all the packets arrive at the destination or that they arrive in the proper order. Further, sometimes, you may not want to incur the time delays and overhead cost associated with those guarantees.

For example, if one computer is sending date and time information to another computer every 100 milliseconds, and the data in the packets is displayed on a digital clock as it is received, you might prefer that each packet make the trip as quickly as possible even if that means that occasionally a packet will be lost or damaged.

The User Datagram Protocol (UDP) is available to support this type of operation. UDP is often referred to as an unreliable protocol because there is no guarantee that a series of packets will arrive in the right order, or that they will arrive at all.

As Java programmers, we have the choice of TCP or UDP, and we need to know enough about the characteristics of each to be able to make informed choices between them.

IP Addresses

We don't really need to know very much about IP to be able to use it, but we do need to know about the addressing scheme used in IP.

Page 212: Basic Java Handout

Every computer attached to an IP network has a unique four-byte (32-bit) address.

Thirty-two bits are sufficient to define a large number of unique addresses, but the manner in which addresses are allocated is wasteful, and many of the addresses that have been allocated are not being used.

Efforts are underway to expand the number of possible unique addresses to a much larger number. The planned number is the number of unique addresses that can be represented with a 128-bit address. Although we haven't taken the time to calculate the figure, Elliotte Rusty Harold reports it to be 1.6043703E32 in his book entitled Java Network Programming.

For human consumption, we usually convert the value of each of the four bytes to an unsigned decimal value and display them connected by periods to make them easier to remember. For example, as near as we can tell, as of this writing, the IP address of www.javasoft.com is 204.160.241.98.

Domain Names

What do we mean by www.javasoft.com?

Even though we can do some tricks to make the numeric IP addresses easier to remember, humans don't do a very good job of remembering long strings of numbers. Humans remember words and names better. Therefore, most IP addresses have a corresponding name known as a domain name. The domain name for the IP address 204.160.241.98 is www.javasoft.com.

The Domain Name System (DNS) was developed to translate between IP addresses and domain names. Whenever you log your browser onto the internet and attempt to

Page 213: Basic Java Handout

connect to a server using its domain name, the browser first communicates with a DNS server to learn the corresponding numeric IP address. The numeric IP address (and not the domain name) is encapsulated into the data packets and used by the internet protocol to route those packets from the source to the destination.

We will learn how to use the Java InetAddress class to find the domain name corresponding to an IP address, and to find the IP address corresponding to a domain name.

What is Your IP Address

Do you have an IP address and a domain name?

If (like us) you use a commercial Internet Service Provider (ISP), you really don't have a fixed IP address or a fixed domain name. Rather, the ISP has a block of IP addresses reserved. When you dial up the ISP and log onto the Internet, the ISP temporarily assigns an IP address to you for the duration of that connection. If you disconnect and reconnect, chances are good that you will get a different IP address for that second session.

Ports

Each server computer that you may connect to will be logically organized into ports. These are not physical ports in the sense of the printer port on the back of your computer. Rather, they are simply logical sub-addresses which you provide to the operating system on the server so that the operating system can cause the appropriate server software to "answer the call." We will write a simple server software package that will service several different ports on independent threads.

Theoretically, there are 65,535 available ports. Port numbers between 1 and 1023 are predefined to be used for certain standard services. For example, if you want to

Page 214: Basic Java Handout

connect with server software that communicates using the HTTP protocol, you would normally connect to port 80 on the server of interest.

Similarly, if you want to connect to a port that will tell you the time, you should connect to port 13. If you want to connect to a port that will simply echo whatever you send to it (usually for test purposes), you should connect to port 7. We will write Java applications that connect to all of these ports

In the interest of brevity, we are not going to attempt to provide a list of ports. However, you should be able to find all the information you might need about port numbers and the services they support by starting your favorite WWW search engine and searching for "well known ports".

Firewalls

You may have heard about firewalls. A firewall is the common name given to the equipment and associated software that is used to insulate the network inside of a company from the Internet at large outside the company. Typically, the firewall will restrict the degree to which computers inside the company can communicate with the Internet for security and other reasons.

Proxy Servers

You may also have heard about proxy servers. A proxy server acts as an interface between computers inside the company and the Internet at large.

Oftentimes the proxy server will have the ability to cache web pages for limited periods of time. For example, if ten people inside the company attempt to connect to the same Internet server and download the same web page within a (hopefully) short period of time, that page may

Page 215: Basic Java Handout

be saved on the proxy server on the first attempt and then delivered to the next nine people without re-acquiring it from the outside web server. This can significantly improve delivery time and reduce network traffic into and out of the company. It can also result in the delivery of stale pages in some cases.

Standards and Protocols

At some point, you may be interested in obtaining technical information about Internet standards and protocol specifications. A good place to start looking for such information is http://ds.internic.net. Another good place to look is http://www.w3.org/pub/WWW/Protocols/. These two URLs will probably provide you with enough reading material to keep you busy for awhile, and will also probably provide links where you can obtain additional information.

URL

URL is an acronym for Uniform Resource Locator (it is also the name of a class in Java). A URL is a pointer to a particular resource at a particular location on the Internet. A URL specifies the following:

1 protocol used to access the server (such as http),

2 name of the server,

3 port on the server (optional)

4 path, and

5 name of a specific file on the server (sometimes optional)

6 anchor or reference point within the file (optional)

Sometimes the name of the file can be omitted, in which case an HTTP browser will usually append the file name

Page 216: Basic Java Handout

index.html to the specified path and try to load that file. In addition to specifying the name of the file of interest, it is also sometimes possible to specify an anchor or reference that has been established inside the file.

The general syntax of a URL is:  

protocol://hostname[:port]/path/filename#ref

The port is optional, and is not normally required if you are accessing a server that provides the required service on a standard port. The browser (or other software being used to connect) should know which port supports the specified protocol and should connect to that port by default.

However, if you were to change the 80 to a 25, you would not be able to connect and successfully communicate with the server because the server does not support the HTTP protocol on port 25.

Socket Classes and URL Class

Java provides two different approaches for doing network programming, as least insofar as the web is concerned. The two approaches are associated with

1 Socket, DatagramSocket, and ServerSocket classes

2 the URL, URLEncoder, and URLConnection classes.

Socket Programming

Socket programming primarily makes use of two socket classes named Socket and DatagramSocket along with the ServerSocket class. The first two socket classes represent TCP and UDP communications respectively.

Generally, the two socket classes are used to implement

Page 217: Basic Java Handout

both clients and servers , while the ServerSocket class is only used to implement servers. We will see numerous examples of socket programming in this series of lessons.

Socket programming provides a low-level approach by which you can connect two computers for the exchange of data. One of those is generally considered to be the client while the other is considered to be the server.

Although the distinction between client and server is becoming less clear each day, there is one fundamental distinction that is inherent in the Java programming language. The client initiates conversations with servers. Servers block and wait for a client to initiate a conversation.

The governing application-level protocol will determine what happens after the connection is made and the conversation has begun. The fact that the two computers can connect doesn't necessarily mean that they can communicate. In order to communicate, they must implement some mutually acceptable application protocol

For example, the fact that we can dial a telephone number for a telephone located in France doesn't mean that we can communicate with the person who answers the phone. We don't know how to speak the French language. Unless the person who answers the phone speaks English, very little communication is likely to take place.

Socket programming has been around for quite a while in the Unix world. Java simply makes it easier by encapsulating much of the complexity of socket programming into classes, and allowing you to approach

Page 218: Basic Java Handout

the task on an object-oriented basis.

According to some authors, some of the generality and capability that Unix socket programmers have enjoyed has been lost in the encapsulation process.

Basically, socket programming makes it possible for you to cause data to flow in a full-duplex mode between a client and a server. This data flow can be viewed in almost exactly the same way that we view data flow to and from a disk: as a stream of bytes.

As with most stream data processing, the system is responsible for moving the bytes from the source to the destination. It is the responsibility of the programmer to assign meaning to those bytes.

Assigning meaning takes on a special significance for socket programming. In particular, as mentioned above, it is the responsibility of the programmer to implement a mutually acceptable communication protocol at the application level to cause the data to flow in an orderly manner.

An application protocol is a set of rules by which the programs in the two computers can carry on a conversation and transfer data in the process. For example, we will write a program using the SMTP mail protocol to send an email message to someone.

We will also write a program that implements a very abbreviated form of the HTTP protocol to download web pages from a server and display them.

We will also write a program that functions as an (abbreviated) HTTP server to deliver web pages to a client and also supports the echo protocol for both TCP

Page 219: Basic Java Handout

and UDP programming.

Each of these programs will involve adherence to a fairly simple protocol (at least the part that we implement will be fairly simple).

In addition, we will also write a program that obtains the date and time from another computer. In this case, the protocol will be about as simple as it can possibly be. In this case, the client will simply make the connection and listen for a string containing the date and time. This will be sort of like dialing the local time service, except that we won't have to listen to an advertisement before getting the time.

The bottom line is that with socket programming, it is easy to write code that will cause a stream of bytes to flow in both directions between a client and a server. This is no more difficult than causing a stream of bytes to flow in both directions between memory and a file on a disk.

However, getting the bytes to flow is the easy part. Beyond that, you must do all of the programming to implement an application protocol that is understood by both the client and the server.

URL Programming

URL programming occurs at a higher level than socket programming, and in theory represents a very powerful idea.

In theory, by using the URL class, you can open a connection to a resource on the web, specified by a URL object, and simply invoke the getContent() method on that URL object. The content of the resource will then be magically downloaded and will appear as an object on

Page 220: Basic Java Handout

the client machine, event if it requires an application protocol that didn't exist when you wrote the program, and contains content that you didn't understand when you wrote the program.

This description may be a bit of an overstatement, but it is pretty close to the claims being made. This is a powerful idea, which may or may not bear fruit in the future.

If fully implemented by browsers, the idea means that you can place new and unusual material on a web site along with special content handlers and protocol handlers. Then a cooperating browser will use those special handlers to move that material from the web site to the client and interpret its content once it get there without a requirement to install software (such as plug-ins) on the client computer on a permanent basis.

"If a browser doesn't recognize a media type, it should be able to download the code to process it from the same place it got the file. If they ever get this working, it will be ... a good thing."

Will they ever get it working? we don't know. If it depends on cooperation among all the major players, including the major browser vendors - probably not. Therefore, we don't plan to spend much time on the topic of protocol and content handlers until we see some evidence that it is working to such an extent that it is practically useful.

That is not to say that you couldn't use the capability right now if you were developing an intranet and wanted the clients to have access to new and unusual content. It would be necessary for you to provide the appropriate protocol and content handlers, and it would probably be

Page 221: Basic Java Handout

necessary for the clients to run Java applications written by you instead of standard browsers to access the data.

Also, the URL class provides an alternative way to connect one computer to another and transfer data on a stream basis, so we will see some examples of retrieving data from a server by obtaining a URL connection, and then opening and servicing I/O streams between the client and the server. We will see some sample programs that make use of this technique, but we will also see that it is redundant with the socket programming approach.

Page 222: Basic Java Handout

Threading in Java

Multitasking vs. Multithreading

The earliest computers did one thing at a time. A lab computer might calculate detonation waves for one of the physicists. Next it would calculate mixing ratios for a chemist. All programs were run sequentially, one at a time; and each had full run of the computer. However two programs couldn't be run at once. This is called batch processing, and it's a very efficient way to get maximum usage out of a very expensive computer because almost all the computer's time is spent actually calculating jobs and not switching between one program and another. However batch processing can be very annoying when your differential equation integration program that would take all of two seconds of CPU time gets stuck in line behind the physics department's nuclear structure modeling project that's going run for the next three days.

Time sharing operating systems were invented to allow multiple people to use one then very expensive computer at the same time. On a time sharing system many people can run programs at the same time. The operating system is responsible for splitting the time among the different programs that are running. That way you can finish integrating your differential equation while the physics department's nuclear modeling program is still churning away. The physics department nuclear modeling program might take two weeks to run instead of three days, but everyone with the shorter programs is happy (at least until the physicists figured out how to hack the computer so that it only ran their program).

Once systems allowed different users to run programs at

Page 223: Basic Java Handout

the same time it was a short step to letting the same user run multiple programs simultaneously. Each running program (generally caled a process) had its own memory space, its own set of variables, its own stack and heap, and so on. One process could spawn another process, but once that occurred the two processes behaved more or less independently. Mechanisms like remote procedure calls (RPC) were developed to allow processes to interact with each other, but such interaction was expensive and difficult. And this is where matters stopped for about twenty years.

However it's not just users that want to do different things at the same time. Many programs also need to do several things at once. A web browser, for instance, can print a file in the background while it downloads a page in one window and formats the page as it downloads. The ability of an individual program to do more than one thing at the same time is most efficiently implemented through threads.

What is a Thread?

A thread can be loosely defined as a separate stream of execution that takes place simultaneously with and independently of everything else that might be happening. A thread is like a classic program that starts at point A and executes until it reaches point B. It does not have an event loop. A thread runs independently of anything else happening in the computer. Without threads an entire program can be held up by one CPU intensive task or one infinite loop, intentional or otherwise. With threads the other tasks that don't get stuck in the loop can continue processing without waiting for the stuck task to finish.

It turns out that implementing threading is harder than

Page 224: Basic Java Handout

implementing multitasking in an operating system. The reason it's relatively easy to implement multitasking is that individual programs are isolated from each other. Individual threads, however, are not. To return to the printing example, suppose that while the printing is happening in one thread, the user deletes a large chunk of text in another thread. What's printed? The document as it was before the deletion? The document as it was after the deletion? The document with some but not all of the deleted text? Or does the whole system go down in flames? Most often in a non-threaded or poorly threaded system it's the latter.

Threaded environments like Java allow a thread to put locks on shared resources so that while one thread is using data no other thread can touch that data. This is done with synchronization. Synchronization should be used sparingly since the purpose of threading is defeated if the entire system gets stopped waiting for a lock to be released. The proper choice of objects and methods to synchronize is one of the more difficult things to learn about threaded programming.

How Java Uses Threads

Java applications and applets are naturally threaded. The runtime environment starts execution of the program with the main() method in one thread. Garbage collection takes place in another thread. Screen updating occurs in a third thread. There may be other threads running as well, mostly related to the behavior of the applet viewer or web browser. All of this happens invisibly to the programmer. Some of the time you're only concerned with what happens in the primary thread which includes the main() method of a program. If this is the case you may not need to worry about threading at

Page 225: Basic Java Handout

all.

Sometimes, however, you need to add your own threads to an applet or application. The simplest reason for adding a separate thread is to perform a long calculation. For instance if you're trying to find the ten millionth prime number, you probably don't want to make users twiddle their thumbs while you search. Or you may be waiting for a resource that isn't available yet, a large graphic to download from the Internet, for example. Once again you shouldn't make the user wait while your program waits. Any operation that is going to take a noticeable period of time should be placed in its own thread.

The other reason to use threading is to more evenly divide the computer's power among different tasks. If you want to draw random rectangles on the display, you would still like the applet to respond to user input. If all the CPU time is spent drawing rectangles, there's nothing left over for the user. On a preemptively multitasking operating system like Solaris or Windows NT, the user may at least be able to kill the application. On a cooperatively multitasking operating system like the MacOS or Windows, the user may have to reboot their machine. This is a bad thing. With threads you can set the priority of different processes, so that user input receives a high priority and drawing pretty pictures receives a low priority. Then the user can stop the applet without flipping the power switch on their machine.

The Thread Classes

Java has two ways a program can implement threading. One is to create a subclass of java.lang.Thread. However sometimes you'll want to thread an object that's already a subclass of another class. Then you use the

Page 226: Basic Java Handout

java.lang.Runnable interface.

The Thread class has three primary methods that are used to control a thread:

public native synchronized void start()public void run()public final void stop()The start() method prepares a thread to be run; the run() method actually performs the work of the thread; and the stop() method halts the thread. The thread dies when the the run() method terminates or when the thread's stop() method is invoked.

You never call run() explicitly. It is called automatically by the runtime as necessary once you've called start(). There are also methods to supend and resume threads, to put threads to sleep and wake them up, to yield control to other threads, and many more. I'll discuss these later.

The Runnable interface allows you to add threading to a class which, for one reason or another, cannot conveniently extend Thread. It declares a single method, run():

public abstract void run()By passing an object which implements Runnable to a Thread() constructor, you can substitute the Runnable's run() method for the Thread's own run() method. (More properly the Thread object's run() method simply calls the Runnable's run() method.)

A simple thread

When writing a threaded program you can pretend that you're writing many different programs, each with its own run() method. Each thread is a subclass of java.lang.Thread. The following program is a thread that

Page 227: Basic Java Handout

prints the numbers between -128 and 127.

public class BytePrinter extends Thread {

    public void run() {        for (int b = -128; b < 128; b++) {            System.out.println(b);        }        }    }You launch this thread from another method, probably in another class, by instantiating an object of this class using new and calling its start() method. To create a thread just call the default constructor for your subclass of Thread. For instance BytePrinter bp = new BytePrinter();This class only has the default, noargs constructor; but there's absolutely no reason you can't add other constructors to your Thread subclass.

Constructing a thread object puts it at the starting line. The bell goes off and the thread starts running when you call the thread's start() method like this:

bp.start(); Once the start() method is called program execution splits in two. Some CPU time goes into whatever statements follow bp.start() and some goes into the bp thread. It is unpredictable which statements will run first. Most likely they will be intermixed. The bp thread will now continue running until one of seven things happens

1 bp's run() method completes.

2 bp's stop() method is called.

Page 228: Basic Java Handout

3 bp's suspend() method is called.

4 bp's sleep() method is called.

5 bp's yield() method is called.

6 bp blocks waiting for an unavailable resource

7 Another thread preempts this thread.

Once program control reaches the end of bp's run() method the thread dies. It cannot be restarted, though you can create a new instance of the same Thread subclass and start that.

A simple thread

For example, the following program launches a single BytePrinter thread: public class ThreadTest {

    public static void main(String args[]) {

        System.out.println("Constructing the thread...");        BytePrinter bp = new BytePrinter();        System.out.println("Starting the thread...");        bp.start();        System.out.println("The thread has been started.");        System.out.println("The main() method is finishing.");        return;            }

}Here's some sample output: % java ThreadTestConstructing the thread...Starting the thread...

Page 229: Basic Java Handout

The thread has been started.The main() method is finishing.-128-127-126-125-124-123-122-121-120Of course this continues for a couple hundred more lines.

Multiple threads

The following program launches three BytePrinter threads: public class ThreadsTest {

    public static void main(String args[]) {            BytePrinter bp1 = new BytePrinter();        BytePrinter bp2 = new BytePrinter();        BytePrinter bp3 = new BytePrinter();        bp1.start();        bp2.start();        bp3.start();                }

}The order of the output you see from this program is implementation dependent, and mostly unpredictable. It may look something like this: -128

Page 230: Basic Java Handout

-127-126...125126127-128-127-126...125126127-128-127-126...125126127In this case the three threads run sequentially, one after the other. However on a few systems you may see something different

Multiple preemptive threads

However on a few systems you may see something like this: -128-127-126-125-124-123-128-127

Page 231: Basic Java Handout

-126-125-128-127-126-125-124-123-122-121-120-119-124-123...125126127In this case output from the three different threads is intermixed. Some systems use cooperative threads that require a thread to explicitly yield control before other, equal priority threads get a chance to run. Other systems use preemptive threading in which the virtual machine guarantees that all threads of the same priority get time in which to run. However, even on preemptive VMs this thread takes so little time to run it's unlikely any intermixing will occur.

Multiple preemptive threads

You will not on any system see something like this: -128-127-126-125-124

Page 232: Basic Java Handout

-12-128-127-126-125-128-127-126-125-1243-122-121-120-1-124-123...125126127It will always be the case that an entire line is or is not printed. There are no partial lines. This is because System.out.println() is thread-safe.

Naming Threads

It's often useful to give different threads in the same class names so you can tell them apart. The following constructor allows you to do that: public Thread(String name)This is normally called from the constructor of a subclass, like this: public class NamedBytePrinter extends Thread {

    public NamedBytePrinter(String name) {        super(name);    }

Page 233: Basic Java Handout

    public void run() {        for (int b = -128; b < 128; b++) {            System.out.println(this.getName() + ": " + b);        }        }    }The getName() method of the Thread class returns this value.

The following program now distinguishes the output of different threads:

public class NamedThreadsTest {

    public static void main(String[] args) {            NamedBytePrinter frank = new NamedBytePrinter("Frank");        NamedBytePrinter mary = new NamedBytePrinter("Mary");        NamedBytePrinter chris = new NamedBytePrinter("Chris");        frank.start();        mary.start();        chris.start();        }

}

Named Threads Output

For example, Frank: -128

Page 234: Basic Java Handout

Mary: -128Mary: -127Mary: -126Mary: -125Mary: -124Mary: -123Mary: -122Mary: -121Chris: -128Chris: -127Chris: -126Chris: -125Chris: -124Chris: -123Chris: -122Chris: -121Chris: -120Mary: -120Mary: -119Chris: -119Chris: -118Frank: -127Frank: -126Frank: -125...Mary: 121Mary: 122Mary: 123Chris: 127Frank: 123Frank: 124Frank: 125Mary: 124Mary: 125

Page 235: Basic Java Handout

Frank: 126Frank: 127Mary: 126Mary: 127Again, the exact ordering and even whether the thread output is intermixed, can vary from system to system and run to run.

Thread Priorities

Not all threads are created equal. Sometimes you want to give one thread more time than another. Threads that interact with the user should get very high priorities. On the other hand threads that calculate in the background should get low priorities.

Thread priorities are defined as integers between 1 and 10. Ten is the highest priority. One is the lowest. The normal priority is five. Higher priority threads get more CPU time.

Warning: This is exactly opposite to the normal UNIX way of prioritizing processes where the higher the priority number of a process, the less CPU time the process gets.

For your convenience java.lang.Thread defines three mnemonic constants, Thread.MAX_PRIORITY, Thread.MIN_PRIORITY and Thread.NORM_PRIORITY which you can use in place of the numeric values.

You set a thread's priority with the setPriority(int priority) method. The following program sets Chris's priority higher than Mary's whose priority is higher than Frank's. It is therefore likely that even though Chris starts last and Frank starts first, Chris will finish before Mary who will finish before Frank.

public class MixedPriorityTest {

Page 236: Basic Java Handout

    public static void main(String args[]) {            NamedBytePrinter frank = new NamedBytePrinter("Frank");        NamedBytePrinter mary = new NamedBytePrinter("Mary");        NamedBytePrinter chris = new NamedBytePrinter("Chris");        frank.setPriority(Thread.MIN_PRIORITY);        mary.setPriority(Thread.NORM_PRIORITY);        chris.setPriority(Thread.MAX_PRIORITY);        frank.start();        mary.start();        chris.start();    }}

Sleep

Sometimes the computer may run too fast for the human beings. If this is the case you need to slow it down. You can make a particular Thread slow down by interspersing it with calls to the Thread.sleep(ms) method. ms is the number of milliseconds you want the thread to wait before proceeding on. There are one thousand milliseconds in a second.

The sleep() method throws InterruptedExceptions. Therefore when you put a thread to sleep, you need to catch InterruptedExceptions. Thus every call to sleep() should be wrapped in a try catch block like this:

        try {            Thread.sleep(1000);        }        catch (InterruptedException e) {

Page 237: Basic Java Handout

                }To delay a program for a fixed amount of time you often do something like this:         try {            Thread.sleep(1000);        }        catch (InterruptedException e) {      }

Synchronization: the problem. part 1

So far all the threads have run independently of each other. One thread did not need to know what another thread was doing. Sometimes, however, threads need to share data. In this case it is important to ensure that one thread doesn't change the data while the other thread is executing. The classic example is file access. If one thread is writing to a file while another thread is reading the file, it's likely that the thread that's reading the file will get corrupt data.

For example, consider the following toy problem:

public class Counter {

    int i = 0;        public void count() {        int limit = i + 100;        while (i++ != limit)    System.out.println(i);     }

}public class CounterThread extends Thread {

    Counter c;   

Page 238: Basic Java Handout

    public static void main(String[] args) {            Counter c = new Counter();        CounterThread ct1 = new CounterThread(c);        CounterThread ct2 = new CounterThread(c);        ct1.start();        ct2.start();    }    public CounterThread(Counter c) {        this.c = c;    }    public void run() {        c.count();    }}Given these two classes what do you expect the output will be?

If you're reading this on the web before class, I really want you to think about this problem before moving on to the next page. Give it some real thought; then run the program and see if that is indeed what happens.

Synchronization: the problem, part 2

The fact is there's no guarantee what the output will be. The Roaster DR3 VM gave me the following output the first time I ran this program: 134567

Page 239: Basic Java Handout

891011...90919293949596979899100101102

Synchronization: the problem, part 3

The second time I ran it on the same VM it appeared to be caught in an infinite loop. The output looked like this: 134567891011...9091

Page 240: Basic Java Handout

9293949596979899100101102103104105...342343344345I didn't run it long enough to be sure, but my best guess is that it would have continued to run until it wrapped around into the negative numbers, then counted back up to 100, and then stopped.

Synchronization: the problem, part 4

Sun's JDK for the Mac 1.0.2 behaved similarly. However it skipped 7 and stopped at 107: 12345689

Page 241: Basic Java Handout

1011...9899100101102103104105106107Can you explain this behavior? How do you get an infinite loop one run, and termination the next with no external input to the program? Why do different VMs give different results? Why is this program non-deterministic? There are no calls to Math.random(). There's no user input. Nothing reads anything from the host machine such as the number of active processes running or the current time. It's just a simple counting program!

Synchronization: some solutions

The fundamental problem in the previous program was that there were two threads modifying the fields of the same object. Furthermore the order in which the fields were modified is indeterminate.

There are a number of possible solutions to this problem. Not all solutions are valid in all situations. For example, one of the simplest and most direct is to make the object immutable, that is not to allow it to change after it's been constructed. You can guarantee this by making all fields private, not providing any setter methods, and not

Page 242: Basic Java Handout

allowing any non-constructor method in the class to change the value of a field. However, this solution is inappropriate for this problem because the count() method must change the field i.

You can do a similar thing by declaring fields to be final. This way they can't be changed after the object is constructed. This isn't always practical, however.

In this example, it would be simple to make i a local variable instead of a field. This is a relatively uncommon solution (why?), but it does work for this case, primarily because this is a toy example.

public class Counter {

    public void count() {        int i = 0;        int limit = 100;        while (i++ != limit)    System.out.println(i);     }

}By making i a local variable instead of a field, each thread that invokes the count() method on this object gets a separate and different i. Each time a method is called, a separate stack frame is set up for its variables and arguments. Different invocations of a method do not share variables. However this has changed the meaning of the program. Now each thread counts from 0 to 100. If this is what was originally intended this is fine. However if the intention was for the first thread to count from 0 to 100 and the second thread to count from 101 to 200, then this solution's no good.

Synchronization: another solution

Page 243: Basic Java Handout

A somewhat more general solution that combines the previous two is to copy the value of the field into a local variable, then change only the local variable. The field remains unchanged inside the method. For example, public class Counter {

    int i = 0;

    public void count() {        int i = this.i;        int limit = i + 100;        while (i++ != limit) System.out.println(i);     }

}Note how the local variable i shadows the field i, and how the this keyword is used to refer to the field i outside the shadow.

This trick is primarily useful when you don't need to save the changed variable back into the field when the method is done. The following saves the state, but is still subject to less obvious synchronization problems.

public class Counter {

    int i = 0;

    public void count() {        int i = this.i;        int limit = i + 100;        while (i++ != limit) System.out.println(i);        this.i = i;     }

}

Page 244: Basic Java Handout

In fact, this is probably even worse than the original example because it will work 99 times out of a 100. The bug here is extremely hard to pin down if you don't spot it in the source code.

The synchronized keyword

Java does allow you to guarantee that no more than one thread at a time will run a method. Other threads will have to wait for the first thread to finish running. In the meantime they block, that is stop executing.

You do this by applying the synchronized keyword to the method, like this:

public class SychronizedCounter extends Counter {

    public synchronized void count() {        int limit = i + 100;        while (i++ != limit) System.out.println(i);    }

}However you don't want to synchronize lightly. This solution severely impacts performance. In general synchronized methods run three to ten times slower that the equivalent non-synchronized method.

Synchronization is not a panacea, either. There can still be thread related bugs in classes that have synchronized methods. There can also be non-thread related bugs. In fact there's one in this very class. Can you find it?

Synchronizing on Objects

Magic Feather example.

Each object has a magic feather called a monitor. When you use the synchronized keyword on a method, you're gaining the monitor of the current object or locking it. As

Page 245: Basic Java Handout

long as a thread possesses the monitor or lock of an object no other thread can get the lock for that object. (Another thread may be able to lock a different object in the same class, however.)

When you use the synchronized modifier to specify that a method is synchronized, you are locking on the particular object whose method is invoked. (Static methods can also be synchronized. In this case, the lock is placed on the java.lang.Class object associated with the object's class.) Since there's only one lock per object, it's not just the synchronized method that can't be invoked by other threads. It's any other synchronized method or block of code in that object.

You can synchronize at a lower level than a method. For example the following program had problems if another thread changed the value of i or this.i while the assignment was taking place.

public class Counter {

    int i = 0;

    public void count() {        int i = this.i;        int limit = i + 100;        while (i++ != limit)    System.out.println(i);        this.i = i;     }

}You can fix this by synchronizing the lines of code that refer to the field:     public void count() {        synchronized (this) {

Page 246: Basic Java Handout

            int i = this.i;        }        int limit = i + 100;        while (i++ != limit) System.out.println(i);        synchronized (this) {            this.i = i;         }    }

Synchronizing on Arbitrary Objects

In the previous example, I synchronized on the object itself, i.e. this. You can synchronize on other objects too. For example, the following static method uses a simple bubble sort to sort an array of ints. The sorting code synchronizes on the array to make sure that no other thread modifies the array while it's being sorted:     public static void bubbleSort(int[] n) {            boolean sorted = false;        synchronized(n) {            while (!sorted) {                sorted = true;                for (int i=0; i < n.length - 1; i++) {                    if (n[i] > n[i+1]) {                        int temp = n[i];                        n[i] = n[i+1];                        n[i+1] = temp;                        sorted = false;                    } // end if                  } // end for          } // end while      } // end synchronized      } // end sort Here you're not worried about this object being changed

Page 247: Basic Java Handout

by a different thread. After all, the method is static. You're worried that the array may be changed by a different thread, so that's what you synchronize.

You can synchronize arrays because they are objects, albeit a funny sort of object. You cannot synchronize primitive data types like int, float, or char.

You can synchronize strings because they're objects, but you don't need to because strings are immutable.

Also note that you don't know anything about what else is going on in the program. There may only be one thread that has access to this array. Then again, there might be dozens. Whether or not you need to synchronize a method like this requires you to know lots of details about where this method is going to be used. When you're writing general utility classes and methods, that may be used by many different programs, you must assume that different threads will call the method at the same time. The Java class library makes this assumption and is thread safe.

How many threads are there?

As a general rule, there are at least three threads executing in any Java program. First of all there's the main thread into which your program is running. This is the thread that includes the main() method that started your application. In an applet this will be the thread into which the applet viewer or web browser was launched.

Next, there's a low priority thread that handles garbage collection and runs finalizers.

In programs that use the AWT, there's also a screen updater thread that checks to see if anything needs to be repainted about 100 times a second.

Page 248: Basic Java Handout

Finally there are any threads your program has explicitly spawned. However you're program is always running in one thread or another. You're never outside the thread system. You can determine the currently executing thread with the static Thread.currentThread() method:

public static native Thread currentThread()For example, the following program prints the name of the primary thread of execution: public class PrimaryThread {    public static void main(String[] args) {        System.out.println(Thread.currentThread());    }}You use the currentThread() method to get a reference to the current thread so you can manipulate it.

Thread Groups

Threads are organized into thread groups. A thread group is simply a related collection of threads. For instance, for security reasons all the threads an applet spawns are members of a particular thread group. The applet is allowed to manipulate threads in its own group but not in others. Thus an applet can't turn off the system's garbage collection thread, for example.

Thread groups are organized into a hierarchy of parents and children.

The following program prints all active threads by using the getThreadGroup() method of java.lang.Thread and getParent() method of java.lang.ThreadGroup to walk up to the top level thread group; then using enumerate to list all the threads in the main thread group and its children (which covers all thread groups).

public class AllThreads {

Page 249: Basic Java Handout

    public static void main(String[] args) {

        ThreadGroup top = Thread.currentThread().getThreadGroup();        while(true) {            if (top.getParent() != null) top = top.getParent();            else break;        }        Thread[] theThreads = new Thread[top.activeCount()];        top.enumerate(theThreads);        for (int i = 0; i < theThreads.length; i++) {            System.out.println(theThreads[i]);        }

    }

}The exact list of threads varies from system to system, but it should look something like this: Thread[clock handler,11,system]Thread[idle thread,0,system]Thread[Async Garbage Collector,1,system]Thread[Finalizer thread,1,system]Thread[main,1,main]Thread[Thread-0,5,main]

Daemon Threads

Threads that work in the background to support the runtime environment are called daemon threads. For example, the clock handler thread, the idle thread, the garbage collector thread, the screen updater thread, and the garbage collector thread are all daemon threads. The virtual machine exits whenever all non-daemon threads

Page 250: Basic Java Handout

have completed.     public final void setDaemon(boolean isDaemon)    public final boolean isDaemon()By default a thread you create is not a daemon thread. However you can use the setDaemon(true) method to turn it into one.

Cooperative vs. Preemptive Threading

In cooperative models, once a thread is given control it continues to run until it explicitly yields control or it blocks. In a preemptive model, the virtual machine is allowed to step in and hand control from one thread to another at any time. Both models have their advantages and disadvantages.

Java threads are generally preemptive between priorities. A higher priority thread takes precedence over a lower priority thread. If a higher priority thread goes to sleep or blocks, then a lower priority thread can be run (assuming one is available and ready to be run). However, as soon as the higher priority thread wakes up or unblocks, it will interrupt the lower priority thread and run until it finishes, it or blocks again, or until it is preempted by an even higher priority thread.

The Java Language Specification allows VMs to occasionally run a lower priority thread instead of a runnable higher priority thread, but in practice this is unusual.

However, nothing in the Java Language Specification specifies what is supposed to happen with equal priority threads. On some systems these threads will be time-sliced, and the runtime will allot a certain amount of time to a thread. When that time is up, the runtime preempts the running thread and switches to the next

Page 251: Basic Java Handout

thread with the same priority. On other systems, a running thread will not be preempted in favor of a thread with the same priority. It will continue to run until it blocks, explicitly yields control, or is preempted by a higher priority thread.

Cooperating

Since you can't be sure whether you'll be working with a cooperative or preemptive model, it's important not to assume preemption is available. CPU- intensive threads should yield control at periodic intervals. There are four different ways a thread can give up control and allow other threads to run.

1 It can block.

2 It can call Thread.yield().

3 It can go to sleep.

4 It can be suspended.

Blocking occurs when a thread has to wait for an operation to complete. Most commonly this is an I/O operation, particularly one involving a network connection. It's also possible for a call to block while waiting for user input. Placing I/O and user input in separate, high priority threads is often a good idea because it allows the computer to be used more efficiently. Other CPU intensive threads can get a lot of work done while waiting for data to come in over the network or the user to type a character or two.

When a program calls Thread.yield(), it's signifying that the current thread, the one which called Thread.yield(), is willing to step aside in favor of another thread. The VM looks to see if any other threads of the same priority are ready to run. If any are, it pauses the currently

Page 252: Basic Java Handout

executing thread and passes control to the next thread in line. If no other threads of the same or higher priority are ready to run, control returns to the thread that yielded. Thus Thread.yield() only signals a willingness to give up control. It does not guarantee that the thread will actually stop. That depends completely on what other threads exist and what their status is.

If a thread definitely wants to give up control for a period of time, whether or not there are any other threads of equal or higher priority ready to run, then it can call sleep(). The sleep() methods put a thread to sleep for a certain amount of time during which even lower priority threads may have an opportunity to run.

public static void sleep(long milliseconds) throws InterruptedExceptionpublic static void sleep(long milliseconds, int nanoseconds) throws InterruptedExceptionFinally, a thread can be suspended. When a thread calls suspend() (or more commonly when a different thread invokes the thread's suspend() method), it is paused indefinitely until some other thread starts it running again by invoking its resume() method. public final void suspend()public final void resume()

Suspend and Resume

The suspend() method temporarily halts a running thread. The resume() method picks up execution of the thread where it left off. public final void suspend() public final void resume()

Joining Threads

The three overloaded join() methods block the calling

Page 253: Basic Java Handout

thread until the thread whose join() method is invoked dies.     public final void join() throws InterruptedException     public final void join(long milliseconds) throws InterruptedException     public final void join(long milliseconds, int nanoseconds)       throws InterruptedException For example, t.join() waits for the Thread t to finish before continuing. t.join(1000) waits at most one second for t to finish before continuing.

You would generally use this when one thread depends on another, for example for a file to be read or an image to be loaded from the net.

The Runnable interface

So far all the threads you've seen have been subclasses of java.lang.Thread. Sometimes, however, you want to add threading to a class that already inherits from a class other than Thread. The most common such occurrence is when you want to add threading to an applet. The easiest way to improve the perceived performance of an applet is to implement the java.lang.Runnable interface.

The Runnable interface declares just one method, run().

public void run()Your class needs to implement this method just as it would if it were a subclass of Thread and declare that it implements the Runnable interface like this: public class MyThreadedClass extends SomeClass implements Runnable {          .          .          .   

Page 254: Basic Java Handout

    public void run() {                  .                  .                  .        }

}To start the threaded object create a new Thread and pass the Runnable object to the Thread constructor. Then call the Thread's start() method like this: MyThreadedClass mtc = new MyThreadedClass();Thread t = new Thread(mtc);t.start();

Java Applet Programming

HTML Overview

HTML is the HyperText Markup Language.

HTML files are text files featuring semantically tagged elements.

HTML filenames are suffixed with .htm or .html.

Here's a simple HTML file:

<html><head><title>My First HTML Document</title></head><body><h1>A level one heading</h1>

Hello there. This is <STRONG>very</STRONG> important.

</body>

Page 255: Basic Java Handout

</html>

Look at this file in your web browser.

Elements that are enclosed in angle brackets like <html>, <head>, and <title> are called tags. Tags are case insensitive. <html> means the same thing as <HTML> as <Html> <HtMl>.

Most tags are matched with closing tags, and affect the text contained between them. The closing tag is the same as the opening tag except for a / after the opening angle bracket. For example, </html>, </head>, and </title> are closing tags. The text in between <title> and </title>, My First HTML Document in the above example, is the title of the page.

As you can see from the above example tags may, in general, nest. However they may not overlap (though some browsers can handle this).

Some tags have attributes. An attribute is a name, followed by an = sign, followed by the value. For example, to make a centered H1 heading, use the ALIGN attribute with value center; i.e.

<h1 align="center">A level one heading</h1>Attributes are also case-insensitive. The double quotes around the value are optional unless the value contains embedded white space.

URLs Overview

URL stands for uniform resource locator. A URL is a pointer to a particular resource on the Internet at a particular location. For example http://metalab.unc.edu/javafaq/course/week5/exercises.html and ftp://ftp.macfaq.com/pub/macfaq/ are both URLs.

Page 256: Basic Java Handout

A URL specifies the protocol used to access a server (e.g., ftp, http), the name of the server, and the location of a file on that server. A typical URL looks like http://metalab.unc.edu/javafaq/books.html. This specifies that there is a file called books.html in a directory called javafaq on the server metalab.unc.edu, and that this file can be accessed via the http protocol. The full syntax is:

protocol://hostname[:port]/path/filename#section

The protocol, also sometimes called the scheme, is generally one of these

file a file on your local disk

ftp an FTP server

http a World Wide Web server

gopher a Gopher server

mailto an email address

news a Usenet newsgroup

telnet a connection to a Telnet-based service

WAIS a WAIS server

A few other protocols are occasionally encountered including rmi (remote method invocation) and https (secure http).

The parts of a URL

The hostname part of the URL should be a valid Internet hostname like www.ora.com or shock.njit.edu. It can also

Page 257: Basic Java Handout

be an IP address like 204.29.207.217 or 128.235.252.184.

The port number is optional. It's not necessary if the service is running on the default port, 80 for http servers.

The path points to a particular directory on the specified server. The path is relative to the document root of the server, not necessarily to the root of the file system on the server. In general a server, especially one open to the public, does not show its entire file system to clients. Rather it shows only the contents of a specified directory. This directory is called the server root, and all paths and filenames are relative to it. Thus on a Unix workstation all files that are available to the public may be in /var/public/html, but to somebody connecting from a remote machine this directory looks like the root of the file system.

The filename points to a particular file in the directory specified by the path. It is often omitted in which case it is left to the server's discretion what file, if any, to send. Many servers will send an index file for that directory, often called index.html or Welcome.html. Others will send a list of the files in the directory. Others may send an error message.

Section is used to reference a named anchor in an HTML document. Some documents refer to the section part of the URL as a "fragment." A named anchor is created in HTML document with a name tag like this

<A NAME="xtocid1902914">Comments</A>

Links Overview

To make a hypertext link, you surround the text you want to be linked with <A></A> tags. Inside the <A> tag

Page 258: Basic Java Handout

place an HREF attribute whose value is the URL you want to link too. For example, Make sure you get the <A HREF="http://………………../xyz.html">    exercises</A> from the web site.Most browsers will underline the linked text, and color it blue or purple, but this is a presentation decision left up to the browser. The browser also provides the user with a means to activate the link (normally by clicking on the linked text). When the user activates the link, the browsers attempts to load the page specified in the link. If the URL in the anchor is not an HTTP URL, then the browser will take whatever action is appropriate, perhaps saving a file for an ftp URL or launching an email program for a mailto URL.

Relative URLsWhen a web browser reads an HTML document, it has a great deal of information about the document. This includes the protocol used to retrieve the document, the name of the host where the document lives, and the path to that document on the host. Most of this is likely to be the same for many of the URLs in that document. Relative URLs inherit the protocol, hostname, and path of their parent document rather than respecifying it in each <A HREF> tag. Thus if any piece of the URL is missing, it is assumed to be the same as that of the document in which the URL is found. Such a URL is called a relative URL. In contrast, a completely specified URL is called an absolute URL.

If the relative link begins with a /, then it is relative to the document root instead of relative to the current file.

Page 259: Basic Java Handout

Relative URLs have a number of advantages. First and least they save a little typing. More importantly relative URLs allow entire trees of HTML documents to be moved or copied from one site to another without breaking all the internal links.

Applet Basics

Hello World: The Applet

The reason people are excited about Java as more than just another OOP language is because it allows them to write interactive applets on the web. Hello World isn't a very interactive program, but let's look at a webbed version. import java.applet.Applet;      import java.awt.Graphics; public class HelloWorldApplet extends Applet {    public void paint(Graphics g) {        g.drawString("Hello world!", 50, 25);    }} The applet version of HelloWorld is a little more complicated than the HelloWorld application, and it will take a little more effort to run it as well.

First type in the source code and save it into file called HelloWorldApplet.java. Compile this file in the usual way. If all is well a file called HelloWorldApplet.class will be created. Now you need to create an HTML file that will include your applet. The following simple HTML file will do.

Page 260: Basic Java Handout

<HTML><HEAD><TITLE> Hello World </TITLE></HEAD>

<BODY>This is the applet:<P><applet code="HelloWorldApplet.class" width="150" height="50"></applet></BODY></HTML>Save this file as HelloWorldApplet.html in the same directory as the HelloWorldApplet.class file. When you've done that, load the HTML file into a Java enabled browser like Internet Explorer 4.0 or Sun's applet viewer included with the JDK.

If the applet compiled without error and produced a HelloWorldApplet.class file, and yet you don't see the string "Hello World" in your browser chances are that the .class file is in the wrong place. Make sure HelloWorldApplet.class is in the same directory as HelloWorld.html. Also make sure that you're using a version of Netscape or Internet Explorer which supports Java. Not all versions do.

In any case Netscape's Java support is less than the perfect so if you have trouble with an applet, the first thing to try is loading it into Sun's Applet Viewer instead. If the Applet Viewer has a problem, then chances are pretty good the problem is with the applet and not with the browser.

What is an Applet?

According to Sun "An applet is a small program that is

Page 261: Basic Java Handout

intended not to be run on its own, but rather to be embedded inside another application....The Applet class provides a standard interface between applets and their environment."

Four definitions of applet:

1 A small application

2 A secure program that runs inside a web browser

3 A subclass of java.applet.Applet

4 An instance of a subclass of java.applet.Applet

public class Applet extends Panel java.lang.Object      |      +----java.awt.Component                      |                      +----java.awt.Container                                      |                                      +----java.awt.Panel                                                      |                                                      +----java.applet.Applet

The APPLET HTML Tag

Applets are embedded in web pages using the <APPLET> and </APPLET> tags. The <APPLET> tag is similar to the <IMG> tag. Like <IMG> <APPLET> references a source file that is not part of the HTML page on which it is embedded. IMG elements do this with the SRC attribute. APPLET elements do this with the CODE attribute. The CODE attribute tells the browser where to look for the compiled .class file. It is relative to the location of the source document. Thus if you're browsing http://metalab.unc.edu/javafaq/index.html and that page references an applet with

Page 262: Basic Java Handout

CODE="Animation.class", then the file Animation.class should be at the URL http://metalab.unc.edu/javafaq/animation.class.

For reasons that remain a mystery to HTML authors everywhere if the applet resides somewhere other than the same directory as the page it lives on, you don't just give a URL to its location. Rather you point at the CODEBASE. The CODEBASE attribute is a URL that points at the directory where the .class file is. The CODE attribute is the name of the .class file itself. For instance if on the HTML page of the previous section you had written

<APPLET CODE="HelloWorldApplet.class" CODEBASE="classes" WIDTH=200 HEIGHT=200></APPLET>then the browser would have tried to find HelloWorldApplet.class in the classes directory in the same directory as the HTML page that included the applet. On the other hand if you had written <APPLET CODE="HelloWorldApplet.class" CODEBASE="http://www.foo.bar.com/classes" WIDTH=200 HEIGHT=200></APPLET>then the browser would try to retrieve the applet from http://www.foo.bar.com/classes/HelloWorldApplet.class regardless of where the HTML page was.

In short the applet viewer will try to retrieve the applet from the URL given by the formula (CODEBASE + "/" + code). Once this URL is formed all the usual rules about relative and absolute URLs apply.

You can leave off the .class extension and just use the class name in the CODE attribute. For example,

Page 263: Basic Java Handout

<APPLET CODE="HelloWorldApplet" CODEBASE="http://www.foo.bar.com/classes" WIDTH=200 HEIGHT=200></APPLET>If the applet is in a non-default package, then the full package qualified name must be used. For example, <APPLET CODE="com.macfaq.greeting.HelloWorldApplet" CODEBASE="http://www.foo.bar.com/classes" WIDTH=200 HEIGHT=200></APPLET>In this case the browser will look for http://www.foo.bar.com/classes/com/macfaq/greeting/HelloWorldApplet.class so the directory structure on the server should also mirror the package hierarchy.

The HEIGHT and WIDTH attributes work exactly as they do with IMG, specifying how big a rectangle the browser should set aside for the applet. These numbers are specified in pixels and are required

Spacing Preferences

The <APPLET> tag has several attributes to define how it is positioned on the page.

The ALIGN attribute defines how the applet's rectangle is placed on the page relative to other elements. Possible values include LEFT, RIGHT, TOP, TEXTTOP, MIDDLE, ABSMIDDLE, BASELINE, BOTTOM and ABSBOTTOM. This attribute is optional.

You can specify an HSPACE and a VSPACE in pixels to set the amount of blank space between an applet and the surrounding text. The HSPACE and VSPACE attributes are optional.

<applet code="HelloWorldApplet.class"

Page 264: Basic Java Handout

CODEBASE="http://www.foo.bar.com/classes" width=200 height=200ALIGN=RIGHT HSPACE=5 VSPACE=10></APPLET>The ALIGN, HSPACE, and VSPACE attributes are identical to the attributes of the same name used by the <IMG> tag.

Alternate Text

The <APPLET> has an ALT attribute. An ALT attribute is used by a browser that understands the APPLET tag but for some reason cannot play the applet. For instance, if you've turned off Java in Netscape Navigator 3.0, then the browser should display the ALT text. Note that I said it should, not that it does. The ALT tag is optional. <applet code="HelloWorldApplet.class" CODEBASE="http://www.foo.bar.com/classes" width=200 height=200ALIGN=RIGHT HSPACE=5 VSPACE=10ALT="Hello World!"></APPLET>ALT is not used by browsers that do not understand <APPLET> at all. For that purpose <APPLET> has been defined to require a closing tag, </APPLET>. All raw text between the opening and closing <APPLET> tags is ignored by a Java capable browser. However a non-Java capable browser will ignore the <APPLET> tags instead and read the text between them. For example the following HTML fragment says Hello to people both with and without Java capable browsers. <applet code="HelloWorldApplet.class" CODEBASE="http://www.foo.bar.com/classes" width=200 height=200ALIGN=RIGHT HSPACE=5 VSPACE=10ALT="Hello World!">

Page 265: Basic Java Handout

Hello World!<P></APPLET>

Naming Applets

You can give an applet a name by using the NAME attribute of the APPLET tag. This allows communication between different applets on the same Web page. <applet code="HelloWorldApplet.class" Name=Applet1CODEBASE="http://www.foo.bar.com/classes" width=200 height=200ALIGN=RIGHT HSPACE=5 VSPACE=10ALT="Hello World!">Hello World!<P></APPLET>

JAR Archives

HTTP 1.0 uses a separate connection for each request. When you're downloading many small files, the time required to set up and tear down the connections can be a significant fraction of the total amount of time needed to load a page. It would be better if you could load all the HTML documents, images, applets, and sounds a page needed in one connection.

One way to do this without changing the HTTP protocol, is to pack all those different files into a single archive file, perhaps a zip archive, and just download that.

We aren't quite there yet. Browsers do not yet understand archive files, but in Java 1.1 applets do. You can pack all the images, sounds, and .class files an applet needs into one JAR archive and load that instead of the individual files. Applet classes do not have to be loaded directly. They can also be stored in JAR archives. To do this you use the ARCHIVES attribute of the APPLET tag

Page 266: Basic Java Handout

<APPLET CODE=HelloWorldApplet WIDTH=200 HEIGHT=100 ARCHIVES="HelloWorld.jar"><hr>Hello World!<hr></APPLET>In this example, the applet class is still HelloWorldApplet. However, there is no HelloWorldApplet.class file to be downloaded. Instead the class is stored inside the archive file HelloWorld.jar.

The OBJECT Tag

HTML 4.0 deprecates the <APPLET> tag. Instead you are supposed to use the <OBJECT> tag. For the purposes of ewbedding applets, the <OBJECT> tag is used almost exactly like the <APPLET> tag except that the class attribute becomes the classid attribute. For example, <OBJECT classid="MyApplet.class" CODEBASE="http://www.foo.bar.com/classes" width=200 height=200ALIGN=RIGHT HSPACE=5 VSPACE=10></OBJECT>The <OBJECT> tag is also used to embed ActiveX controls and other kinds of active content, and it has a few additional attributes to allow it to do that. However, for the purposes of Java you don't need to know about these.

The <OBJECT> tag is supported by Netscape ???? and later and Internet Explorer ???? and later. It is not supported by earlier versions of those browsers so <APPLET> is unlikely to disappear anytime soon.

Page 267: Basic Java Handout

You can support both by placing an <APPLET> element inside an <OBJECT> element like this:

<OBJECT classid="MyApplet.class" width=200 height=200><APPLET code="MyApplet.class" width=200 height=200></APPLET></OBJECT>Browsers that understand <OBJECT> will ignore its content while browsers that don't will display its content.

PARAM elements are the same for <OBJECT> as for <APPLET>.

Finding an Applet's Size

When running inside a web browser the size of an applet is set by the height and width attributes and cannot be changed by the applet. Many applets need to know their own size. After all you don't want to draw outside the lines. :-)

Retrieving the applet size is straightforward with the getSize() method. java.applet.Applet inherits this method from java.awt.Component. getSize() returns a java.awt.Dimension object. A Dimension object has two public int fields, height and width. Below is a simple applet that prints its own dimensions.

import java.applet.*;        import java.awt.*;public class SizeApplet extends Applet {    public void paint(Graphics g) {        Dimension appletSize = this.getSize();        int appletHeight = appletSize.height;        int appletWidth = appletSize.width;        g.drawString("This applet is " + appletHeight +

Page 268: Basic Java Handout

            " pixels high by " + appletWidth + " pixels wide.",             15, appletHeight/2);            }}

Note how the applet's height is used to decide where to draw the text. You'll often want to use the applet's dimensions to determine how to place objects on the page. The applet's width wasn't used because it made more sense to left justify the text rather than center it. In other programs you'll have occasion to use the applet width too.

Passing Parameters to Applets

Parameters are passed to applets in NAME=VALUE pairs in <PARAM> tags between the opening and closing APPLET tags. Inside the applet, you read the values passed through the PARAM tags with the getParameter() method of the java.applet.Applet class.

The program below demonstrates this with a generic string drawing applet. The applet parameter "Message" is the string to be drawn.

import java.applet.*;        import java.awt.*; public class DrawStringApplet extends Applet {    public void paint(Graphics g) {        String inputFromPage = this.getParameter("Message");        g.drawString(inputFromPage, 50, 25);    }} You also need an HTML file that references your applet. The following simple HTML file will do: <HTML>

Page 269: Basic Java Handout

<HEAD><TITLE> Draw String </TITLE></HEAD>

<BODY>This is the applet:<P><APPLET code="DrawStringApplet.class" width="300" height="50"><PARAM name="Message" value="Howdy, there!">This page will be very boring if your browser doesn't understand Java.</APPLET></BODY></HTML> Of course you are free to change "Howdy, there!" to a "message" of your choice. You only need to change the HTML, not the Java source code. PARAMs let you customize applets without changing or recompiling the code.

This applet is very similar to the HelloWorldApplet. However rather than hardcoding the message to be printed it's read into the variable inputFromPage from a PARAM in the HTML.

You pass getParameter() a string that names the parameter you want. This string should match the name of a <PARAM> tag in the HTML page. getParameter() returns the value of the parameter. All values are passed as strings. If you want to get another type like an integer, then you'll need to pass it as a string and convert it to the type you really want.

The <PARAM> HTML tag is also straightforward. It occurs between <APPLET> and </APPLET>. It has two attributes of its own, NAME and VALUE. NAME

Page 270: Basic Java Handout

identifies which PARAM this is. VALUE is the value of the PARAM as a String. Both should be enclosed in double quote marks if they contain white space.

An applet is not limited to one PARAM. You can pass as many named PARAMs to an applet as you like. An applet does not necessarily need to use all the PARAMs that are in the HTML. Additional PARAMs can be safely ignored.

Processing An Unknown Number Of Parameters

Most of the time you have a fairly good idea of what parameters will and won't be passed to your applet. However some of the time there will be an undetermined number of parameters. For instance Sun's imagemap applet passes each "hot button" as a parameter. Different imagemaps have different numbers of hot buttons. Another applet might want to pass a series of URL's to different sounds to be played in sequence. Each URL could be passed as a separate parameter.

Or perhaps you want to write an applet that displays several lines of text. While it would be possible to cram all this information into one long string, that's not too friendly to authors who want to use your applet on their pages. It's much more sensible to give each line its own <PARAM> tag. If this is the case, you should name the tags via some predictable and numeric scheme. For instance in the text example the following set of <PARAM> tags would be sensible:

<PARAM name="Line1" value="There once was a man from Japan"><PARAM name="Line2" value="Whose poetry never would scan"><PARAM name="Line3" value="When asked reasons why,">

Page 271: Basic Java Handout

<PARAM name="Line4" value="He replied, with a sigh:"><PARAM name="Line5" value="I always try to get as many syllables into the last line as I can.">The program below displays this limerick. Lines are accumulated into an array of strings called poem. A for loop fills the array with the different lines of poetry. There are 101 spaces in the array, but since you won't normally need that many, an if clause tests to see whether the attempt to get a parameter was successful by checking to see if the line is null. As soon as one fails, the loop is broken. Once the loop is finished num_lines is decremented by one because the last line the loop tried to read wasn't there.

The paint() method loops through the poem array and prints each String on the screen, incrementing the y position by fifteen pixels each step so you don't draw one line on top of the other.

Processing An Unknown Number Of Parameters

import java.applet.*;        import java.awt.*;                           public class PoetryApplet extends Applet {

    String[] poem = new String[101];    int numlines;

    public void init() {

        String nextline;

        for (numlines = 1; numlines < poem.length;

Page 272: Basic Java Handout

numlines++) {            nextline = this.getParameter("Line" + numlines);            if (nextline == null) break;            poem[numlines] = nextline;        }        numlines--;          }        public void paint(Graphics g) {            int y = 15;            for (int i=1; i <= numlines; i++) {            g.drawString(poem[i], 5, y);                    y += 15;        }            }    }

You might think it would be useful to be able to process an arbitrary list of parameters without knowing their names in advance, if nothing else so you could return an error message to the page designer. Unfortunately there's no way to do it in Java 1.0 or 1.1. It may appear in future versions.

Applet Security

The possibility of surfing the Net, wandering across a random page, playing an applet and catching a virus is a fear that has scared many uninformed people away from Java. This fear has also driven a lot of the development of Java in the direction it's gone. Earlier I discussed various

Page 273: Basic Java Handout

security features of Java including automatic garbage collection, the elimination of pointer arithmetic and the Java interpreter. These serve the dual purpose of making the language simple for programmers and secure for users. You can surf the web without worrying that a Java applet will format your hard disk or introduce a virus into your system.

In fact both Java applets and applications are much safer in practice than code written in traditional languages. This is because even code from trusted sources is likely to have bugs. However Java programs are much less susceptible to common bugs involving memory access than are programs written in traditional languages like C. Furthermore the Java runtime environment provides a fairly robust means of trapping bugs before they bring down your system. Most users have many more problems with bugs than they do with deliberately malicious code. Although users of Java applications aren't protected from out and out malicious code, they are largely protected from programmer errors.

Applets implement additional security restrictions that protect users from malicious code too. This is accomplished through the java.lang.SecurityManager class. This class is subclassed to provide different security environments in different virtual machines. Regrettably implementing this additional level of protection does somewhat restrict the actions an applet can perform. Let's explore exactly what an applet can and cannot do.

What Can an Applet Do?

An applet can:

1 Draw pictures on a web page

Page 274: Basic Java Handout

2 Create a new window and draw in it.

3 Play sounds.

4 Receive input from the user through the keyboard or the mouse.

5 Make a network connection to the server from which it came and can send to and receive arbitrary data from that server.

Anything you can do with these abilities you can do in an applet. An applet cannot:

1 Write data on any of the host's disks.

2 Read any data from the host's disks without the user's permission. In some environments, notably Netscape, an applet cannot read data from the user's disks even with permission.

3 Delete files

4 Read from or write to arbitrary blocks of memory, even on a non-memory-protected operating system like the MacOS. All memory access is strictly controlled.

5 Make a network connection to a host on the Internet other than the one from which it was downloaded.

6 Call the native API directly (though Java API calls may eventually lead back to native API calls).

7 Introduce a virus or trojan horse into the host system.

8 An applet is not supposed to be able to crash the host system. However in practice Java isn't quite stable enough to make this claim yet.

Page 275: Basic Java Handout

Who Can an Applet Talk To?

By default an applet can only open network connections to the system from which the applet was downloaded. This system is called the codebase. An applet cannot talk to an arbitrary system on the Internet. Any communication between different client systems must be mediated through the server.

The concern is that if connections to arbitrary hosts were allowed, then a malicious applet might be able to make connections to other systems and launch network based attacks on other machines in an organization's internal network. This would be an especially large problem because the machine's inside a firewall may be configured to trust each other more than they would trust any random machine from the Internet. If the internal network is properly protected by a firewall, this might be the only way an external machine could even talk to an internal machine. Furthermore arbitrary network connections would allow crackers to more easily hide their true location by passing their attacks through several applet intermediaries.

HotJava, Sun's applet viewer, and Internet Explorer (but not Netscape) let you grant applets permission to open connections to any system on the Internet, though this is not enabled by default.

How much CPU time does an applet get?

One of the few legitimate concerns about hostile applets is excessive use of CPU time. It is possible on a non-preemptively multitasking system (specifically the Mac) to write an applet that uses so much CPU time in a tight loop that it effectively locks up the host system. This is not a problem on preemptively multitasking systems like

Page 276: Basic Java Handout

Solaris and Windows NT. Even on those platforms, though, it is possible for an applet to force the user to kill their web browser, possibly losing accumulated bookmarks, email and other work.

It's also possible for an applet to use CPU time for purposes other than the apparent intent of the applet. For instance, a popular applet could launch a Chinese lottery attack on a Unix password file. A popular game applet could launch a thread in the background which tried a random assortment of keys to break a DES encrypted file. If the key was found, then a network connection could be opened to the applet server to send the decrypted key back. The more popular the applet was the faster the key would be found. The ease with which Java applets are decompiled would probably mean that any such applet would be discovered, but there really isn't a way to prevent it from running in the first place.

User Security Issues and Social Engineering

Contrary to popular belief most computer break-ins by external hackers don't happen because of great knowledge of operating system internals and network protocols. They happen because a hacker went digging through a company's garbage and found a piece of paper with a password written on it, or perhaps because they talked to a low-level bureaucrat on the phone, convinced this person they were from the local data processing department and that they needed him or her to change their password to "DEBUG."

This is sort of attack is called social engineering. Java applets introduce a new path for social engineering. For instance imagine an applet that pops up a dialog box that says, "You have lost your connection to the network.

Page 277: Basic Java Handout

Please enter your username and password to reconnect." How many people would blindly enter their username and password without thinking? Now what if the box didn't really come from a lost network connection but from a hacker's applet? And instead of reconnecting to the network (a connection that was never lost in the first place) the username and password was sent over the Internet to the cracker? See the problem?

Preventing Applet Based Social Engineering Attacks

To help prevent this, Java applet windows are specifically labeled as such with an ugly bar that says: "Warning: Applet Window" or "Unsigned Java Applet Window." The exact warning message varies from browser to browser but in any case should be enough to prevent the more obvious attacks on clueless users. It still assumes the user understands what "Unsigned Java Applet Window" means and that they shouldn't type their password or any sensitive information in such a window. User education is the first part of any real security policy.

The Basic Applet Life Cycle

1. The browser reads the HTML page and finds any <APPLET> tags.

2. The browser parses the <APPLET> tag to find the CODE and possibly CODEBASE attribute.

Page 278: Basic Java Handout

3. The browser downloads the .class file for the applet from the URL found in the last step.

4. The browser converts the raw bytes downloaded into a Java class, that is a java.lang.Class object.

5. The browser instantiates the applet class to form an applet object. This requires the applet to have a noargs constructor.

6. The browser calls the applet's init() method.

7. The browser calls the applet's start() method.

8. While the applet is running, the browser passes any events intended for the applet, e.g. mouse clicks, key presses, etc., to the applet's handleEvent() method. Update events are used to tell the applet that it needs to repaint itself.

9. The browser calls the applet's stop() method.

10. The browser calls the applet's destroy() method.

All applets have the following four methods: public void init();public void start();public void stop();public void destroy();They have these methods because their superclass, java.applet.Applet, has these methods. (It has others too, but right now I just want to talk about these four.)

In the superclass, these are simply do-nothing methods. For example,

public void init() {}

Subclasses may override these methods to accomplish certain tasks at certain times. For instance, the init()

Page 279: Basic Java Handout

method is a good place to read parameters that were passed to the applet via <PARAM> tags because it's called exactly once when the applet starts up. However, they do not have to override them. Since they're declared in the superclass, the Web browser can invoke them when it needs to without knowing in advance whether the method is implemented in the superclass or the subclass. This is a good example of polymorphism.

init(), start(), stop(), and destroy()

The init() method is called exactly once in an applet's life, when the applet is first loaded. It's normally used to read PARAM tags, start downloading any other images or media files you need, and set up the user interface. Most applets have init() methods.

The start() method is called at least once in an applet's life, when the applet is started or restarted. In some cases it may be called more than once. Many applets you write will not have explicit start()methods and will merely inherit one from their superclass. A start() method is often used to start any threads the applet will need while it runs.

The stop() method is called at least once in an applet's life, when the browser leaves the page in which the applet is embedded. The applet's start() method will be called if at some later point the browser returns to the page containing the applet. In some cases the stop() method may be called multiple times in an applet's life. Many applets you write will not have explicit stop()methods and will merely inherit one from their superclass. Your applet should use the stop() method to pause any running threads. When your applet is stopped, it should not use any CPU cycles.

Page 280: Basic Java Handout

The destroy() method is called exactly once in an applet's life, just before the browser unloads the applet. This method is generally used to perform any final clean-up. For example, an applet that stores state on the server might send some data back to the server before it's terminated. many applets will not have explicit destroy() methods and just inherit one from their superclass.

For example, in a video applet, the init() method might draw the controls and start loading the video file. The start() method would wait until the file was loaded, and then start playing it. The stop() method would pause the video, but not rewind it. If the start() method were called again, the video would pick up where it left off; it would not start over from the beginning. However, if destroy() were called and then init(), the video would start over from the beginning.

In the JDK's appletviewer, selecting the Restart menu item calls stop() and then start(). Selecting the Reload menu item calls stop(), destroy(), and init(), in that order. (Normally the byte codes will also be reloaded and the HTML file reread though Netscape has a problem with this.)

The applet start() and stop() methods are not related to the similarly named methods in the java.lang.Thread class.

Your own code may occasionally invoke start() and stop(). For example, it's customary to stop playing an animation when the user clicks the mouse in the applet and restart it when they click the mouse again.

Your own code can also invoke init() and destroy(), but this is normally a bad idea. Only the environment should call init() and destroy().

Page 281: Basic Java Handout

The Coordinate System

Java uses the standard, two-dimensional, computer graphics coordinate system. The first visible pixel in the upper left-hand corner of the applet canvas is (0, 0). Coordinates increase to the right and down.

Graphics Objects

In Java all drawing takes place via a Graphics object. This is an instance of the class java.awt.Graphics.

Initially the Graphics object you use will be the one passed as an argument to an applet's paint() method. Later you'll see other Graphics objects too. Everything you learn today about drawing in an applet transfers directly to drawing in other objects like Panels, Frames, Buttons, Canvases and more.

Each Graphics object has its own coordinate system, and all the methods of Graphics including those for drawing Strings, lines, rectangles, circles, polygons and more. Drawing in Java starts with particular Graphics object.

Page 282: Basic Java Handout

You get access to the Graphics object through the paint(Graphics g) method of your applet. Each draw method call will look like g.drawString("Hello World", 0, 50) where g is the particular Graphics object with which you're drawing.

For convenience's sake in this lecture the variable g will always refer to a preexisting object of the Graphics class. As with any other method you are free to use some other name for the particular Graphics context, myGraphics or appletGraphics perhaps.

Drawing Lines

Drawing straight lines with Java is easy. Just call g.drawLine(x1, y1, x2, y2) where (x1, y1) and (x2, y2) are the endpoints of your lines and g is the Graphics object you're drawing with.

This program draws a line diagonally across the applet.

import java.applet.*;        import java.awt.*;

public class SimpleLine extends Applet {

public void paint(Graphics g) {         g.drawLine(0, 0, this.getSize().width, this.getSize().height);    }}

Drawing Rectangles

Drawing rectangles is simple. Start with a Graphics object g and call its drawRect() method: public void drawRect(int x, int y, int width, int height)

Page 283: Basic Java Handout

As the variable names suggest, the first int is the left hand side of the rectangle, the second is the top of the rectangle, the third is the width and the fourth is the height. This is in contrast to some APIs where the four sides of the rectangle are given.

This uses drawRect() to draw a rectangle around the sides of an applet.

import java.applet.*;        import java.awt.*; public class RectangleApplet extends Applet {    public void paint(Graphics g) {        g.drawRect(0, 0, this.getSize().width - 1, this.getSize().height - 1);    }}

Remember that getSize().width is the width of the applet and getSize().height is its height.

Why was the rectangle drawn only to getSize().height-1 and getSize().width-1?

Remember that the upper left hand corner of the applet starts at (0, 0), not at (1, 1). This means that a 100 by 200 pixel applet includes the points with x coordinates between 0 and 99, not between 0 and 100. Similarly the y coordinates are between 0 and 199 inclusive, not 0 and 200.

There is no separate drawSquare() method. A square is just a rectangle with equal length sides, so to draw a square call drawRect() and pass the same number for both the height and width arguments.

Loading Images

Polygons, ovals, lines and text cover a lot of ground. The

Page 284: Basic Java Handout

remaining graphic object you need is an image. Images in Java are bitmapped GIF or JPEG files that can contain pictures of just about anything. You can use any program at all to create them as long as that program can save in GIF or JPEG format.

Images displayed by Java applets are retrieved from the web via a URL that points to the image file. An applet that displays a picture must have a URL to the image its going to display. Images can be stored on a web server, a local hard drive or anywhere else the applet can point to via a URL. Make sure you put your images somewhere the person viewing the applet can access them. A file URL that points to your local hard drive may work while you're developing an applet, but it won't be of much use to someone who comes in over the web.

Typically you'll put images in the same directory as either the applet or the HTML file. Though it doesn't absolutely have to be in one of these two locations, storing it there will probably be more convenient. Put the image with the applet .class file if the image will be used for all instances of the applet. Put the applet with the HTML file if different instances of the applet will use different images. A third alternative is to put all the images in a common location and use PARAMs in the HTML file to tell Java where the images are.

If you know the exact URL for the image you wish to load, you can load it with the getImage() method:

URL imageURL = new URL("http://www.prenhall.com/logo.gif");java.awt.Image img = this.getImage(imageURL);You can compress this into one line as follows Image img = this.getImage(new URL("http://www.prenhall.com/logo.gif"));

Page 285: Basic Java Handout

The getImage() method is provided by java.applet.Applet. The URL class is provided by java.net.URL. Be sure to import it.

Code and Document Bases

If you don't know the exact URL of the image, but you do know its name and that it's in the same directory as the applet, you can use an alternate form of getImage() that takes a URL and a filename. Use the applet's getCodeBase() method to return the URL to the applet directory like this: Image img = this.getImage(this.getCodeBase(), "test.gif");The getCodeBase() method returns a URL object that points to the directory where the applet came from.

Finally if the image file is stored in the same directory as the HTML file, use the same getImage() method but pass it getDocumentBase() instead. This returns a URL that points at the directory which contains the HTML page in which the applet is embedded.

Image img = this.getImage(this.getDocumentBase(), "test.gif");If an image is loaded from the Internet, it may take some time for it to be fully downloaded. Most of the time you don't need to worry about this. You can draw the Image as soon as you've connected it to a URL using one of the above methods. Java will update it as more data becomes available without any further intervention on your part.

Load all the images your applet needs in the init() method. In particular you do not want to load them in the paint() method. If you do they will be reloaded every time your applet repaints itself, and applet performance will be abysmal.