184
Object Oriented Programming with Java Revision 0.3 Lee Chuk Munn July 19, 1999

67544219-OOP-JAVA

Embed Size (px)

Citation preview

Page 1: 67544219-OOP-JAVA

Object Oriented Programming with JavaRevision 0.3

Lee Chuk Munn

July 19, 1999

Page 2: 67544219-OOP-JAVA

Contents

1 Introducing Java 11.1 What is Java? . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.1.1 Simple . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.1.2 Object Oriented . . . . . . . . . . . . . . . . . . . . . 21.1.3 Network Savvy . . . . . . . . . . . . . . . . . . . . . . 21.1.4 Interpreted . . . . . . . . . . . . . . . . . . . . . . . . 21.1.5 Robust . . . . . . . . . . . . . . . . . . . . . . . . . . 21.1.6 Secure . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.1.7 Architecture Neutral . . . . . . . . . . . . . . . . . . . 41.1.8 Portable . . . . . . . . . . . . . . . . . . . . . . . . . . 41.1.9 High Performance . . . . . . . . . . . . . . . . . . . . 41.1.10 Multithreaded . . . . . . . . . . . . . . . . . . . . . . 51.1.11 Dynamic Language . . . . . . . . . . . . . . . . . . . . 5

1.2 First Java Program . . . . . . . . . . . . . . . . . . . . . . . . 51.2.1 Java Development Kit . . . . . . . . . . . . . . . . . . 61.2.2 Java CLASSPATH . . . . . . . . . . . . . . . . . . . . . 7

2 The Java Programming Language 82.1 Reserved Word . . . . . . . . . . . . . . . . . . . . . . . . . . 82.2 Primitive Types . . . . . . . . . . . . . . . . . . . . . . . . . . 82.3 Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.4 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.4.1 Binary Operators . . . . . . . . . . . . . . . . . . . . . 102.4.2 String Concatenation . . . . . . . . . . . . . . . . . . 102.4.3 Unary Operator . . . . . . . . . . . . . . . . . . . . . 102.4.4 Increment and Decrement Operators . . . . . . . . . . 112.4.5 Conditional Operators . . . . . . . . . . . . . . . . . . 112.4.6 Relational Operators . . . . . . . . . . . . . . . . . . . 112.4.7 Bitwise Operators . . . . . . . . . . . . . . . . . . . . 112.4.8 Conditional Expression Operator . . . . . . . . . . . . 122.4.9 Assignment Operators . . . . . . . . . . . . . . . . . . 12

2.5 Flow Control Statements . . . . . . . . . . . . . . . . . . . . . 132.5.1 Comments . . . . . . . . . . . . . . . . . . . . . . . . . 13

i

Page 3: 67544219-OOP-JAVA

CONTENTS

2.5.2 Semicolons, Blocks and Whitespace . . . . . . . . . . 142.5.3 if-else Statement . . . . . . . . . . . . . . . . . . . . 142.5.4 switch-case Statement . . . . . . . . . . . . . . . . . 152.5.5 while Statement . . . . . . . . . . . . . . . . . . . . . 172.5.6 do-while Statement . . . . . . . . . . . . . . . . . . . 172.5.7 for Statement . . . . . . . . . . . . . . . . . . . . . . 172.5.8 break, continue and Label Statement . . . . . . . . . 182.5.9 return Statement . . . . . . . . . . . . . . . . . . . . 19

2.6 Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.6.1 Multidimensional Array . . . . . . . . . . . . . . . . . 20

2.7 Defining Methods . . . . . . . . . . . . . . . . . . . . . . . . . 212.7.1 main Method . . . . . . . . . . . . . . . . . . . . . . . 22

3 Object Orientation 233.1 Why the Hype? . . . . . . . . . . . . . . . . . . . . . . . . . . 233.2 Object Concepts . . . . . . . . . . . . . . . . . . . . . . . . . 23

3.2.1 What is an Object? . . . . . . . . . . . . . . . . . . . 233.2.2 What is a Class? . . . . . . . . . . . . . . . . . . . . . 243.2.3 What is a Property? . . . . . . . . . . . . . . . . . . . 243.2.4 What is Encapsulation? . . . . . . . . . . . . . . . . . 243.2.5 What is Abstraction? . . . . . . . . . . . . . . . . . . 253.2.6 What is Inheritance? . . . . . . . . . . . . . . . . . . . 253.2.7 What is Polymorphism? . . . . . . . . . . . . . . . . . 26

3.3 Expressing Objects with Java . . . . . . . . . . . . . . . . . . 263.3.1 Objects and Class . . . . . . . . . . . . . . . . . . . . 263.3.2 Constructors and Destructors . . . . . . . . . . . . . . 273.3.3 Encapsulation . . . . . . . . . . . . . . . . . . . . . . . 293.3.4 Method and Member Visibility . . . . . . . . . . . . . 303.3.5 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . 313.3.6 Polymorphism . . . . . . . . . . . . . . . . . . . . . . 343.3.7 Overriding . . . . . . . . . . . . . . . . . . . . . . . . 353.3.8 Overloading . . . . . . . . . . . . . . . . . . . . . . . . 363.3.9 super and this . . . . . . . . . . . . . . . . . . . . . 37

3.4 final Keyword . . . . . . . . . . . . . . . . . . . . . . . . . . 383.5 static Keyword . . . . . . . . . . . . . . . . . . . . . . . . . 39

4 Abstract Class and Interface 424.1 Abstract Class . . . . . . . . . . . . . . . . . . . . . . . . . . 42

4.1.1 Defining an Abstract Class . . . . . . . . . . . . . . . 424.2 Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

4.2.1 Defining an Interface . . . . . . . . . . . . . . . . . . . 454.2.2 Implementing an Interface . . . . . . . . . . . . . . . . 45

4.3 Differences between Abstract Class and Interface . . . . . . . 47

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. ii

Page 4: 67544219-OOP-JAVA

CONTENTS

5 Building GUIs with AWT 495.1 Component and Container . . . . . . . . . . . . . . . . . . . . 495.2 LayoutManager . . . . . . . . . . . . . . . . . . . . . . . . . . 51

5.2.1 FlowLayout . . . . . . . . . . . . . . . . . . . . . . . . 525.2.2 GridLayout . . . . . . . . . . . . . . . . . . . . . . . . 535.2.3 BorderLayout . . . . . . . . . . . . . . . . . . . . . . 53

5.3 Container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555.3.1 Using Panel in Complex GUIs . . . . . . . . . . . . . 555.3.2 Frame . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

5.4 AWT Components . . . . . . . . . . . . . . . . . . . . . . . . 575.4.1 Button . . . . . . . . . . . . . . . . . . . . . . . . . . 575.4.2 Checkbox . . . . . . . . . . . . . . . . . . . . . . . . . 585.4.3 CheckboxGroup . . . . . . . . . . . . . . . . . . . . . . 585.4.4 Choice . . . . . . . . . . . . . . . . . . . . . . . . . . 595.4.5 List . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595.4.6 Label . . . . . . . . . . . . . . . . . . . . . . . . . . . 605.4.7 TextField . . . . . . . . . . . . . . . . . . . . . . . . 615.4.8 TextArea . . . . . . . . . . . . . . . . . . . . . . . . . 61

5.5 The AWT Paint Cycle . . . . . . . . . . . . . . . . . . . . . . 625.5.1 paint(Graphics) Method . . . . . . . . . . . . . . . . 625.5.2 repaint() Method . . . . . . . . . . . . . . . . . . . . 625.5.3 update(Graphics) Method . . . . . . . . . . . . . . . 63

5.6 Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 635.6.1 Using Font . . . . . . . . . . . . . . . . . . . . . . . . 64

5.7 Customizing Components . . . . . . . . . . . . . . . . . . . . 655.8 Adding Menus to Frame . . . . . . . . . . . . . . . . . . . . . 66

5.8.1 MenuBar . . . . . . . . . . . . . . . . . . . . . . . . . . 665.8.2 Menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . 675.8.3 MenuItem and CheckboxMenuItem . . . . . . . . . . . 67

5.9 AWT Events . . . . . . . . . . . . . . . . . . . . . . . . . . . 68

6 Inner Class 696.1 Member Class . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

6.1.1 Referencing Containing Class’ Members . . . . . . . . 716.1.2 Instantiating Member Classes . . . . . . . . . . . . . . 72

6.2 Anonymous Class . . . . . . . . . . . . . . . . . . . . . . . . . 736.2.1 Instance Initializers . . . . . . . . . . . . . . . . . . . 74

7 Handling AWT Events 757.1 The MVC Architecture . . . . . . . . . . . . . . . . . . . . . 76

7.1.1 The Model . . . . . . . . . . . . . . . . . . . . . . . . 767.1.2 The View . . . . . . . . . . . . . . . . . . . . . . . . . 777.1.3 The Controller . . . . . . . . . . . . . . . . . . . . . . 77

7.2 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. iii

Page 5: 67544219-OOP-JAVA

CONTENTS

7.2.1 The AWT Event Model . . . . . . . . . . . . . . . . . 777.2.2 Identifying Source, Listener and Event Objects . . . . 777.2.3 Event Listener Interface . . . . . . . . . . . . . . . . . 797.2.4 Event Source . . . . . . . . . . . . . . . . . . . . . . . 807.2.5 Event Objects . . . . . . . . . . . . . . . . . . . . . . 807.2.6 A Button Example . . . . . . . . . . . . . . . . . . . . 807.2.7 Another Button Example . . . . . . . . . . . . . . . . 82

7.3 Creating Customized Events . . . . . . . . . . . . . . . . . . . 837.3.1 Account Class Again . . . . . . . . . . . . . . . . . . . 847.3.2 The AccountEvent Object . . . . . . . . . . . . . . . . 847.3.3 AccountListener Interface . . . . . . . . . . . . . . . 847.3.4 Event Listener Registration/Deregistration . . . . . . 85

8 Exceptions 898.1 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

8.1.1 An Exceptional Example . . . . . . . . . . . . . . . . 898.1.2 Exception Objects . . . . . . . . . . . . . . . . . . . . 908.1.3 try-catch Block . . . . . . . . . . . . . . . . . . . . . 918.1.4 And finally... . . . . . . . . . . . . . . . . . . . . . . 928.1.5 Declaring Exceptions . . . . . . . . . . . . . . . . . . . 948.1.6 Generating Exceptions . . . . . . . . . . . . . . . . . . 94

8.2 Creating Your Own Exception . . . . . . . . . . . . . . . . . 95

9 Streams 989.1 The File Class . . . . . . . . . . . . . . . . . . . . . . . . . . 989.2 Character and Byte Streams . . . . . . . . . . . . . . . . . . . 100

9.2.1 InputStream . . . . . . . . . . . . . . . . . . . . . . . 1009.2.2 OutputStream . . . . . . . . . . . . . . . . . . . . . . 1019.2.3 A File Copy Example . . . . . . . . . . . . . . . . . . 103

9.3 Stream Chaining . . . . . . . . . . . . . . . . . . . . . . . . . 1059.3.1 Decorator Design . . . . . . . . . . . . . . . . . . . . . 1079.3.2 Performing I/O with Account . . . . . . . . . . . . . . 107

10 Object Serialization 11210.1 Serialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112

10.1.1 The Serializable Interface . . . . . . . . . . . . . . 11310.1.2 ObjectInputStream and ObjectOutputStream . . . . 113

10.2 Customizing the Serialization Process . . . . . . . . . . . . . 11410.2.1 Specifying What Gets Serialized . . . . . . . . . . . . 11410.2.2 readObject and writeObject Method . . . . . . . . 115

10.3 Validating a Deserialized Object . . . . . . . . . . . . . . . . 11610.4 Versioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. iv

Page 6: 67544219-OOP-JAVA

CONTENTS

11 Networking 12011.1 Addresses and Ports . . . . . . . . . . . . . . . . . . . . . . . 12011.2 Client-Server Model . . . . . . . . . . . . . . . . . . . . . . . 121

11.2.1 Defining the Protocol . . . . . . . . . . . . . . . . . . 12311.2.2 Writing a Server . . . . . . . . . . . . . . . . . . . . . 12511.2.3 Writing the Server API . . . . . . . . . . . . . . . . . 12911.2.4 Using the AccountServerAPI . . . . . . . . . . . . . . 133

12 Threads and Synchronization 13512.1 What is a Thread? . . . . . . . . . . . . . . . . . . . . . . . . 136

12.1.1 Creating a Thread . . . . . . . . . . . . . . . . . . . . 13712.1.2 Thread Class . . . . . . . . . . . . . . . . . . . . . . . 13912.1.3 Priorities . . . . . . . . . . . . . . . . . . . . . . . . . 14312.1.4 States of a Thread . . . . . . . . . . . . . . . . . . . . 143

12.2 Enhancing AccountServer . . . . . . . . . . . . . . . . . . . 14312.3 Synchrnonization . . . . . . . . . . . . . . . . . . . . . . . . . 150

12.3.1 synchronized Keyword . . . . . . . . . . . . . . . . . 15112.3.2 Thread Safe Objects . . . . . . . . . . . . . . . . . . . 154

12.4 Condition Variables . . . . . . . . . . . . . . . . . . . . . . . 15812.5 Implication of static on Threads . . . . . . . . . . . . . . . 160

A Listing 163A.1 Core Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163

A.1.1 Account.java . . . . . . . . . . . . . . . . . . . . . . 163A.1.2 AccountListener.java . . . . . . . . . . . . . . . . . 166A.1.3 AccountEvent.java . . . . . . . . . . . . . . . . . . . 166A.1.4 AccountException.java . . . . . . . . . . . . . . . . 166A.1.5 Interest.java . . . . . . . . . . . . . . . . . . . . . . 167

A.2 Subclass and Implementations . . . . . . . . . . . . . . . . . . 167A.2.1 FixedDepositAccount.java . . . . . . . . . . . . . . 167A.2.2 SavingAccount.java . . . . . . . . . . . . . . . . . . 168A.2.3 GenerousRate.java . . . . . . . . . . . . . . . . . . . 168A.2.4 TightRate.java . . . . . . . . . . . . . . . . . . . . . 168A.2.5 ErroneousAmountException.java . . . . . . . . . . . 169A.2.6 OverDrawnException.java . . . . . . . . . . . . . . . 169

A.3 Account Server . . . . . . . . . . . . . . . . . . . . . . . . . . 169A.3.1 AccountServer.java . . . . . . . . . . . . . . . . . . 169A.3.2 ConnectionHandler.java . . . . . . . . . . . . . . . . 170A.3.3 AccountProtocol.java . . . . . . . . . . . . . . . . . 172A.3.4 Counter.java . . . . . . . . . . . . . . . . . . . . . . 172A.3.5 Counter.java . . . . . . . . . . . . . . . . . . . . . . 173A.3.6 AccountServerAPI.java . . . . . . . . . . . . . . . . 173

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. v

Page 7: 67544219-OOP-JAVA

List of Figures

1.1 The JDK 1.2 security architecture . . . . . . . . . . . . . . . 31.2 Environment settings . . . . . . . . . . . . . . . . . . . . . . . 7

3.1 Instantiation . . . . . . . . . . . . . . . . . . . . . . . . . . . 243.2 The cat class hierarchy . . . . . . . . . . . . . . . . . . . . . . 253.3 Account class hierarchy . . . . . . . . . . . . . . . . . . . . . 35

4.1 Concept of an interface . . . . . . . . . . . . . . . . . . . . . . 44

5.1 GUI produced by AFrame.java . . . . . . . . . . . . . . . . . 515.2 Container managed by FlowLayout . . . . . . . . . . . . . . . 525.3 Container managed by GridLayout . . . . . . . . . . . . . . . 535.4 Container managed by BorderLayout . . . . . . . . . . . . . 545.5 A Java calculator . . . . . . . . . . . . . . . . . . . . . . . . . 555.6 A Checkbox component . . . . . . . . . . . . . . . . . . . . . 585.7 A Choice component . . . . . . . . . . . . . . . . . . . . . . . 595.8 A List component . . . . . . . . . . . . . . . . . . . . . . . . 605.9 A TextField component . . . . . . . . . . . . . . . . . . . . . 615.10 An example of using font . . . . . . . . . . . . . . . . . . . . 645.11 PrettyPanel with a button . . . . . . . . . . . . . . . . . . . 655.12 An example of a Frame with a MenuBar . . . . . . . . . . . . 675.13 A menu with MenuItems . . . . . . . . . . . . . . . . . . . . . 68

7.1 A typical GUI front end . . . . . . . . . . . . . . . . . . . . . 757.2 The model/view/controller architecture . . . . . . . . . . . . 767.3 Event source and listeners . . . . . . . . . . . . . . . . . . . . 787.4 A RolloverButton example . . . . . . . . . . . . . . . . . . . 827.5 Notifying listeners . . . . . . . . . . . . . . . . . . . . . . . . 88

9.1 InputStream class hierarchy . . . . . . . . . . . . . . . . . . . 1019.2 InputStream class hierarchy . . . . . . . . . . . . . . . . . . . 1039.3 Stream chaining example . . . . . . . . . . . . . . . . . . . . 1069.4 Contents of an AccountInputStream file . . . . . . . . . . . . 109

10.1 Graphical interface of serialver . . . . . . . . . . . . . . . . . 119

vi

Page 8: 67544219-OOP-JAVA

LIST OF FIGURES

11.1 IP address format . . . . . . . . . . . . . . . . . . . . . . . . . 12111.2 Interaction between ServerSocket and Socket . . . . . . . . 12311.3 Flow diagram of AccountServer’s protocol . . . . . . . . . . 126

12.1 Time/thread graph . . . . . . . . . . . . . . . . . . . . . . . . 13912.2 Life cycle of a thread . . . . . . . . . . . . . . . . . . . . . . . 14412.3 A modifed flow diagram of AccountServer’s protocol . . . . 14512.4 A race condition . . . . . . . . . . . . . . . . . . . . . . . . . 15212.5 wait() and notify() interaction . . . . . . . . . . . . . . . . 161

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. vii

Page 9: 67544219-OOP-JAVA

List of Tables

2.1 List of Java reserved words . . . . . . . . . . . . . . . . . . . 82.2 Binary operators . . . . . . . . . . . . . . . . . . . . . . . . . 102.3 Conditional operators . . . . . . . . . . . . . . . . . . . . . . 112.4 Relational operators . . . . . . . . . . . . . . . . . . . . . . . 122.5 Bitwise operators . . . . . . . . . . . . . . . . . . . . . . . . . 122.6 Assigment operators . . . . . . . . . . . . . . . . . . . . . . . 13

3.1 Method and member accessibility . . . . . . . . . . . . . . . . 31

4.1 Differences between abstract class and interface . . . . . . . . 48

7.1 AWT event list . . . . . . . . . . . . . . . . . . . . . . . . . . 79

9.1 Input stream classes . . . . . . . . . . . . . . . . . . . . . . . 1029.2 Output stream classes . . . . . . . . . . . . . . . . . . . . . . 104

viii

Page 10: 67544219-OOP-JAVA

Chapter 1

Introducing Java

1.1 What is Java?

Java can be describe as follows:

Java: A simple, object oriented, network savvy, interpreted, ro-bust, secure, architecture neutral, portable, high performance,multithreaded, dynamic language.

Since the sentence is loaded with so many buzzwords, lets take a look atwhat it is trying to say.

1.1.1 Simple

What exactly do we mean by simple? The Java designers had the followingobjectives in mind:

• Java was designed to be programmed easily without a lot of esoterictraining.

• Java omits many rarely used, poorly understood, confusing featuresof C++ that brings more grief than benefit. These omitted featuresprimarily consist of operator overloading, multiple inheritance, andextensive automatic coercions.

• Automatic garbage collection for simplifying the task of Java program-ming. A common source of complexity in many C and C++ applica-tions is storage management: the allocation and freeing of memory.By virtue of having automatic garbage collection the Java languagenot only makes the programming task easier, it also dramatically cutsdown on bugs.

• Another aspect of being simple is being small. One of the goals ofJava is to enable the construction of software that can run standalonein small machines.

1

Page 11: 67544219-OOP-JAVA

Secure 1.1.6

• Finally, delivering a set of well defined library that is easy to learn anduse.

1.1.2 Object Oriented

Object-oriented design is a technique that focuses design on the data andon the interfaces to it. Object-oriented design facilitates the clean definitionof interfaces and makes software component and reuse a reality.

The object-oriented facilities of Java are essentially those of C++, withextensions from Objective C for more dynamic method resolution.

A common misconception is that using an object oriented language likeJava makes your program object oriented. This could not be further from thetruth. “Object orientedness” is a matter of technique, training, experienceand personal preference.

1.1.3 Network Savvy

Java has an extensive library of routines for coping easily with TCP/IPprotocols like HTTP and FTP. This makes creating network connectionsmuch easier than in C or C++. Java applications can open and accessobjects across the net via URLs with the same ease that programmers areused to when accessing a local file system.

1.1.4 Interpreted

The Java compiler generates byte codes instead of native machine code. Abyte coded class file contains all the necessary information that the Javainterpreter or Java Virtual Machine (JVM) needs to run. The class file canbe executed on whatever native platform that JVM has been ported to.

1.1.5 Robust

Java puts a lot of emphasis on early checking for possible problems, laterdynamic (runtime) checking, and eliminating situations that are error prone.One of the advantages of a strongly typed language like Java is that it allowsextensive compile-time checking so bugs can be found early.

The single biggest difference between Java and C/C++ is that Java hasa pointer model that eliminates the possibility of overwriting memory andcorrupting data. Instead of pointer arithmetic, Java has true arrays. Thisallows subscript checking to be performed.

1.1.6 Secure

Java is intended for use in networked/distributed environments. Towardthat end, a lot of emphasis has been placed on security. Java enables the

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 2

Page 12: 67544219-OOP-JAVA

Secure 1.1.6

construction of virus-free, tamper-free systems. The JVM defines a “sand-box” where the user can safely and securely download and use Java classes.

Core Java APISecurityPackage

SecurityManager

AccessController

Operating System

KeyDatabase

Class Loader

Bytecode Verifier

Core API

RemoteClass

SignedClass

LocalClass

Figure 1.1: The JDK 1.2 security architecture

Security has been further beefed up with the release of JDK 1.2. TheJDK 1.2 security architecture (see figure 1.1) is an extension of the JDK 1.1.Elements of the security architecture or sandbox comprises of the following:

Bytecode verifier The bytecode verifier ensures that the Java class filesfollow the rules of the Java language. Core classes are not subjectedto the bytecode verifier’s scrutinity.

Class loader Loads classes that are not found in the CLASSPATH.

Access controller The access controller allows or prevents access to theoperating system. The access controller is only found in JDK 1.2.

Security manager The security manager is the primary interface betweenthe core API and the operating system. In JDK 1.2, the securitymanager works in tandem with the access controller.

Security package The security package forms the basis of authenticatingsigned Java classes.

Key database A database to store keys used by the security manager andaccess controller to verify the digital signature in signed class files.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 3

Page 13: 67544219-OOP-JAVA

High Performance 1.1.10

The Java security architect, Li Gong presented1 the following 5 equationswhich is useful for understanding Java security.

1. security != cryptography

2. correct security model != bug free implementation

3. testing != formal verification

4. component security != overall system security

5. Java security != applet containment

1.1.7 Architecture Neutral

Java was designed to support applications on networks. In general, networksare composed of a variety of systems with a variety of CPU and operatingsystem architectures. To enable a Java application to execute anywhereon the network, the compiler generates an architecture-neutral object fileformat–the compiled code is executable on many processors, given the pres-ence of the Java runtime system.

The Java compiler does this by generating bytecode instructions whichhave nothing to do with a particular computer architecture. Rather, they aredesigned to be both easy to interpret on any machine and easily translatedinto native machine code on the fly for performance.

1.1.8 Portable

Being architecture neutral is a big chunk of being portable, but there’smore to it than that. Unlike C and C++, there are no “implementationdependent” aspects of the specification. For example, int always means asigned two’s complement 32 bit integer, and float always means a 32-bitIEEE 754 floating point number.

1.1.9 High Performance

While the performance of interpreted bytecodes is usually more than ade-quate, there are situations where higher performance is required. The byte-codes can be translated on the fly (at runtime) into machine code for theparticular CPU the application is running on. The bytecode format wasdesigned with generating machine codes in mind, so the actual process ofgenerating machine code is generally simple.

With the imminent release of the “HotSpot” JVM, Java performancewill continue to gain ground against native applications.

1see http://java.sun.com/javaone/sessions/slides/TT03/index.html.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 4

Page 14: 67544219-OOP-JAVA

First Java Program 1.2

1.1.10 Multithreaded

Multithreading is a way of building applications with multiple threads. Un-fortunately, writing programs that deal with many things happening at oncecan be much more difficult than writing in the conventional single-threadedprograms.

Java has a sophisticated set of synchronization primitives that are basedon the widely used monitor and condition variable paradigm. By integratingthese concepts into the language (rather than only in classes) they becomemuch easier to use and are more robust.

1.1.11 Dynamic Language

The Java language was design to adapt to an evolving environment. Forexample, Java only loads classes as they are needed, even from across thenetwork. Classes in Java also have a runtime representation. Classes areessentially self describing making it possible to dynamically link classes intoa running system.

1.2 First Java Program

No programing language introduction is complete without an attempt at thehello world program. We will not be an exception to this rule. Lets takea look at a Java program.

1 // Customary hello world program2 import java.lang.*;3 public class HelloWorld {4 public static void main(String[] args) {5 System.out.println("hello world");6 }7 }

Here is a line by line commentary of the above program.

line 1, This is a comment line. Comments are preceeded by a //.

line 2, The import tells the Java complier that the program will be usingroutines in the java.lang library. Notice that Java program state-ments are terminated by “;”. There are ofcourse exception to thisrule.

line 3, This line defines the actual “program”. The “program” name isHelloWorld. It must be save in a file called HelloWorld.java. Thecontents of this program is those within its curly brackets.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 5

Page 15: 67544219-OOP-JAVA

Java Development Kit 1.2.2

line 4, The main function is the entry point of this program. Parametersare passed into the program via args which is an array of String.

line 5, main contains exactly one line of code and it prints out the helloworld message.

To compile the program, we invoke the Java compiler (javac) like so:

javac HelloWorld.java

Correct any errors reported by javac and recompile. A successful compila-tion will produce a HelloWorld.class file. Now you are ready to executethis program. Recall that class files contain byte code and can only beexecuted by the the JVM. To execute HelloWorld.class do the following

java HelloWorld

and the string “hello world” should be displayed.

1.2.1 Java Development Kit

To develope and deploy Java applications, you will need a compiler, a JVM,supporting libraries and perhaps documentations. Collectively these areknown as the Java Development Kit or JDK. Javasoft provides a free refer-ence implementation of the JDK on its website2. The Javasoft’s JDK, whichwe will be using, containts the following:

tools Tools include a Java compiler, a JVM, a debugger, a documentationextractor, a packaging utility call jar and others.

library The standard library is found under the lib directory and is dis-tributed as a ZIP file (classes.zip)

documentations The documentations can be found under the docs direc-tory. Use your browser and open docs/index.html.

demonstrations Demo programs are found under demos.

C header files These header files are mandatory for interfacing a Java pro-gram with a C program or vice versa. This is call Java Native Interfaceor JNI for short. We will not be covering JNI in this course.

sources Yes, the JDK sources are available as part of the distribution.2see http://java.sun.com/products/jdk

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 6

Page 16: 67544219-OOP-JAVA

Java CLASSPATH 1.2.2

1.2.2 Java CLASSPATH

The Java tools needs to know where the JDK are located. To do this, thesetools will reference the CLASSPATH environment variable. The directories andfiles in a CLASSPATH specification should be colon separated on UNIX andsemicolon separated on Windows. You need to include atleast classes.zipand your current directory in your CLASSPATH specification. Figure 1.2 showa generic setting.

On UNIX Bourne shell:

# Assume JDK is located in /opt/jdk1.1JAVA_HOME=/opt/jdk1.1CLASSPATH=$JAVA_HOME/lib/classes.zip:.PATH=$JAVA_HOME/bin:$PATHexport JAVA_HOME CLASSPATH PATH

On Windows:

rem Assume JDK is located in c:\jdk1.1set JAVA_HOME=c:\jdk1.1set CLASSPATH=%JAVA_HOME%\lib\classes.zip;.set PATH=%JAVA_HOME%\bin;%PATH%

Figure 1.2: Environment settings

Classes can be installed in one of 2 ways:

1. In a JAR (Java Archive) or a ZIP file.

2. Individual class files in a directory.

If classes are packed in an archive (JAR or ZIP) file, the you need to includethe archive file name in your CLASSPATH. Witness the classes.zip filein figure 1.2. If your class files are kept in a directory, you specify thedirectory that contains these class files. Again note the “.” in figure 1.2which references your current directory.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 7

Page 17: 67544219-OOP-JAVA

Chapter 2

The Java ProgrammingLanguage

2.1 Reserved Word

Java is a very small and compact language. There following is a list of Javakeywords. These words are reserved any may not be used in any identifiers(see section 2.3 on page 9).

abstract do implements private throwboolean double import protected throwsbreak else instanceof public transientbyte extends int return truecase false interface short trycatch final long static voidchar finally native super volatileclass float new switch whilecontinue for null synchronizeddefault if package this

Table 2.1: List of Java reserved words

2.2 Primitive Types

All data in Java belongs to a particular type. Java defines a numner of typesknown as primitive data types which are atomic in the sense that these typescannot be broken down into simpler types. These types can be classified intothe following groups:

1. Integer, represented as two’s complement

8

Page 18: 67544219-OOP-JAVA

Identifiers 2.3

byte 8 bits, −27 . . . − 27 − 1

short 16 bits, −215 . . . − 215 − 1

int 32 bits, −231 . . . − 231 − 1

long 64 bits, −263 . . . − 263 − 1

2. Floating point, IEEE 754-1985

float 32 bits,±3.4028E + 38 ≤ x ≤ ±1.4023E + 45.

double 64 bits,±1.79769E + 208 ≤ x ≤ ±4.9406E − 324.

3. Boolean (boolean), which has the value true or false.

4. Character (char), 16bit in Unicode, 0x0000 ≤ x ≤ 0xFFFF.

5. String (String), must be enclosed in double quotes “ . . . ”.

6. Arrays, which are proper types and not pointers. We will look atarrays in page 19.

Integer types can be represented using decimal, octal or hexadecimal.Furthermore, if an integer value is immediately followed by the letter “L”or “l” indicates that the integer value is long. These forms are shown asfollows:

5 — indicates an int value

5L — indicates a long value

05 — the prefix 0 indicates an octal value

0x5 — the prefix 0x indicates a hexadecimal value

Similarly, you can indicate a floating point number to be either float ordouble by appending either the letter “F” or “D” to the number respectively.

2.3 Identifiers

Identifiers are used as meaningful and easy to remember names to mem-bers(variables), constants, methods, classes, etc. A valid identifier is onethat begins with either an letter, an underscore ( ), or a dollar ($) andis followed by any number of letters, underscores, dollars or digits. Thefollowing is a list of valid and invalid indentifiers:

• thisLine, valid

• $money$, valid

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 9

Page 19: 67544219-OOP-JAVA

Unary Operator 2.4.4

• toBeOrNotToBe, valid

• $12345, valid

• 123isAsEasyAsABC, invalid

To declare and use and identifier, we have to preceed it with a type. Letsdeclare an identifier called foo and bar which are of type integer (int). Wewill also initialize bar with the value of 100.

int foo, bar = 100;

2.4 Operators

If you are familar with either C or C++ operators then you will feel rightat home with Java operators.

2.4.1 Binary Operators

Binary operators take two operands and returns a result. Please refer totable 2.2.

Operator Use Result+ op1 + op2 adds op1 to op2- op1 - op2 subtracts op2 from op1∗ op1 ∗ op2 multiplies op1 by op2/ op1 / op2 divides op1 by op2% op1 % op2 compute the remainder from dividing

op1 by op2

Table 2.2: Binary operators

2.4.2 String Concatenation

Strings can be concatenated using the plus operator (+).

String msg = "There are " + days + "in a leap year.";

2.4.3 Unary Operator

Unary operators changes the sign of a value or variable. The code snippetbelow illustrates this.

2 + -3

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 10

Page 20: 67544219-OOP-JAVA

Bitwise Operators 2.4.8

2.4.4 Increment and Decrement Operators

Increment and decrement operators can be used as short cut to incrementor decrement a variable by one. There are two versions of these operator, aprefix and a postfix version. The prefix version implies that the increment ordecrement should be perform first before any other operation while the post-fix version performs the increment or decrement after the entire expressionhas been evaluated.

The code below

1 count = ++itemA + itemB--;

can be rewritten as follows:

1 itemA = itemA + 1;2 count = itemA + itemB;3 itemB = itemB - 1;

2.4.5 Conditional Operators

These operator are used in boolean expressions and consists of logical “and”,“or” and “not”. Please refer to table 2.3.

Operator Use Result&& op1 && op2 op1 and op2 are both true|| op1 || op2 either op1 or op2 is true! !op1 op1 is false if its orignal value

is true and vice versa

Table 2.3: Conditional operators

2.4.6 Relational Operators

Relational operators compares two operands and returns boolean values de-pending on the outcome of the evaluation. Please refer to table 2.4.

2.4.7 Bitwise Operators

The following operators are used to manipulate bit patterns. Java’s bitwiseoperators are not as extensive as some languages like C/C++. Please referto table 2.5.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 11

Page 21: 67544219-OOP-JAVA

Assignment Operators 2.5

Operator Use Result> op1 > op2 true iff op1 is greater than op2>= op1 >= op2 true iff op1 is greater or equal to op2< op1 < op2 true iff op1 is less than op2<= op1 <= op2 true iff op1 is less or equal to than op2== op1 == op2 true iff op1 is equal to op2!= op1 != op2 true iff op1 is not equal to op2

Table 2.4: Relational operators

Operator Use Result>> op1 >> op2 shift bits of op1 right by a distance

of op2 bits, sign preserving<< op1 << op2 shift bits of op1 left by a distance

of op2 bits, sign preserving>>> op1 >>> op2 shift bits of op1 right by a distance

of op2 bits, non sign preserving& op1 & op2 bitwise AND op1 with op2|| op1 || op2 bitwise OR op1 with op2^ op1 ^ op2 bitwise exclusive OR op1 with op2~ ~op1 complements op1

Table 2.5: Bitwise operators

2.4.8 Conditional Expression Operator

We can use conditional expression operator to selectively evaluate portionsof an expression. The syntax for conditonal expression operator is as follows:

<conditional-expression>? <expr_1>: <expr_2>

In the following example, count will either get the value 0 or an incrementof 1 depending on whether its current value is greater than MAX.

1 count = (count > MAX)? 0: ++count;

2.4.9 Assignment Operators

These are short hand operators. They reduce the following expression

op1 = op1 OPERATOR op2

to

op1 OPERATOR= op2

Please refer to table 2.6.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 12

Page 22: 67544219-OOP-JAVA

Comments 2.5.1

Operator Use Result+= op1 += op2 increment op1 by op2-= op1 += op2 decrement op1 by op2∗ = op1 ∗ = op2 multiply op1 by op2 and assign

the result to op1/= op1 /= op2 divide op1 by op2 and assign

the result to op1%= op1 %= op2 the remainder of the division is assigned

to op1<<= op1 <<= op2 left shift op1 by a distance of op2 and

assign the result to op1, sign preserving>>= op1 >>= op2 right shift op1 by a distance of op2 and

assign the result to op1,sign preserving>>>= op1 >>>= op2 right shift op1 by a distance of op2 and

assign the result to op1,non sign preserving

&= op1 &= op2 bitwise AND op1 by op2|= op1 |= op2 bitwise OR op1 by op2

ˆ= op1 ˆ= op2 bitwise exclusive OR op1 by op2

Table 2.6: Assigment operators.

2.5 Flow Control Statements

Flow control statements determines the flow of our program. These state-ments can be classified into the following categories:

Decision making — if-else, switch-case

Loops — for, while, do-while

Exceptions — try-catch-finally, throw

Miscellaneous — break, contine, label: return

We will differ the discussion of exceptions to chapter 8.

2.5.1 Comments

Comments are used to document the code. The correct use of commentsaids the codes maintainability. There are three different types of comments.

1. Comment to the end of line using a double slash, //int counter = 0; // Used to hold the clock count

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 13

Page 23: 67544219-OOP-JAVA

if-else Statement 2.5.3

2. Delimited comment used /∗ and ∗/ to enclose the comments like so:count = item /∗ from stock ∗/ + count;

3. Documentation comments is a variation of delimeted comments. Alltext between /∗∗ ...∗/ are treated as comments and can be extractedas documentation by the javadoc tool.

2.5.2 Semicolons, Blocks and Whitespace

Java is a context free langage unlike languages like COBOL where characterposition matters. Liberal use of what space such as tab, space and new linesare recommended to make the program readable.

Java program statements are terminated with a semicolon (;). A blockis a group of statements enclosed within a pair of curly brackets ({}). State-ments within a block is treated as if it were a single statement. You donot need to terminate block statements with a semicolon. Variables definewithin a block is not visible outside of the block. In the following example,count is not available outside the block.

1 {2 int count;3 count = (count > MAX)? 0: ++count;4 }

2.5.3 if-else Statement

The if-else statement provides your programs with the ability to selec-tively execute other statements based on some criteria. The syntax of theif-else statement is:

if <condition><statement_1>

[ else<statement_2> ]

If the <condition> is evaluated to true, <statement_1> will be executeotherwise do <statement_2>. The following example illustrates the use ofthis statement:

1 char grade;2 int score;3 . . .4

5 if (score > 90) {6 grade = ’A’;

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 14

Page 24: 67544219-OOP-JAVA

switch-case Statement 2.5.4

7 } else if (score >= 80) {8 grade = ’B’;9 } else if (score >= 70) {

10 grade = ’C’;11 } else if (score >= 60) {12 grade = ’D’;13 } else {14 // Everybody below 60 fails15 grade = ’F’;16 }

Note that the else clause if option which means that if the condition isnot met, an action is not taken. The following code snippet will only printout the message “excellent!” if the score is 90 and above:

1 . . .2 if (score > 90)3 System.out.println("excellent!");4 . . .

2.5.4 switch-case Statement

Use the switch statement to conditionally perform statements based onsome expression; the expression must evaluate to an integer type. Youcan think of switch as a compound if-else statement. If the followingexample:

1 int month;2 . . .3 switch (month) {4 case 1:5 System.out.println("January");6 break;7 case 2:8 System.out.println("February");9 break;

10 case 3:11 System.out.println("March");12 break;13 case 4:14 System.out.println("April");15 break;16 case 5:17 System.out.println("May");18 break;

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 15

Page 25: 67544219-OOP-JAVA

switch-case Statement 2.5.4

19 case 6:20 System.out.println("June");21 break;22 case 7:23 System.out.println("July");24 break;25 case 8:26 System.out.println("August");27 break;28 case 9:29 System.out.println("September");30 break;31 case 10:32 System.out.println("October");33 break;34 case 11:35 System.out.println("November");36 break;37 case 12:38 System.out.println("December");39 break;40 default:41 System.out.println("Not a valid month");42 }

If month falls in the range of 1 and 12, then an appropriate month willbe printed otherwise a Not a valid month message will be printed. Thedefault acts as a catch all if month is not in the specified range.

The break statements cause control to break out of the switch andcontinue with the first statement following the switch. The break state-ments are necessary because case statements fall through. That is, withoutan explicit break control will flow sequentially through subsequent casestatements. The default and break are optional;

The general syntax of the switch statement is as follows:

switch <condition>case <value_1>:

<statement_1>. . .break;

case <value_2>:<statement_2>. . .break;

. . .

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 16

Page 26: 67544219-OOP-JAVA

for Statement 2.5.7

[ default:<default_statement> ]

2.5.5 while Statement

Generally, a while statement performs some action while a certain conditionremains true. The syntax of the while statement is:

while <condition><statement>

That is, while <expression> is true, do <statement>. <statement> canbe a single statement or a block. An example of the while statement is asfollows:

1 . . .2 while (input.read() != -1) {3 count++;4 System.out.println("characters read = " + count);5 }6 . . .

2.5.6 do-while Statement

The do-while loop, which is similar to the while loop you have met earlierexcept that the expression is evaluated at the bottom of the loop:

do {<statement>

} while (<expression>);

The do-while statement is a less commonly used loop construct in pro-gramming but does have its uses. For example, the do-while is convenientto use when the statements within the loop must be executed at least once.

2.5.7 for Statement

Use the for loop when you know the constraints of the loop (its initializationinstruction, termination criteria, and increment instruction). The syntax offor loop is:

for (<initialization>, <expression>, <increment>)<statement>

The following example uses a for loop to sum all numbers in the rangeof 1 to 100.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 17

Page 27: 67544219-OOP-JAVA

break, continue and Label Statement 2.5.8

1 int total = 0;2 for (int x = 1; x <= 100; x++)3 total += x;4 System.out.println("total = " + total);

2.5.8 break, continue and Label Statement

The following keywords are used to control program flows within loop state-ments. A label is used to identify a particular statement. Label namesfollows identifiers (see section 2.3 on page 9) naming conventions. The syn-tax of a label is as follows:

<label>:<statement>

We have seeen the break statement within the switch statement; recallthat the break causes the flow of control to jump out of the switch state-ment. Another form of the break statement causes flow of control to breakout of a labeled statement. The break statement has the following syntax.The <label> is optional. If <label> is not present, break will break out ofthe “closest” loop.

break [<label>];

While a break breaks out of a loop, a continue causes control to betransfered back to the loop for re evaluation. As with break, continue hasthe label and unlabelled form.

continue [<label>];

Lets examine a code snippet to see break, contiune and label statementsin action.

1 outer_loop: while (a > MAX) {2 if (testIt(a)) {3 a++;4 continue; // Note this5 } else {6 for (int j = 0; true; j++) {7 a = compute(j, a);8 if (a > j) {9 continue; // Note this

10 } else if ((a > 0) && (a < j)) {11 continue outer_loop; // Note this12 } else {13 break outer_loop; // Note this14 }

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 18

Page 28: 67544219-OOP-JAVA

Array 2.6

15 }16 }17 }18 System.out.prinln("All done!");

The explanation of the above code is as follows:

line 4, This continue will cause the control to be transfered to the whileloop in line 1.

line 9, Since there are no label following the continue, control will go backto for in line 6.

line 11, Returns to the while loop in line 1

line 13, The break exist both the inner for and outer while loops. Controlwill be transfered to line 18.

2.5.9 return Statement

A return is used to exit from a method. The general syntax of return isas follows:

return [ <value> ];

A return with a value returns the value to the caller of the method that weare currently leaving.

2.6 Array

Like most programming language, Java allows you to collect and managemultiple values through an array. The following is a declaration of an integerarray called intArray.

int[] intArray;

Note the square brakets ([]) indicates an array. Once you have declaredan array, you have to allocate the array by specifying the size of the array.Java does not support compile time array allocation. To create an array weuse the new keyword. We will now create intArray with 10 elements. Thedesired sized in placed within the square brackets.

intArray = new int[10];

In general creating an array of any type has the following syntax:

<type>[] <identifer> = new <type>[<size>];

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 19

Page 29: 67544219-OOP-JAVA

Multidimensional Array 2.6.1

Every array has a property called length. length returns the numberof elements in an array. length is not present when an array is not created.

1 int[] intArray = new int[100];2 for (int i = 0; i < intArray.length; i++)3 intArray[i] = i;

Another way of creating arrays is with an initializer which looks like thefollowing:

int[] intArray = {1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 0xa};

2.6.1 Multidimensional Array

Java also supports multidimensional arrays. Multidimensional arrays arereally arrays of arrays. To declare a two dimensional array you use 2 pairsof [] like so:

int[][] intArray = new int[10][10];

When allocating a multidimensional array, you do not have to specifythe number of elements that are contained in each dimension. For example,the following

1 int[][] intArray = new int[10][];2 for (int i = 0; i < intArray.length; i++) {3 intArray[i] = new int[i];4 for (int j = 0; j < intArray[i].lenght; j++)5 intArray[i][j] = j;6 }

initializes the array with the following values:

1 intArray[0] = 02 intArray[1] = 0, 13 intArray[2] = 0, 1, 24 intArray[3] = 0, 1, 2, 35 intArray[4] = 0, 1, 2, 3, 46 intArray[5] = 0, 1, 2, 3, 4, 57 intArray[6] = 0, 1, 2, 3, 4, 5, 68 intArray[7] = 0, 1, 2, 3, 4, 5, 6, 79 intArray[8] = 0, 1, 2, 3, 4, 5, 6, 7, 8

10 intArray[9] = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

You cannot create an inner array without first creating the outer. Thisis legal:

int[][] intArray = new int[10][];

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 20

Page 30: 67544219-OOP-JAVA

Defining Methods 2.7.1

but not this:

int[][] intArray = new int[][10];

Multidimenstional arrays can also be allocated and initialized with nestedinitializers. For example, rewriting the example in page 20 produces the fol-lowing:

1 int[][] intArray = {2 {0}, {0, 1}, {0, 1, 2},3 {0, 1, 2, 3}, {0, 1, 2, 3, 4},4 {0, 1, 2, 3, 4, 5}, {0, 1, 2, 3, 4, 5, 6},5 {0, 1, 2, 3, 4, 5, 6, 7}, {0, 1, 2, 3, 4, 5, 6, 7, 8},6 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}7 };

2.7 Defining Methods

Methods object oriented way of saying functions. A method has the generalsyntax:

public <return_type> <name>([<type> param_1, . . .]) {<method_body>

}

The <return_type> is the type returned by the the method. Return typescan be any valid Java type which includes all primitive types, arrays andreferences. To return a value we use return with the desired value when wewish to exit the method.

Method parameters are passed by-value viz. any modification done onthe formal parameter will not affect the actual parameter.

1 public void fooBar(int input) {2 input = 7;3 }4 . . .5 int fred = 0;6 foobar(fred);7 System.out.println("fred = " + fred); // fred = 0;

Although we pass fred into fooBar() to be modified the value remainsunchanged once fooBar() has completed execution.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 21

Page 31: 67544219-OOP-JAVA

main Method 2.7.1

2.7.1 main Method

The main() method name is usually reserved for the main entry point ofJava programs viz. the method that the JVM will call first when we executea Java program. A Java program without a main() will not run. Thesignature of main() is as follows:

public static void main(String[] args) { . . .}

The args is an arrays and is used to store command line parameters. Ifwe execute the following line

java FooBar 123 456 789

the following are found in args:

args[0] = "123"args[1] = "456"args[2] = "789"

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 22

Page 32: 67544219-OOP-JAVA

Chapter 3

Object Orientation

3.1 Why the Hype?

Object-orientation is a new technology based on objects and classes. Itpresently represents the best methodological framework for software design-ers to develop complex large scale systems. Objects provide a focus through-out analysis, design, and implementation by emphasizing the state, behavior,and interaction of objects in its models, providing the desirable property ofseamlessness between activities.

The use of objects distinguishes object-orientation from other techniquessuch as traditional structured methods (process-based: data and functionare separate) or other techniques such as knowledge based systems (logicprogamming, rules: Prolog) or mathematical methods (functional program-ming: ML, Lisp).

The benefits of object orientation are obvious; some of the benefits arelisted below:

• Faster development by breaking down complex systems to managablechunks.

• Increased quality.

• Easier maintance.

• Enhanced modifiability to adapt to changes.

• Increase software reuse.

3.2 Object Concepts

3.2.1 What is an Object?

There are many definitions of objects. For this course, we define an objectas follows:

23

Page 33: 67544219-OOP-JAVA

What is Encapsulation? 3.2.4

Object An entity which has state, behaviour and identity with a well de-fined role in a problem space.

The key in object orientation is to be able to identify objects and howto partition entities in a problem space into objects. So how do you defineobjects? In general, anything with a clearly defined boundry. You wouldfor instance define a car as an object or a road as an object since both haveclearly defined boundry. But a car/road would not fit our defination.

3.2.2 What is a Class?

A class is a template for objects. A class can be defined as follows:

Class A class is a set of objects that share a common structure and acommon behavior.

How do class and object differ? Think of classes as programs and objectsas processes; processes are dynamic copies of programs just as an object isa dynamic copy of a class. The act of creating an object from a class iscalled instantiating and the instantiated object is called an instance of aclass. From figure 3.1, ObjectA

′is instantiated from ClassA and is said to

be an instance of ClassA.

ClassAinstantiate=⇒ ObjectA

Figure 3.1: Instantiation

3.2.3 What is a Property?

A property is a single public attribute. We can use properties to classify andobject as well as to use properties to denote the current state of an object.Properties of a cat includes the following non exhaustive list: type of cat,size, color, etc.

3.2.4 What is Encapsulation?

One of the main difficulties when dealing with complex software is the levelof implementation details. Very often we are overwhelmed by them that wedo not know where to begin. Another difficulty with large software is thatoften a minute change to one part of the system requires changes to everyother parts. This is because we implement parts of the system based on theimplementation of another part.

The object oriented way of tackling this problem is encapsulation; hidingwhat is not necessary so that we can concentrate on what is the issue at hand:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 24

Page 34: 67544219-OOP-JAVA

What is Inheritance? 3.2.7

Encapsulation The principle of hiding design or implementation informa-tion that are not relevant to the current object.

3.2.5 What is Abstraction?

While encapsulating is hiding away details, abstract is ignoring them alto-gether.

Abstraction The principle of ignoring those aspects of a subject that arenot relevant to the current purpose in order to concentrate more fullyon those that are.

We use abstraction everyday to help us focus on a particular subject. Men-tion the word “car” and most of use will have the mental image of a metalicbody with wheels that travels on roads. We may not have imagined a driveror even the make and color of the car. We have abstracted the notion of acar to its purest form ignoring other details.

3.2.6 What is Inheritance?

Inheritance is a relationship between classes where one class is the parentclass of another. Inheritance can be defined as:

Inheritance Properties or characteristics received from an ancestor.

Sometimes, inheritance is also know as an “is-a” relationship. Inheritanceencourages reuse and simplifies code development. Consider the followingclass hierarchy shown in figure 3.2.

Tiger → Hobbes↗

Cat↘

Lion

Figure 3.2: The cat class hierarchy

Besides the “is-a” relationship, inheritance can also have the notion ofspecialization. In figure 3.2 we see that Hobbes1 is a specialization of tiger;it is a stuff tiger to be exact.

1For those who do not know what Hobbes is should buy a copy of SCMP and checkout the comics section. You will not regret it.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 25

Page 35: 67544219-OOP-JAVA

Objects and Class 3.3.1

3.2.7 What is Polymorphism?

Polymorphism is the ability of an object to assume many different forms.The word polymorphism is a derived from two words: “poly” which meansmany and “morph” which means forms. Refering to figure 3.2, we see thata cat object can also be a lion object or a tiger object since cat is the lowestcommon denominator class of the two.

3.3 Expressing Objects with Java

3.3.1 Objects and Class

We know that objects are instantiated from classes so lets look at defininga class in Java. In Java, a class definition has the following syntax:

public class <class_name> {<member_declaration><methods_declaration>

}

Classes can contain properties usually modelled by member variables.These are also declared as part of the class body. The following is an Accountclass with name, account number, account balance and overdraft as prop-erties. Account also has the deposit(), withdrawal() and transfer()method. This class must by save in a file called “Account.java”.

1 public class Account {2 public String name;3 public int acctNo;4 public float balance;5 public boolean overdraft;6 public void deposit(float amt) {7 if (amt >= 0)8 balance += amt;9 }

10 public void withdrawal(float amt) {11 if ((amt <= balance) && (amt >= 0))12 balance -= amt;13 }14 public void transfer(Account from, float amt) {15 if (amt < 0)16 return;17 from.withdrawal(amt);18 deposit(amt);19 }20 }

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 26

Page 36: 67544219-OOP-JAVA

Constructors and Destructors 3.3.2

To instantiate an Account object we use new. In the following code, we“open” an account for Fred.

1 Account fred;2 . . .3 fred = new Account();4 fred.name = "Fred";5 fred.acctNo = 12345;6 fred.balance = 100F;7 fred.overdraft = true;

line 1, Declare an Account variable. Note that Account is not a primitivetype (see section 2.2). We call type type of variable reference type.The initial value of reference type is null.

line 3, Instantiate an object call fred.

line 4 to 7, Assign values to object fred properties.

3.3.2 Constructors and Destructors

Constructors are useful for initializing objects before they are being used.Constructors are special purpose methods; a constructor is only used duringinstantiation to initialize the object and is never used again. A constructormust follow the following rules:

1. A constructor’s name must be the name of the class.

2. A constructor does not have any return type.

We can write a constructor for Account as follows:

1 public class Account {2 private String name;3 private int acctNo;4 private float balance;5 private boolean overdraft;6 public Account(String n, int no) {7 name = n;8 acctNo = no;9 balance = 100F;

10 overdraft = false;11 }12 . . .13 }

Now using the constructor, we can rewrite the code in page 27 as follows:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 27

Page 37: 67544219-OOP-JAVA

Constructors and Destructors 3.3.2

Account fred = new Account("Fred", 12345);

Every object has a default constructor if one is not provided. The de-fault constructor takes no argument and has an empty body. A defaultconstructor has the following signature:

public <class_name>() { }

Once you created your own constructor, you lose the the default constructor.Destructors are the exact opposite to constructors. Destructors are

called before the object is grabage collected and its memory released. Some-times an object may hold other objects like a network connection, or adatabase record or an opened file. These must be properly closed so thatthe database record is in a consistend state for instance. The garbage collectcannot do this for us. We must perform these in the destructors.

In Java, a destructors is known as a finalizer. Finalizers are optional;if they are not present in an object, no finalization will be done. To add afinalizer to an object simply add the following method:

protected void finalize() {// perform clean up

}

Lets add a finalizer to Account class. Our finalizer will check if anaccount object has an savings. If balance is not 0, we will save the objectotherwise we will discard the object.

1 public class Account {2 private String name;3 private int acctNo;4 private float balance;5 private boolean overdraft;6 public Account(String n, int no) {7 . . .8 }9 . . .

10 protected void finalize() {11 if (balance <= 0) {12 // save this account13 }14 }15 }

There are some additional things to be aware about finalizers:

• A finalizer is invoked before the the JVM garbage collects the object.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 28

Page 38: 67544219-OOP-JAVA

Encapsulation 3.3.3

• The JVM may exit without garbage collecting objects; so objects withfinalizer may never be called.

• the JVM makes no guarantees about when garbage collection occursor the order of the object will be collected. Therefore we cannot knowthe time or order of the finalizers will be invoked.

3.3.3 Encapsulation

Examining the code snippet on page 27 , we see that we need to knowAccount internals to use it; furthermore if we decide to change the accountname from name to accountName we will have to change every reference toit. Clearly we need to hide the implementation details from view. We reallyneed a way of manipulating the properties without knowing how it is done.We use encapsulation to achieve this.

To encapsulate properties we use getter and setter methods. The getterand setter methods has the following “pattern”:

public void set<PropertyName>(<PropertyType> value) {. . .

}

public <PropertyType> get<PropertyName>() {. . .

}

If the <PropertyType> is boolean, the getter method is replaced with thefollowing method signature:

public boolean is<PropertyName>() {. . .

}

This type of property is know as boolean property.Properties with the pair set/get is known as a read-write property while

properties with only a set or a get is know as a write only and read onlyproperties respectively. Lets rewrite Account so that we access its proper-ties through getter and setter instead of directly manipulating the membervariables.

1 public class Account {2 private String name;3 private int acctNo;4 private float balance;5 private boolean overdraft;6 . . .

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 29

Page 39: 67544219-OOP-JAVA

Method and Member Visibility 3.3.4

7 public void setName(String n) {8 name = n;9 }

10 public String getName() {11 return name;12 }13 public int getAccountNumber() {14 return acctNo;15 }16 public float getBalance() {17 return balance;18 }19 public void setOverdraft(boolean b) {20 overdraft = b;21 }22 public boolean isOverdraft() {23 return (overdraft);24 }25 }

name and overdraft are read/write property while acctNo and balance areread only since we have not provided setter.

It is important to recognize what we have done. We have hid implemen-tation details viz. the member names in this case, from the outside world.To reinforce this notion, we changed all member visibility from public toprivate. A private means that these members are only accessable withinthe Account class. The benefit we got is:

1. Manipulating properties with setName("Fred") and getName() is muchmore meaningful than this:

fred.name = "Fred";

2. Changing implementations eg. renaming the variables, will not requiremassive global changes.

3.3.4 Method and Member Visibility

Encapsulation hides a class internal details for the outside world; if we wereto provide getter and setter methods but leave Account class member dec-laration as public as in page 3.3.1, then we leave our members exposed.This is because public allows virtually any one to access the member. Byusing private, we have effectively closed all members to the outside world.By doing this, we are enforcing encapsulation.

Java provides the following visibility keywords which can be used onmembers or methods:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 30

Page 40: 67544219-OOP-JAVA

Inheritance 3.3.5

public A method or member that is declared public is accessible fromany class.

protected A method or member that is declared protected is accessibleonly to its subclass and the class itself. We will examine the notion ofsubclass in section 3.3.5 on page 31.

private A private method or member of a class is only accessible fromwithin that class. Other classes including subclass cannot access thismember or method.

Table 3.1 summarizes the previous points:

Keyword Self Subclass Otherspublic Yes Yes Yes

protected Yes Yes Noprivate Yes No No

Table 3.1: Method and member accessibility

The following are some tips on using visibility scopes.

• There is no reason why you should declare any member as public un-less performance is a big issue. You should always encapsulate mem-bers with public setter and getter methods. Standard methods thatmanipulate your class should be made public.

• If you have written a class and you want to perhaps give control ofyour class’ members and methods to its subclass but not anyone else,then declare these as protected.

• Declare your members and methods as private if they are used onlywithin your class.

3.3.5 Inheritance

Java uses the keyword extends to denote inheritance. The syntax forextends is as follows:

public <class_name>extends <parent_class_name> {. . .

The parent class is also know as superclass and the child class is sometimescalled a subclass.

We will now reuse Account to define SavingAccount and FixedDepositAccount.We want FixedDeposit to have the following additional characteristics:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 31

Page 41: 67544219-OOP-JAVA

Inheritance 3.3.5

FixedDeposit

• term to denote the duration of the deposit.

• interest is the interest rate for term.

SavingAccount

• Nothing special about this class. Just an “is-a” relationship.

The following code snippet implements this:

1 public class FixedDepositAccount2 extends Account {3 private Date term;4 private float interest;5 public FixedDepositAccount(String n, int acct) {6 super(n, acct);7 term = null;8 interest = -1F;9 }

10 public void setTerm(Date t) {11 // We only allow to set the term once12 if (term == null)13 term = t;14 }15 public Date getTerm() {16 return (term);17 }18 public void setInterest(float i) {19 if (interest == -1F)20 interest = i;21 }22 public float getInterest() {23 return (interest);24 }25 }26

27 public class SavingAccount28 extends Account {29 public SavingAccount(String n, int acct) {30 super(n, acct);31 }32 }

When we extends a class, we inherit all visible members and meth-ods. Visible members and methods are those marked with either public or

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 32

Page 42: 67544219-OOP-JAVA

Inheritance 3.3.6

protected. We will look into visibility rules in more detail in section 3.3.4later in this chapter. Java only supports single inheritance.

So what has FixedDepositAccount and SavingAccount inherited? Ashort answer would be all the getter and setter methods as well as deposit(),withdrawal() and transfer(). What have they not inherited?

• The private member variables. But notice that we can still accessthese variables via the appropriate getter and setter methods.

• Account’s constructor; we therefore need to provide constructors forour two child classes.

What is the super() in line 6 and 14. super is a keyword in Java. Itreferences the parent class. You can think of super as a “..” in your DOSfile system. Similary this refers to the current object. To understand line6 and 14 we need to delve a little more into inheritace.

Object and Constructor Chaining

All Java objects inherit Object implicitly. The only exception to this ruleis the Object itself. So if we write

public class Account {

the Java compiler will modify the declaration to this:

public class Accountextends Object {

This is to ensure that every object have all the necessary methods likeclone(), notify(), equals(), etc. Please refer to the documentation formore information.

We also know that every object has a constructor. So when an object isinstantiated its constructor gets called. But before we can create the objectitself the JVM must ensure that the parent is create before the child. Todo this the Java compiler will insert a super() as the first line in everyconstructor. This ensures that the parent constructors gets called. This isknow as constructor chaining. Note that the compiler will only chain to thedefault constructor of the parent class. This works well if the parent classhas a default constructor.

But Account does not have a default constructor! We have replace itwith our own constructor. In this case we have to do the chaining ourself.The

super(n, acct);

is the link to our parent class.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 33

Page 43: 67544219-OOP-JAVA

Polymorphism 3.3.6

3.3.6 Polymorphism

Like most object oriented programming language, Java allows you to holdan object with its parent type variable (polymorphic). So we can do this:

Account fred = new SavingAccount("Fred", 12345);

Subsequently when we use fred, the JVM needs to dynamically lookupwhat fred refers to. Although this incur a small overhead but the benefitfar outweighs the performance hit.

Because you can use a parent object reference to hold a child object, weneed to know exactly what is the actual object. We can use the instanceofoperator for this purpose. instanceof will return true if the object on theleft hand side of the operator is an instance of the right hand side class.Consider the following:

1 FixedDepositAccount foo = new FixedDepositAccount("Foo", 67890);2 SavingAccount fred = new SavingAccount("Fred", 12345);3 Account acct = fred;

Using instanceof of fred and foo, we get the following results:

• acct instanceof SavingAccount, true

• fred instanceof SavingAccount, true

• fred instanceof Account, true because Account is the parent classof SavingAccount

• foo instanceof SavingAccount, false

Casting refers to converting from one type to another. In C, a char *can be cast to almost anything. In Java, casting goes through strict runtimechecks to ensure that you are not violating security rules. The general syntaxfor casting is as follows:

<type_a_ref> = (<type_a_class>)<type_b_ref>;

Casting is only permitted between equvalent primitive types eg. fromint to long or from float to double. If can loose precision if you cast froma wider type to a narrower type eg. from long to short.

Casting between objects is much more interesting. In this case, we canhave three possible situations:

1. From a child class to a parent class.

2. From a parent class to a child class.

3. Between siblings.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 34

Page 44: 67544219-OOP-JAVA

Overriding 3.3.7

FixedDepositAccount↗

Account↘

SavingAccount

Figure 3.3: Account class hierarchy

Lets look at the Account hierarchy again as show in figure 3.3.We have the following objects:

1 FixedDepositAccount fixed = new FixedDepositAccount(...);2 SavingAccount save = new SavingAccount(...);3 Account acct;

Casting an object can be divided into the following three cases:

1. Assigning a subclass to a superclass (up cast) can be done with a sim-ple assigment.

acct = save;

2. Assigning a superclass to a subclass (down cast). This requires thecast operator otherwise it would not compile. Furthermore the castis check during runtime to ensure that what we are casting to is thecorrect type.

save = (SavingAccount)acct;

The JVM will check acct during runtime to make sure that acct isactually referencing a SavingAccount object. Otherwise you will geta ClassCastException error.

3. Casting between siblings is illegal and will never compile. The follow-ing is illegal.

save = (SavingAccount)foo;

3.3.7 Overriding

When a subclass defines a method with the exact same name and signatureas a method in its super class it is said to override the superclass method.Overriding is used to customize a superclass method. FixedDepositAccountdoes not allow withdrawal until the term matures. But since we have ex-tended Account which allows withdrawal. We must therefore modify the be-haviour of withdrawal(). We will override this method in FixedDepositAccount.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 35

Page 45: 67544219-OOP-JAVA

Overloading 3.3.8

1 public class FixedDepositAccount2 extends Account {3 private Date term;4 private float interest;5 public FixedDepositAccount(String n, int acct) {6 super(n, acct);7 term = null;8 interest = -1F;9 }

10 // setter and getter methods for term and interest11 . . .12 public void withdrawal(float amt) {13 Date today = new Date();14 // If mature then we allow withdrawal15 if (today.after(term))16 super.withdrawal(amt);17 }18 }

Notice that in line 12, we override withdrawal() so that it will check if theterm has matured. If it has not, then we will not do anything; but if it haswe then allow the withdrawal. Line 16 calls the superclass’ withdrawal()by prefixing it with a super.

We can override override superclass’ methods and members. To over-riding a member, declare a member with the same name and type in thesubclass. Similarly you can access the overridden superclass’ member byprefixing a super.

3.3.8 Overloading

Overloading is commonly used in Java to define a number of related methodswith the same name but different signature. Overloading allows us to tailora method to different use as we shall see in withdrawal() method. You canalso overload constructors. Armed with overloading, We will now add morecapabilities to FixedDepositAccount.

• Add an extra constructor such that if no account number is give, itwill automatically assign one.

• Add an additional withdrawal() that withdraws the entire amount.We now can withdraw the entire amount or portion of our balanancedepending on the method we use.

The code to implement the new functionality is as follows:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 36

Page 46: 67544219-OOP-JAVA

super and this 3.3.9

1 public class FixedDepositAccount2 extends Account {3 . . .4 public FixedDepositAccount(String n, int acct) {5 super(n, acct);6 term = null;7 interest = -1F;8 }9 public FixedDepositAccount(String n) {

10 this(n, Math.abs((new Random()).nextInt()));11 }12 . . .13 public void withdrawal(float amt) {14 . . .15 }16 public void withdrawal() {17 withdrawal(getBalance());18 }

The following is an explanation of the above code snippet:

line 9, This is the overloaded constructor. You only need to supply theaccount name.

line 10, Notice that we use a random number generator to generate anaccount number. Recall that we use super( . . . ) in page 33 to chainthe superclass’ constructor. Similarly we use this( . . . ) to invoke aconstructor in the current class. Again this() must be the first linein a constructor.

line 16, 17, This withdrawal() method withdraws the entire balance fromthe account. We use getBalance() which we have inherited fromAccount to get the full balance. Now using withdrawal(float amt)method, we withdrawal the entire amount. Of course the withdrawalis subject to the usual checks.

3.3.9 super and this

We have seen the use of super and this over the last few sections. Letssummarize what we have learnt:

1. Invoking superclass’ constructor. Use super( . . . ).

2. Invoking current class’ constructor. Use this( . . . ).

3. Invoking an overridden method or member. Use super.<method>.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 37

Page 47: 67544219-OOP-JAVA

final Keyword 3.4

4. Refering to current class. Use this. like this.<method> or just thiswhich refers to the current instance.

The this keyword can also be used to disambiguate the context. Con-sider the following code:

1 public void fred(int count) {2 this.count = count;3 }

The this.count refers the the instance member while count refer to fred’sformal parameter. Actually, all instance methods and members have animplicit this preceeding them.

3.4 final Keyword

You can use the final keyword on classes, methods and members. A classdeclared with the final keyword cannot be subclassed. A final class isdeclared as follows:

public final class Fred {. . .

A final method cannot be overriden by subclasses. This is to preventsubclass from changing the functionalities of your method. For example,you have a method that calculates interest retes; to prevent users formarbitrarily changing your interest rate calculation, you declare the methodas final. Below is a code snippet from FixedDepositAccount which we havelooked at previously. If we do not want others to override our withrawal()methods, we add the final keyword as below. Note that the final keyworddoes not alter the signature of the method.

1 public class FixedDepositAccount2 extends Account {3 . . .4 public final void withdrawal(float amt) {5 . . .6 }7 public final void withdrawal() {8 withdrawal(getBalance());9 }

10 . . .

A final member is a member whose values you cannot change once youhave assigned a value to it. If we have the following declaration:

public final double PI = 3.414;

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 38

Page 48: 67544219-OOP-JAVA

static Keyword 3.5

then PI’s value cannot be changed. If we have a final member whose typeis an object like so:

public final Account fred = new Account("Fred", 12345);

then we cannot change the member itself but we can change the content ofthe member. So while reassigning a value to fred is not permissible,

fred = new Account("Barney", 23456);

call a method in Account to modify its member is permissible. Thereforethe following is permissible:

fred.withdrawal(100F);fred.deposit(200F);

When you declare a final member, you have to provide an initializer tothe member. If you decide to declare a final member without an initialize,then you will have to initialize that final member in the class’ constructor,for instance:

public class OverdrawnExceptionextends Exception {private final String name;private final int acctNo;private final float balance;private final float withdrawAmount;private final Date date;public OverdrawnException(Account acct, float amt) {

super("Overdrawn");name = acct.getName();acctNo = acct.getAccountNumber();balance = acct.getBalance();withdrawnAmount = amt;date = new Date();

}. . .

If you don’t, the Java complier will complain this as an error.

3.5 static Keyword

In most programming language, you have the concept of global variables;a global variable is ”visible” from every part of a program. Changes to aglobal variable can be seen globally. You can declare a member in a class tobe global by adding a static keyword in its declaration.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 39

Page 49: 67544219-OOP-JAVA

static Keyword 3.5

Let’s take a look at what a non-global member in Java terms first beforewe look at what a global member is. Consider the following simple classwhich consists of 1 member:

public class Foo {public String name;

}

Now we instantiate 2 instances of this class and perform some operations onthem;

1 Foo fred = new Foo();2 Foo barney = new Foo();3 fred.name = "Fred Flintstone";4 barney.name = "Barney Rubble";5 System.out.println("fred = " + fred.name);6 System.out.println("barney = " + barney.name);

What do you expect the output from lines 5 and 6 to be? The answer shouldcome as no suprise; “Fred Flintstone” (line 5 ) and “Barney Rubble” (line6 ). The name member is known as an instance member because if we changethis member, the change will only affect that particular instance viz. localto that instance. So, if we assigned “Fred Flinstone” to fred.name, thenthat assigment should only affect fred. Similarly for barney.

Now consider adding static to Foo like so:

public class Foo {public static String name;

}

If we were to run the previous sequence of statement again, both the outputwill be “Barney Rubble”. What is going on here? The reason is becausewhen we declare any member with static, we make that member to be aclass member ; as the name implies, all instance references 1 copy of thismember. So if an instance modifies a class member, its modification isvisible to every other instance of the same class. This is an extremely goodapproach to sharing information between instance. But you have to ensurethat 2 or more instances do not modify a class instance simultaneously.This can potentially cause data corruption. We will address this issue insection 12.5. You do not have to instantiate an instance of a class to use itsclass member. We can reference a class member by preceeding the member’sname with the its class’ name; therefore, if we want to reference name, wecan use the following method:

Foo.name = "Fred Flintstone";

We can combine final and static to declare “constant”; for example,to declare a π constant, we can declare it in the following way:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 40

Page 50: 67544219-OOP-JAVA

static Keyword 3.5

public class Circle {public static final double PI = 3.414;

}

So you can use PI in the following manner:

double circumference = 2 * Circle.PI * radius;

In fact, constants declared in the following manner throughout the JDK.For an example, see the Double class in java.lang package.

Similarly, you can declare class methods; a class method is declared withthe static keyword. The following is a class method declaration:

1 public class Circle {2 public static final double PI = 3.414;3 public static double circumference(double radius) {4 return (2 * PI * radius);5 }6 }

There are a few points that you need to remeber about class method:

1. All variables and members used in a class method are assumed to bedeclared with static. If you try to use an instance inside a classmethod, the compiler will flag it as an error. The following exampleillustrates this:

1 public class Circle {2 public final double PI = 3.414;3 public static double circumference(double radius) {4 return (2 * PI * radius);5 }6 }

Line 4 is an error because PI in line 2 is declared without a static.

2. You cannot use this inside a class method. this refers to an instance;since a class method is not in an instance, therefore using this wouldcause the Java compiler to complain.

To use a static method, you do not have to instantiate the class; as withclass member, just preceed the method name with its class name. Therefore,I can use circumference() in the following way:

double myCircle = Circle.circumference(2.1);

Can you explain why when we print “Hello World” to the console we performthe following:

System.out.println("Hello World"):

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 41

Page 51: 67544219-OOP-JAVA

Chapter 4

Abstract Class and Interface

4.1 Abstract Class

Abstract classes are incomplete classes. There are incomplete because whenwriting the class the behaviour of a method cannot be determine.

4.1.1 Defining an Abstract Class

To declare a class to be abstract, we do the following:

1. Denote the class as abstract with the abstract keyword in the classdeclaration.

2. Mark unimplemented methods with the abstract keyword. Abstractmethods do not have body.

Abstract can contain non abstract methods. The general syntax for declar-ing an abstract class is as follows:

public abstract class <class_name> {public abstract void <method_name>(...);

}

To use an abstract class, we extends it and override those abstractmethods by providing them with implementation. Note also the followingpoints about abstract classes:

• If a subclass does not implement all abstract methods of its superclass,the subclass itself is an abstract class.

• You cannot instantiate an abstract class.

Consider the Account class from the previous chapter. We want toadd printing capabilities to Account. Obviously the amount of informa-tion printed out by different Account subclass are different, so when we

42

Page 52: 67544219-OOP-JAVA

Defining an Abstract Class 4.1.1

cannot implement the printing at Account level. But we do want to pointout to anyone inheriting Account that they do need to consider printing.We therefore declare a method called printAccount() as abstract. Thefollowing code does this:

1 public abstract class Account {2 private String name;3 . . .4 public Account(String n, int no) {5 . . .6 }7 public abstract void printAccount();8 public void deposit(float amt) {9 . . .

10 }11 public void withdrawal(float amt) {12 . . .13 }14 public void transfer(Account from, float amt) {15 . . .16 }17 }

We declare the Account class as abstract by denoting it with abstractkeyword in line 1. In line 7, we mark printAccount() as abstract. Abstractmethods do not have a method body.

We will now have to rewrite FixedDepositAccount and SavingAccountto implement printAccount().

1 public class FixedDepositAccount2 extends Account {3 . . .4 public FixedDepositAccount(String n, int acct) {5 super(n, acct);6 }7 public void printAccount() {8 System.out.println("Account name = " + getName());9 System.out.println("Amount deposited = $" + getBalance());

10 System.out.println("Mature on = " + getTerm());11 System.out.println("Interest rate = " + getIneterest() + "%");12 }13 . . .14 }15

16 public class SavingAccount

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 43

Page 53: 67544219-OOP-JAVA

Interface 4.2

17 extends Account {18 public SavingAccount(String n, int acct) {19 super(n, acct);20 }21 public void printAcount() {22 System.out.println("Account name = " + getName());23 System.out.println("Current balance = $" + getBalance());24 }25 }

Lines 7 and 21 implement the abstract method printAccount(). When youimplement an abstract method you drop the abstract keyword.

4.2 Interface

What is an interface? It is a point where two entities meet. Let’s considera Walkman. A Walkman has a play button. We know that when we pressit, the Walkman will play whatever tapes happens to be in it. The “Play”button is therefore an interface between you and the Walkman’s internalmachinery.

Besides the play button, the Walkman has other buttons such as forward,backward, stop, etc. These buttons constitute a cassette player’s interface.When you purchase a cassette player, you would expect these buttons (func-tions) to be present. Any cassette player with any one of these functionsmissing would deemed incomplete.

INTERFACE

User Provider

Figure 4.1: Concept of an interface

The Walkman example highlights the following point:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 44

Page 54: 67544219-OOP-JAVA

Implementing an Interface 4.2.2

• There are two sides in every interface. One is the provider, whatservices it provides. The other is the user.

• The interface hides the implementation from the user. Your focus ison the interface, not the implementation.

• An interface guarantees all functions are complete.

Figure 4.1 illustrates the concept of an interface.

4.2.1 Defining an Interface

In Java, an interface is a set of methods under a name. These methods arevery much like abstract methods in that they have no implementation. Toimplement an interface we use the interface keyword. An interface hasthe following syntax:

public interface <interface_name>[ extends <interface_1>, ...] {<method_1>;<method_2>;. . .

}

Optionally an interface can inherit any number of super interfaces via theuse of extends keyword.

4.2.2 Implementing an Interface

Classes can implement any number of interface. To implement an in-terface, classes use the keyword implements in the class declaration. Aclass that implements an interface must provide implementation for all itsmethods and methods in its super interface. The syntax is as follows:

public class <class_name>implements <interface_0>[, <interface_1>, ...] {. . .

}

We will now add interest calculation to Account. We are well awarethat interest rate fluctuates and the formula for calculating interest rateschanges. We cannot hardcode this calculation into Account; otherwise weneed to recompile everytime the interest calculation changes. We can usean interface to overcome this problem. This is how we do it:

1. Define an interface call Interest. This interface has one singlemethod called calculate() which performs interest calculations.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 45

Page 55: 67544219-OOP-JAVA

Implementing an Interface 4.2.2

2. Add a method in Account that accepts an Interest interface. Callcalculate() when we want to calculate interest.

The Interest looks like this:

1 public interface Interest {2 public float calculate(float amt);3 }

calculate() takes in the amount of money that you want to calculate theinterest on and returs the interest on the input amount. You have to savethis interface in a file called “Interest.java” just like a class.

Lets implement two interest which we will call GenerousRate and TightRate.

1 public class GenerousRate2 implements Interest {3 public float calculate(float amt) {4 return (amt * 0.5F);5 }6 }7

8 public class TightRate9 implements Interest {

10 public float calculate(float amt) {11 return (amt * 0.01F);12 }13 }

Notice the way the Interest interface is defined and implemented:

• Interface and its implementation are totally separate.

• For 1 interface, multiple implementations are possible. In our Interestexample, there are two implementations.

We now turn our attention to Account. The listing is as follows:

1 public abstract class Account {2 private String name;3 . . .4 private Interest interest;5 public Account(String n, int no) {6 name = n;7 acctNo = no;8 balance = 100F;9 overdraft = false;

10 interest = null;

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 46

Page 56: 67544219-OOP-JAVA

Differences between Abstract Class and Interface 4.3

11 }12 public abstract void printAccount();13 public void setInterestCalculation(Interest i) {14 interest = i;15 }16 public float calculateInterest() {17 if (interest != null)18 return(interest.calculate(getBalance()));19 else20 return(0F);21 }22 . . .23 }

Comments on the above code:

line 13 to 15, We define a method to set interest calculation. Notice thatwe use interest to hold an Interest interface.

line 16 to 21, When we invoke this method, Account will check if an inter-est calculation has been set. If it has then we call the calculate()method, otherwise we return 0.

The entire key to interface hinges on this: we reveal an object’s interface(methods therein) without relying on any one class (line 18 ). The JVM willlookup the actual implementation during runtime viz. at the point time ofinvocation.

Let’s look at somemore code to see how all these works:

1 SavingAccount fred = new SavingAccont("Fred", 12345);2 fred.setInterestCalculation(new TightRate());3 System.out.println("tight = " + fred.calculateInterest());4 fred.setInterestCalculation(new GenerousRate());5 System.out.println("generous = " + fred.calculateInterest());

4.3 Differences between Abstract Class and Inter-face

Although abstract classes and interface provide similar features, the are infact quite different. Table 4.1 list of their differences.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 47

Page 57: 67544219-OOP-JAVA

Differences between Abstract Class and Interface 4.3

Abstract Class InterfaceYou extends an abstract class. You implements and interface.Can only subclass 1 abstract class. You can implement more than 1 inter-

face.You are allowed to selectively overrideany abstract methods.

You must implement all the methodsin it.

Static in the sense that it is compiledinto a class.

Dynamic because you can change an in-terface’s implementation at runtime.

Table 4.1: Differences between abstract class and interface

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 48

Page 58: 67544219-OOP-JAVA

Chapter 5

Building GUIs with AWT

The graphical user interface (refer to GUI henceforth) is an important partof the modern day application. Like most programming libraries, the JDKallows you to develop GUI front ends by using the Abstract WindowingToolkit or more commonly know as the AWT.

5.1 Component and Container

The basic GUI building blocks in AWT are Components and Containers.Components is the base class of all AWT widgets (eg. Button, List, Choice,etc.). We will use the word component to refer to AWT widgets collectivelyand Component to refer specifically to the class. As the base class, Componentprovides the following methods which are common across all components:

public void paint(Graphics g)Called when the Container needs to update the GUI. Control will bepassed to this method for drawing. Graphics is an abstraction of thescreen. We will look at Container and Graphics shortly.

public void repaint()Force an update of the component; call this method when you need tothe component to be redrawn.

public void setBackground(Color c)Sets the background color of a component.

public void setForeground(Color c)Sets the foreground color of a component.

public void setEnabled(boolean b)Enable or disable a component. A disabled component is greyed outand is not usable; eg. a disabled Button cannot be pressed.

49

Page 59: 67544219-OOP-JAVA

Component and Container 5.1

public void setFont(Font f)Sets the font for this component. We will look at manipulating fontsin section 5.6.1.

public void requestFocus()Set the mouse focus to this component.

The above is not an exhaustive list of all methods; please consult the theComponent API documentation.

The Container class, as the name implies acts as a container for compo-nents. To built a GUI, you add components in to Containers. Here is thecatch: since Containers are themselves subsclass of Component, you canadd Containers to Containers! Using this technique, we can build verycomplex GUIs.

The following are important methods in Container class:

public Component add(Component c)Adds a component to a Container.

public Component add(String name, Component c)Adds a component to a name location in Container.

public void setLayout(LayoutManager mgr)Sets a LayoutManager to the Container. We will look at LayoutManagerin section 5.2.

Lets take a bird’s eyeview of building a simple GUI with Componentsand Containers before we proceed further.

1 import java.lang.*;2 import java.awt.*;3 public class AFrame {4 public AFrame() {5 Button button = new Button("Press Me!");6 button.setBackground(Color.red);7 button.setForeground(Color.white);8 Frame frame = new Frame("A Frame");9 frame.setLayout(new FlowLayout());

10 frame.setBackground(Color.yellow);11 frame.add(button);12 frame.setSize(200, 100);13 frame.setVisible(true);14 }15 public static void main(String[] args) {16 AFrame aFrame = new AFrame();17 }18 }

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 50

Page 60: 67544219-OOP-JAVA

LayoutManager 5.2.1

The GUI produced by the previous code snippet is shown in figure 5.1.

Figure 5.1: GUI produced by AFrame.java

An explanation of AFrame.java is as follows:

line 2, Unlike java.lang package which is imported by default, you have toimport java.awt package manually otherwise your program will notcompile.

line 5, Recall Button is a subclass of Component. We create an instance ofButton.

line 6 and 7, Sets button’s foreground and background color.

line 8, We create an instance of Frame which is a subclass of Container.

line 9, Set the layout or arrangement viz. how components in frame willbe arranged.

line 11, Add the button to the frame for display.

line 12, Sets the frame’s size for display. The width and height is 200 by100 pixel respectively.

line 13, Finally, when all the setup is completed, we display the frame bysetting its visible property to true.

5.2 LayoutManager

The layout of components within a Container is done by LayoutManager.Before you add any components to a Container you need to set the lay-out or arrangement of the Container using setLayout() method. TheLayoutManager controls the placement of components according to its theLayoutManager’s layout policy. The LayoutManager controls all aspect ofa component in the Container: its placement, size, orientation, etc.

The JDK comes with 5 LayoutManagers. We will examine only thefollowing 3: FlowLayout, GridLayout and BorderLayout.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 51

Page 61: 67544219-OOP-JAVA

FlowLayout 5.2.2

5.2.1 FlowLayout

FlowLayout arranges components in a Container like sentences in a page;from left to right and from top to bottom. FlowLayout will try to fit asmany components on a line as possible before moving them to the next.When you resize a Container, FlowLayout will rearranges the componentsaccording to the new Container’s size.

The following code adds 3 Buttons to a FlowLayoutmanaged Container.

1 import java.lang.*;2 import java.awt.*;3 public class FlowLayoutEx {4 public FlowLayoutEx() {5 Frame frame = new Frame("FlowLayout");6 frame.setLayout(new FlowLayout());7 frame.add(new Button("One"));8 frame.add(new Button("Two"));9 frame.add(new Button("Three"));

10 frame.setSize(200, 100);11 frame.setVisible(true);12 }13 public static void main(String[] args) {14 FlowLayoutEx ex = new FlowLayoutEx();15 }16 }

Notice that in line 6, we set the FlowLayout to be the layout of the frame.All subsequent add (line 7 to 9 ) will be under FlowLayout’s control.

When you run FlowLayoutEx program, you will see the frame as shown infigure 5.2. When the frame is resized, the buttons will adjust to accomodatethe new size.

Figure 5.2: Container managed by FlowLayout

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 52

Page 62: 67544219-OOP-JAVA

BorderLayout 5.2.3

5.2.2 GridLayout

The GridLayout devides the Container into a specificed number of rowsand columns, very much like a matrix. Components in the grid are arrangedfrom left to right and from top to bottom. The size of each cell is the sizeof the largest component in the grid.

The following code snippet creates a 3 rows by 2 columns grid.

1 import java.lang.*;2 import java.awt.*;3 public class GridLayoutEx {4 private String[] label = {"A", "B", "C", "D", "E", "F" };5 public GridLayoutEx() {6 Frame frame = new Frame("GridLayout");7 frame.setLayout(new GridLayout(3, 2));8 for (int i = 0; i < label.length; i++)9 frame.add(new Button(label[i]));

10 frame.pack();11 frame.setVisible(true);12 }13 public static void main(String[] args) {14 GridLayoutEx ex = new GridLayoutEx();15 }16 }

Figure 5.3: Container managed by GridLayout

Do not over or under add() a GridLayout managed container; otherwisethe layout of your component will be unpredictable.

5.2.3 BorderLayout

BorderLayout divides a container into 5 region. They are “north”, “south”,“east”, “west” and “center”. When you add a component to a BorderLayoutmanaged container, you need to specify the region or your component willnot show up when you display the container.

The following code adds 5 buttons to the 5 region in BorderLayout.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 53

Page 63: 67544219-OOP-JAVA

BorderLayout 5.3

1 import java.lang.*;2 import java.awt.*;3 public class BorderLayoutEx {4 public BorderLayoutEx() {5 Frame frame = new Frame("BorderLayout");6 frame.setLayout(new BorderLayout());7 frame.add(new Button("North"), BorderLayout.NORTH);8 frame.add(new Button("South"), BorderLayout.SOUTH);9 frame.add(new Button("East"), BorderLayout.EAST);

10 frame.add(new Button("West"), BorderLayout.WEST);11 frame.add(new Button("Center"), BorderLayout.CENTER);12 frame.setSize(200, 200);13 frame.setVisible(true);14 }15 public static void main(String[] args) {16 BorderLayoutEx ex = new BorderLayoutEx();17 }18 }

Note lines 7 to 11; we specify the region the component is to be added.The first parameter of add() is the component itself, in this case a Buttonwhile the second is the position. The result of BorderLayoutEx is shown infigure 5.4.

Figure 5.4: Container managed by BorderLayout

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 54

Page 64: 67544219-OOP-JAVA

Using Panel in Complex GUIs 5.3.1

5.3 Container

Components cannot exist in limbo. They must be added to containers. TheJDK java.awt. package have different containers; they are

1. Panel — Panels are your basic component laying containers. Theycan be added to Frames, Dialog, ScrollPane and Panel.

2. ScrollPane — These are scrollable Panels.

3. Frame — This is a top level application window.

4. Dialog — These are temporary frames for prompting users and fordisplaying messages.

We will examine Panel and Frame in greater detail in the following section.ScrollPane and Dialog are variations of Panel and Frame and will be leftas an exercise for the reader.

5.3.1 Using Panel in Complex GUIs

Panels allow us to create very sophisticated GUIs. Although Panels them-selves are not part of the visible GUI, they provide layout control as we willshortly see. Consider the calculator in figure 5.5.

Figure 5.5: A Java calculator

Although the layout of the caluclator does not resemble any of thosethat we have seen, it is in fact done by cleverly combining 2 layouts and 2Panels. The code to create the calculator is show below:

1 import java.lang.*;2 import java.awt.*;3 public class Calculator4 extends Frame {

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 55

Page 65: 67544219-OOP-JAVA

Frame 5.3.2

5 private String[] label = {"1", "2", "3", "+",6 "4", "5", "6", "-", "7", "8", "9", "*",7 "C", "0", "=", "/"};8 public Calculator() {9 super("Calculator");

10 Panel numberPad = new Panel();11 numberPad.setLayout(new GridLayout(4, 4));12 for (int i = 0; i < label.length; i++)13 numberPad.add(new Button(label[i]));14 Panel base = new Panel();15 base.setLayout(new BorderLayout());16 TextField display = new TextField("0", 10);17 display.setBackground(Color.black);18 display.setForeground(Color.green);19 base.add(display, BorderLayout.NORTH);20 base.add(numberPad, BorderLayout.CENTER);21 add(base, BorderLayout.CENTER);22 pack();23 }24 public static void main(String[] args) {25 Calculator calc = new Calculator();26 calc.setVisible(true);27 }28 }

The key to the calculator application lies in line 20.

line 10 to 13, Creates a Panel call numberPad. This is our calculator’skeypad.

line 14 and 15, We instantiated another Panel and set this to BorderLayout.

line 19, We add the display which we created in line 16 to the “north” ofbase

line 20, Add the numberPad to the “center” of base.

You can add as much layers of Panel as you like to create the desirelayout. A good habit to acquire when developing GUI using AWT is tofirst draw the GUI. Study the GUI and decide on the most optimal way toconstruct the GUI.

The default layout of Panel is FlowLayout.

5.3.2 Frame

All components must be added to a Frame to be visible. Frames are stan-dalone componets; unlike Panel a Frame cannot be added to another Frame

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 56

Page 66: 67544219-OOP-JAVA

Button 5.4.1

even though it is a subclass of Container.The class Frame has the following 2 constructors:

public Frame()Creates an instance of a Frame without a title.

public Frame(String title)Creates an instance of a Frame with the specified title.

Frames by default are BorderLayout managed. To display a Frame youhave to perform the following steps:

1. Set the size of the Frame. You can do this by either using the setSize()or pack() method. pack() tells the Frame to use the smallest possiblesize to display its components.

2. Make the Frame visible. This is done by calling setVisible() withtrue.

If you forgot to set the window size, the Frame will not be visible even thoughyou callsetVisible(). visible.

Other useful methods include:

public void setTitle(String title)Sets or changes the Frame’s title.

public void hide()Hides the Frame. This is equivalent to calling setVisible() withfalse.

public void setMenuBar(MenuBar mb)Sets a menu bar to the Frame. We will look at menus and menu barsin section 5.8.

public void setResizable(boolean b)Allows the Frame to be resized.

public void dispose()Before discarding a Frame instance, it is always good to call thismethod. dispose() frees all resources associated with the Frame in-stance.

5.4 AWT Components

5.4.1 Button

To create a button we us the Button class. The Button allows label but noimages to be display on its face. The following code creates a button withthe label “Press Me!”.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 57

Page 67: 67544219-OOP-JAVA

CheckboxGroup 5.4.4

1 Button button = new Button("Press Me!");

5.4.2 Checkbox

Checkbox provides a simple two state button. Figure 5.6 is created by thefollowing code:

1 Panel panel = new Panel();2 panel.setLayout(new GridLayout(1, 3));3 panel.add(new Checkbox("Adidas"));4 panel.add(new Checkbox("Nike"));5 panel.add(new Checkbox("Reebok"));

Figure 5.6: A Checkbox component

Checkbox has the following 2 constructors:

public void Checkbox(String label)Instantiate a Checkbox with label.

public void Checkbox(String label, boolean state)Instantiate a Checkbox setting the state of the newly created Checkboxto state. The default state is false.

5.4.3 CheckboxGroup

Checkboxes may optionally be part of a CheckboxGroup which simulates“radio button” behaviour. A Checkbox can specify a CheckboxGroup ob-ject when instantiated. When a Checkbox within a CheckboxGroup is se-lected, the CheckboxGroup ensures that the previously selected Checkboxbecomes unselected. The previous Checkbox example can be converted to aCheckboxGroup as follows:

1 CheckboxGroup cbg = new CheckboxGroup();2 Panel panel = new Panel();3 panel.setLayout(new GridLayout(1, 3));4 panel.add(new Checkbox("Adidas", false, cbg));5 panel.add(new Checkbox("Nike", true, cbg));6 panel.add(new Checkbox("Reebok", false, cbg));

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 58

Page 68: 67544219-OOP-JAVA

List 5.4.5

5.4.4 Choice

This class represents a drop down list. A Choice is shown in figure 5.7.

Figure 5.7: A Choice component

The add() method adds an item item with the specified label to Choice.The following illustrates its use:

1 Choice choice = new Choice();2 choice.add("Adidas");3 choice.add("Nike");4 choice.add("Reebok");

Other methods in Choice includes:

public String getSelectedItem()Returns the label of the selected item.

public int getItemCount()Returns the number of items in a Choice.

public void remove(String label)Removes an item.

public void select(String str)Programatically selects an item from a Choice.

5.4.5 List

A List component is used to display a list of strings. The List is scrollable ifnecessary. The List constructor takes two optional arguments that specifiesthe number of visible rows in the list window and whether multiple selectionin the List is possible.

1 List list = new List(4, true);2 list.add("Adidas");3 list.add("Nike");4 list.add("Reebok");

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 59

Page 69: 67544219-OOP-JAVA

Label 5.4.7

creates a List with 4 visible items and allows multiple selection as shownin figure 5.8.

Figure 5.8: A List component

Other userful methods in this class are:

public void add(String item)Adds an item to the List.

public void remove(String item)Removes an item from the List.

public int getItemCount()Returns the number of items in the List.

public String getSelectedItem()Returns the selected item.

public String[] getSelectedItems()Returns all selected items if multiple selection is enabled.

public void select(int index)Programatically selects an item at position index.

public void deselects(int index)Programatically deselects an item at position index.

public void makeVisible(int index)Makes the item at position index visible from the List window.

public void setMultipleMode(boolean b)Enable/disable multiple selection mode for the List.

5.4.6 Label

Label as the name implies are a single line of text used for labelling com-ponents. A label is created as follows:

1 Label label = new Label("Name:");

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 60

Page 70: 67544219-OOP-JAVA

TextArea 5.4.8

5.4.7 TextField

These are single editable line of text. TextField is normally used in formstype applications where the user is required to fill in their personal details.The following creates an entry to solicit a user’s name:

1 Panel panel = new Panel();2 panel.add(new Label("Name: "));3 panel.add(new TextField(30));

The code produces the figure 5.9.

Figure 5.9: A TextField component

Other interesting TextField methods are:

public void selectAll()Highlights the text in the TextField.

public void setEditable(boolean b)A bit like setEnabled() in Component. This method makes the TextFieldeither editable or uneditable.

public void setText(String msg)Set the text msg in the TextField.

public void setCaretPosition(int index)Sets the caret at the specified position.

public void setEchoChar(char c)Displays the character c in the TextField for any characted typedinto the TextField. This is normally used for password entry.

5.4.8 TextArea

This class displays and allows you to edit multi line text. The methodsappendText(), insertText() and replaceText() provides various tech-niques for specifying text to appear in the TextArea. You can also use theabove mentioned TextField methods with TextArea.

The following code creates a TextArea that is 40 columns wide and 5rows high.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 61

Page 71: 67544219-OOP-JAVA

repaint() Method 5.5.3

1 TextArea textArea = new TextArea(5, 40);

Horizontal and vertical scrollbars will automatically appear when required.

5.5 The AWT Paint Cycle

We have seen how most of the components behave. A question arises: whatif we want to customize components? How do we add “wall paper” to aPanel or an image to a Button? To be able to do these and more, we mustfirst understand the AWT paint cycle. The key to customization lies inthe following methods: paint(), update() and repaint(). The previouslymentioned 3 methods are part of Component. Recall that Component is thesuperclass of all components (widgets).

When a component is first displayed, the JVM will call the paint()method of each component in a Frame; these components draw themselveson the screen. The components will redraw themselves again when eitherone of the following 2 events occurs:

Exposure — This happens when we resize a frame, an overlapped portion ofthe frame is exposed or whenever the JVM thinks that the componentrequires to redraw itself on the screen to update its appearance. Inthis case, the JVM will call paint() directly.

Forced — When a program wants to update the screen eg. an animatedbutton needs to draw the next image. The program can call repaint()to force a redraw.

5.5.1 paint(Graphics) Method

The paint() method handles most of the painting of the components. Thesignature for paint() is as follows:

public void paint(Graphics g)

The Graphics parameter is an abstract representation of the screen. What-ever we “draw” on Graphics will appear on the screen. We will look atGraphics in section 5.6 in page 63. To customize a component, we overridethis paint() method.

5.5.2 repaint() Method

Sometimes we want to update a component on the window or the entire win-dow all together. We invoke repaint() which schedules a cal to update().The following sequence of method cals occurs:

repaint() −→ update() −→ paint()

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 62

Page 72: 67544219-OOP-JAVA

Graphics 5.6.1

5.5.3 update(Graphics) Method

update() is an intermediate method call when we call force a redraw butis never involved on an exposure update. Why is this so? The reason isto allow more control over the painting process. The default behaviour ofupdate() is as follows:

1. Clears the component by filling the component with its backgroundcolor.

2. Calls paint() with Graphics that it receives.

For most application, the default behaviour is sufficient. But if you aredoing animation, developing arcade style games or anything along those linesyou might want to override update(). The reason is twofold: firstly, it isquite inefficient to redraw the entire screen; and secondly excessive clearingand redrawing will cause the screen to flicker.

We will not look into this subject any further.

5.6 Graphics

The Graphics is an abstraction of the screen. What you draw on Graphicswill appear on the screen. The Graphics class provides some highleveldrawing methods like drawing lines, ovals, etc. The following is a partial listof methods.

public void drawString(String str, int x, int y)Draws str on (x, y). Note that (x, y) refers to the lower left cornerof the str instead of the the normal upper left corner.

public void drawLine(int x_1, int y_1, int x_2, int y_2)Draws a line from (x_1, y_1) to (x_2, y_2).

public void drawOval(int x, int y, int width, int height)Draws an oval.

public void drawRect(int x, int y, int width, int height)Draws a rectangle.

public void setColor(Color c)Sets the color for the drawing pen.

public void setFont(Font f)Sets the font to be used.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 63

Page 73: 67544219-OOP-JAVA

Using Font 5.7

5.6.1 Using Font

JDK 1.1 supports the following font types: Serif, SansSerif, Monospaced,Dialog and DialogInput. Besides the JDK 1.1 include fonts, you can alsouse the fonts installed on the native operating system. The following codesnippet gets a list of installed fonts from the operating system which youcan then use.

1 Toolkit toolkit = Toolkit.getDefaultToolkit();2 String[] installedFonts = toolkit.getFontList();

The Font class has the following constructor:

public Font(String name, int style, int size)

name This is the name of the font. You can either use the JDK 1.1default font or query the operation system for the required font.

style The style can be one of the following: PLAIN, BOLD or ITALICor the sum of BOLD and ITALIC.

size The size of the font.

The following creates a ”Monospaced”, 20 point font. The font style isbold and italicised. The output is shown in figure 5.10.

1 public void paint(Graphics g) {2 g.setFont(new Font("Monospaced", Font.BOLD + Font.ITALIC, 20));3 g.drawString("Hello World!", 10, 100);4 }

Figure 5.10: An example of using font

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 64

Page 74: 67544219-OOP-JAVA

Customizing Components 5.7

5.7 Customizing Components

We have seen all the required pieces of Java techology to allows us to cus-tomize components. Lets put these different pieces together and see how itall fits together. We will create a customize Panel by giving it a wallpaperof squares as shown in figure 5.11.

Figure 5.11: PrettyPanel with a button

The code to create PrettyPanel is as follows:

1 import java.lang.*;2 import java.awt.*;3 public class PrettyPanel4 extends Panel {5 public PrettyPanel() {6 setBackground(Color.black);7 }8 public void paint(Graphics g) {9 Dimension size = getSize();

10 g.setColor(Color.red);11 int count = size.width/10;12 for (int i = 1; i < count; i++)13 g.drawLine(i*10, 0, i*10, size.height);14 g.setColor(Color.blue);15 count = size.height/10;16 for (int i = 1; i < count; i++)17 g.drawLine(0, i*10, size.width, i*10);18 }19 }

The explanation is as follows:

line 2, Do not forget to import the java.awt package.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 65

Page 75: 67544219-OOP-JAVA

MenuBar 5.8.2

line 5, Since constructors are not inherited, we provide a constructor.

line 6, Just for fun, we set the default background to black.

line 8, We override the paint() method to provide our own drawing.

line line 9, Get the size of the Panel. We need to know the size so thatwe can draw the appropriate number of lines. Remember, Graphicsrepresents the display area of PrettyPanel and getSize() gives usthis area.

line 10 to 13, We draw red vertical lines, 10 pixel apart.

line 14 to 17, We draw blue horizonal lines, 10 pixel apart.

Using PrettyPanel is like using your regular Panel; consider the follow-ing code:

1 PrettyPanel pretty = new PrettyPanel();2 pretty.add(new Button("Press Me!"));

5.8 Adding Menus to Frame

You can set menus to frame. These are the normal pulldown menus thatappear on top of a frame. To add a menu to a Frame, you need to performthe following steps:

1. Add a MenuBar to a Frame by calling setMenuBar() method. Only 1MenuBar instance can be added to a Frame.

2. Add Menus to MenuBar. These will appear as labels on the MenuBar.

3. Add MenuItem and/or CheckboxMenuItem to Menu.

4. You can optionally add a Menu within a Menu. The former becomes asubmenu of the latter.

5.8.1 MenuBar

A MenuBar is required before you can create menus. The following codeadds a MenuBar to a Frame:

1 Frame frame = new Frame("Menu");2 MenuBar menuBar = new MenuBar();3 frame.setMenuBar(menuBar);

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 66

Page 76: 67544219-OOP-JAVA

MenuItem and CheckboxMenuItem 5.9

5.8.2 Menu

Menus are labels that are displayed on the MenuBar. We will now add 2menus, “File” and “Edit” to a MenuBar. The following code is a continuationof the example form the previous section.

1 Menu fileMenu = new Menu("File");2 Menu editMenu = new Menu("Edit");3 Menu aboutMenu = new Menu("About");4 menuBar.add(fileMenu);5 menuBar.add(editMenu);6 menuBar.setHelpMenu(aboutMenu);

Line 6 adds a help menu to the MenuBar. At the name implies, a helpmenu provides help, information and the usual about dialog box. You canonly set one help menu per MenuBar instance.

Figure 5.12: An example of a Frame with a MenuBar

5.8.3 MenuItem and CheckboxMenuItem

MenuItem and CheckboxMenuItem are the leaf node in Menu. Typically,MenuItem and CheckboxMenuItem would represent the actual functions thatwe wish to provide to the user. MenuItem and CheckboxMenuItem must beadded to Menu. We now add “Save”, “Save As. . . ”, “Open” and “Exit” to“File” menu. Again, the code continues from the previous example.

1 fileMenu.add(new MenuItem("Save"));2 fileMenu.add(new MenuItem("Save As..."));3 fileMenu.add(new MenuItem("Open"));4 fileMenu.addSeparator();5 fileMenu.add(new MenuItem("Exit"));

The addSeparator() on line 4 adds a line to the menu; see figure 5.13.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 67

Page 77: 67544219-OOP-JAVA

AWT Events 5.9

Figure 5.13: A menu with MenuItems

5.9 AWT Events

We have seen how easy it is to use AWT components to create GUI. Butour GUI is still deviod of life. The GUI does not know how to respond tomouse clicks. For that we need to understand events which we will examinein the chapter 7.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 68

Page 78: 67544219-OOP-JAVA

Chapter 6

Inner Class

The JDK 1.1 introduces a number of new features to the Java language;one of these is inner classes. Inner classes are simply classes within classes.There are 4 categories of inner classes:

Nested top level classes and interfaces Classes and interfaces definedwith the static keyword. Cannot access containing class’ methodsand members.

Member class Member classes are classes without the static keyword.Member class can access containing class’ methods and members, evenprivate denoted ones.

Local class Local classes are like member classes except that they are de-fined within a block, typically within a method. Hence they are onlyvisible within a block.

Anonymous class These are nameless classes. They are defined and usedonly once.

Of the 4 types of inner classes mentioned above, we personally feel thatmember classes and anonymous classes are the most useful. As such wewill be focusing our attention on them. The remainding 2 inner classes arevariations of member and anonymous class.

6.1 Member Class

Member class are particularly useful for defining utility or helper classes.Prior to JDK 1.1, helper classes must be defined as a separate “top level”class. These helper class are not very closely related to the main class inthe sense that they cannot access the main class’ internal methods andmembers. You have to resort to parameter passing. This can sometimes bevery crumblesome. Member classes overcomes these difficulties.

When using member class, you have to remember the following:

69

Page 79: 67544219-OOP-JAVA

Member Class 6.1

• An instance of a member class must always be associated with aninstance of its containing class.

• A member class can access its methods and members as well as thoseof its containing class, including private methods and members.

We will demonstrate the use of member class by adding the followingfeatures to the Account on page 43 so the it performs the following:

• When a subclass of Account is instantiated, it will install a defaultinterest calculation method.

• A user can install its own interest rate calculation method via thesetInterestCalculation() method.

The new Account class looks like this:

1 public abstract class Account {2 private String name;3 private float balance;4 . . .5 private Interest interest;6 public class DefaultRate7 implements Interest {8 public float calculate(float amt) {9 return (balance * 0.1F);

10 }11 }12 public Account(String n, int no) {13 interest = new DefaultRate();14 }15 . . .16 public void setInterestCalculation(Interest i) {17 interest = i;18 }19 public float calculateInterest() {20 return (interest.calculate(getBalance()));21 }22 . . .23 }

The explanation for the above code is as follows:

line 6 to 11, This is the member class. Notice that declaring a memberclass is just like defining a regular top level class. Our inner class iscalled DefaultRate and it implements the Interest interface.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 70

Page 80: 67544219-OOP-JAVA

Referencing Containing Class’ Members 6.1.1

line 9, Since member class can access its containing class’ members, wedirectly access balance to calculate the interest ignoring amt.

line 13, When we instantiate Account we set the interest member withan instance of DefaultRate.

When do we use member class? We offer the following guidelines:

• When you require a helper or a utility class.

• You are defining a class and this class is of no use to any other classesexcept one.

• Two classes have interwind relationship.

Compiling Account will now produce not 1 but 2 classes. In addition to theAccount.class, you will also find the class Account$DefaultRate.classwhich is the inner class.

6.1.1 Referencing Containing Class’ Members

Recall that all instance methods and members are implicitly prefixed by athis. Does this apply for inner classes as well? Lets take a look again atline 9 of Account which is reproduced below:

return (balance * 0.1F);

If we follow the usual rule and rewrite the above to this

return (this.balance * 0.1F);

we would get an error message. This is because “this” refers to the currentinstance and the current instance which is an instance of DefaultRate doesnot contain a member called balance.

balance is actually the containing class’ member. So using this wouldbe wrong. To access the containing class’ member, we use a variation of thethis. The syntax is <class_name>.this where <class_name> is the nameof the containing class. Line 9 would look like the following when writtenin its entire form:

return (Account.this.balance * 0.1F);

The following class further illustrates this concept:

1 public class Outer {2 public String msg = "outer";3 public class Inner {4 public String msg = "inner";5 public class InnerInner {

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 71

Page 81: 67544219-OOP-JAVA

Instantiating Member Classes 6.2

6 public String msg = "innerinner";7 public void print() {8 System.out.prinln("msg = " + msg);9 System.out.prinln("msg = " + InnerInner.this.msg);

10 System.out.prinln("msg = " + Inner.this.msg);11 System.out.prinln("msg = " + Outer.this.msg);12 }13 }14 }15 }

The output will be

msg = innerinnermsg = innerinnermsg = innermsg = outer

6.1.2 Instantiating Member Classes

Instantiating member classes presents a few problems. Remember that amember class must always be associated with its containing instance. Sowe have to instantiate the containing class first before creating the memberclass. The syntax for instantiating a member class is <containing_instance>.new.The following code snippet creates an instance of all member class in Outer:

1 Outer outer = new Outer();2 Outer.Inner inner = new outer.new Inner();3 Outer.Inner.InnerInner innerInner = new inner.new InnerInner();4 innerInner.print();

Note the following about instantiating member classes.

line 1, Creates an instance of Outer first.

line 2, Creates an instance of Inner within outer.

line 3, Creates an instance of InnerInner within inner.

In the new, we name the class to be created relative to the instance thatis going to contain it like so

inner.new InnerInner()

and not

inner.new Outer.Inner.InnerInner()

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 72

Page 82: 67544219-OOP-JAVA

Anonymous Class 6.2

6.2 Anonymous Class

Anonymous classses are classes without names. Unlike member class whereyou have to define and instantiate the class to be used; anonymous classescombine these 2 steps into 1.

Let’s take a look at an example of anonymous class before discussing ingreater detail. We rewrite (again!) Account using anonymous class insteadof member class as in page 70.

1 public abstract class Account {2 private String name;3 private float balance;4 . . .5 private Interest interest;6 public Account(String n, int no) {7 . . .8 interest = new Interest() {9 public float calculate(float amt) {

10 return (balance * 0.1F);11 }12 };13 }14 . . .15 }

The lines between 8 and 12 inclusive defines an anonymous class. Anony-mous classes can be defined in 2 ways:

new <class_name>([<type> <param_1> ...]) {<class_body>

}

or

new <interface_name>() {<interface_body>

}

When you are creating an anonymous class using an interface, rememberyou are implementing the interface so you must implement all the interface’smethod.

The anonymous class syntax combines class definition with instantiation.Anonymous classes cannot have constructors. However if you really need toinitialize the class you can resort to “instance initializers”. Refer to thefollowing section.

When do you use anonymous class? You would use them if

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 73

Page 83: 67544219-OOP-JAVA

Instance Initializers 6.2.1

• A class has a very short body.

• Only one instance of the class is needed.

• The class is use immediately after being defined.

6.2.1 Instance Initializers

Instance initializers are arbitrarily blocks of code in a class definition. Theyare executed after the superclass’ constructor but before the class’ construc-tor. If a class has multiple instance initializers, then they are executed in theorder in which they appear. We add an instance initializer to the previousanonymous class example. The anonymous class calculates the interest rateto use based on the month; only the constructor is shown:

1 . . .2 public Account(String n, int no) {3 . . .4 interest = new Interest() {5 private float monthlyRate[] = { 0.1F, 0.07F, 0.1F, 0.1F,6 0.1F, 0.12F, 0.1F, 0.1F, 0.08F, 0.1F, 0.1F, 0.05F };7 private float rate; {8 rate = monthlyRate[9 (Calendar.getInstance()).get(Calendar.MONTH)];}

10 }11 public float calculate(float amt) {12 return (balance * rate);13 }14 }15 }16 . . .

The instance initializer (lines 7 to 10 ) gets the appropriate interest rateaccording to the month when the anonymous class is instantiated.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 74

Page 84: 67544219-OOP-JAVA

Chapter 7

Handling AWT Events

You are asked to develop a forms front end, much like the one shown infigure 7.1. Your front end has to be generic as lots of existing and newyet undevelop applications will be using it. It must be modular and allowson-the-fly customization; eg. one application uses the the HKID field as anindex into a database to verify the input data while another runs an hashfunction to verify its correctness. More importantly, if any of the underlyinginformation changes, the form must be able to update itself.

Figure 7.1: A typical GUI front end

None of these requirements presents an insurmountable programmingchallange. If you were to write the code that handles each requirement,it would add significant coding to your overall effort. The way to tackle itwould be to implement the said GUI using the model/view/controller (MVCfor short) introduced in Smalltalk-80.

We will begin this section by looking at the MVC architecture and how

75

Page 85: 67544219-OOP-JAVA

The Model 7.1.1

they influence the desgin of AWT. We will then move on to handling AWTevents and eventually creating our very own custom events.

7.1 The MVC Architecture

The MVC was designed to reduce the overall programming effort by dele-gating specific responsibilities to the model, view and controller. Figure 7.2illustrates the MVC architecture.

Model

Controller

View

View

View

Controller

Controller

Figure 7.2: The model/view/controller architecture

The MVC has the following benefits:

• Encourages the application to be data (model) centered instead of userinterface (view) centered.

• A well defined separation between components of a program. Eachcomponent can be written separately.

• Each component has a well define set of API. Future enhancementsand components written to the API can replace either the model, viewor controller.

• The binding between the 3 components are dynamic and occurs atruntime.

7.1.1 The Model

The model is an object that represents the data. This can be a file, a matrixstored in an array or records held a database. The model has no specific

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 76

Page 86: 67544219-OOP-JAVA

Identifying Source, Listener and Event Objects 7.2.2

knowledge of either its views or controllers. If the model changes, the modelis responsible for notifying its view. If a particular piece of data requiresvalidation for example, the model is responsible for invoking the appropriatecontroller.

7.1.2 The View

Views are the faces of the model. A record’s data can be represented bydifferent views. Examples of views include the traditional window GUI, aHTML page, LED displays or your humble text. The view is also responsiblefor representing the data in different forms: as a graph, a pie chart, etc.

7.1.3 The Controller

The controller provides a means of interacting with the model. Validatingdate fields and checking the existance of records are just 2 examples of whatyou can do with controllers.

7.2 Events

Events are messages sent from one object to another, notifying the recipientthat something interesting has happened. Events are key to implementingMVC in Java. A view might sent out an event, notifying the model that theuser has changed portion of the data. The model, on receiving the event,fires another event to the various controllers to validate the new data, forexample. When the controllers have completed their job, the model savesthe data into a database.

Components sending the event, the event source, is said to fire the event;the components receiving the events are called event listeners. Events canbe single or multicast.

7.2.1 The AWT Event Model

The current AWT event model, introduced as part of the revamped AWTin JDK 1.1, is called the delegate model. It is comprised of event listeners,event sources and event objects.

The delegate model works as follows: an event source sends a notifi-cation to the listener and passing to the listener an event object. Eventlisteners must register themselves with event sources in order to receivingnotifications. Figure 7.3 is a diagram of this interaction.

7.2.2 Identifying Source, Listener and Event Objects

The entire AWT is based on the delegate model. Capturing a Button pressedor a mouse clicked require us to register and capture the correct event.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 77

Page 87: 67544219-OOP-JAVA

Identifying Source, Listener and Event Objects 7.2.2

EventListener

EventSource

EventObject

Registerevent listenerFire event

Figure 7.3: Event source and listeners

As it turns out, the delegate model follows a certain naming convention,very much like the getter/setter method for encapsulating properties. Thenaming convention are as follows:

Event source Event sources provides registration and deregistration forlisteners. To identify them look for the following signature:

• public void addXXXListner(XXXListener)

• public void removeXXXListner(XXXListener)

Event listener Look for classes that implements the XXXListener inter-face. These are listeners for the XXX event.

Event object An event object has the following name XXXEvent. Everymethod in the XXXListener interface will have this one and only objectas parameter.

Lets look at a concrete example: to capture a Button click, we mustcapture the “action” event. Using the above mentioned naming conventions,we know the following:

• Action event sources are those objects which have the following meth-ods:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 78

Page 88: 67544219-OOP-JAVA

Event Listener Interface 7.2.3

public void addActionListener(ActionListener l)public void removeActionListener(ActionListener l)

• Action event listeners are those objects which implements the ActionL-

istener interface.

• ActionEvent is the event object passed from the event source to theevent listener.

The table 7.1 show a list of all AWT events.

Component Listener Interface Listener Methods Event ClassButton ActionListener public void actionPerformed() ActionEvent

List

MenuItem

TextField

Scrollbar AdjustmentListener public void adjustmentValueChanged() AdjustmentEvent

Component ComponentListener public void componentHidden() ComponentEvent

public void componentMoved()

public void componentResized()

public void componentShown()

Container ContainerListener public void componentAdded() ContainerEvent

public void componentRemoved()

Component FocusListener public void focusGained() FocusEvent

public void focusLost()

Checkbox ItemListener public void itemStateChanged() ItemEvent

CheckboxMenuItem

Choice

List

Component KeyListener public void keyPressed() KeyEvent

public void keyReleased()

public void keyTyped()

Component MouseListener public void mouseClicked() MouseEvent

public void mouseEntered()

public void mouseExited()

public void mousePressed()

public void mouseReleased()

Component MouseMotionListener public void mouseDragged() MouseEvent

public void mouseMoved()

TextComponent TextListener public void textValueChanged() TextEvent

Window WindowListener public void windowActivated() WindowEvent

public void windowClosed()

public void windowClosing()

public void windowDeactivated()

public void windowDeiconified()

public void windowIconified()

public void windowOpened()

Table 7.1: AWT event list

7.2.3 Event Listener Interface

The event listener interface is an interface that contains methods denotingspecific events. These methods are called event handling methods. When

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 79

Page 89: 67544219-OOP-JAVA

A Button Example 7.2.6

an event occurs, the appropriate event method is invoked. Related eventhandling methods are grouped into a single interface eg. the MouseListenerinterface contains the following methods:

mousePressed(MouseEvent)mouseClicked(MouseEvent)mouseEntered(MouseEvent)mouseExited(MouseEvent)mouseReleased(MouseEvent)

An object that is interested in listening for mouse events will have to imple-ment this interface. Notifications are made by invoking specific methods inthe MouseListener interface; for example when a mouse button is pressed,the event source will call mouseClicked() method.

7.2.4 Event Source

Event sources are objects that fire events. As noted earlier, event sourcesprovides events registration and deregistration methods. A listener calls theappropriate addXXXListener() to register itself as a listener and removeXXXListener()to stop receiving events notification.

Multiple listeners can register with a source to receive event notifications.

7.2.5 Event Objects

Event objects encapsulates all information pertaining to a specific event. Inthe case of a mouse event, the MouseEvent object would contain informationlike the number of mouse clicks and the position of the mouse pointer whenthe event occur. Event objects are passed from the source to the listenervia the event handling methods.

All AWT’s event objects are subclass of AWTEvent in the java.awt.eventpackage. The getSource() method which all XXXevent inherits returns theevent source object. So if a reference fredButton fires a ActionEvent, thengetSource() will return a reference to fredButton.

7.2.6 A Button Example

The AWT does not have a rollover button. We will use AWT event toimplement just such a button. The rollover button will do the following:when the mouse pointer moves over the surface of the button, the button’sbackground will turn red while the button’s label will be black. When themouse pointer leaves the button, the button’s color is reversed.

The steps are as follows:

1. The RolloverButton is a subclass of Button.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 80

Page 90: 67544219-OOP-JAVA

A Button Example 7.2.6

2. The listener must implement the MouseListener.

3. Register the listener with the event source which in this case is theRolloverButton.

4. Perform the necessary color change in the event handler methods.

The code is as follows:

1 import java.lang.*;2 import java.awt.*;3 import java.awt.event.*;4 public class RolloverButton5 extends Button6 implements MouseListener {7 public RolloverButton(String label) {8 super(label);9 mouseExited(null);

10 addMouseListener(this);11 }12 public void mouseEntered(MouseEvent mEvt) {13 setBackground(Color.red);14 setForeground(Color.black);15 }16 public void mouseExited(MouseEvent mEvt) {17 setBackground(Color.black);18 setForeground(Color.red);19 }20 public void mouseClicked(MouseEvent mEvt) { }21 public void mousePressed(MouseEvent mEvt) { }22 public void mouseReleased(MouseEvent mEvt) { }23 }

The explanation for the RolloverButton class is as follows:

line 3, To capture AWT events, you must import java.awt.event.

line 5, We reuse Button class since RolloverButton is essentially a Button.

line 6, We must implement MouseListner interface to capture mouse events.

line 9, Our specification is that when the mouse pointer leaves the button,the button returns to a black background and red foreground colorpair. Here, we fake a mouseExited() event to set the initial buttonbehaviour.

line 10, We register with RolloverButton that we are interested in receiv-ing mouse events. Notice that we are adding ourself as a listener viz.we are the source as well as the listener.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 81

Page 91: 67544219-OOP-JAVA

Another Button Example 7.2.7

line 12 to 22, These methods are part of the MouseListener interface andmust be implemented by RolloverButton. We are only interested inmouseEntered() and mouseExited()method. The others have emptymethod bodies.

When the mouse enter an instance of RolloverButton, mouseEntered()will be invoked. In mouseEntered(), we set the background color to redand the foreground to black. Similarly, when the mouse leaves the but-ton instance, mouseExited() is invoked. Figure 7.4 shows 2 instances ofRolloverButton, one with a rollover face.

Figure 7.4: A RolloverButton example

7.2.7 Another Button Example

The following code prints out “hello world—” whenever the RolloverButtonis pressed. Note the use of anonymous class to creates a listener in line 9 to13.

1 import java.lang.*;2 import java.awt.*;3 import java.awt.event.*;4 public class ButtonEventEx5 extends Frame {6 public ButtonEventEx() {7 super("Button Event");8 RolloverButton button = new RolloverButton("Press Me!");9 button.addActionListener(new ActionListener() {

10 public void actionPerformed(ActionEvent aEvt) {11 System.out.println("hello world!");12 }13 });14 setLayout(new FlowLayout());15 add(button);16 pack();17 }18 public static void main(String[] args) {

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 82

Page 92: 67544219-OOP-JAVA

Creating Customized Events 7.3.1

19 ButtonEventEx ex = new ButtonEventEx();20 ex.setVisible(true);21 }22 }

7.3 Creating Customized Events

How do we create and fire our own events? Short answer: not very difficult.Remember, events in the JDK 1.1 are fired by invoking specific methods inthe listener objects. The steps for creating events is as follows:

Define the event object class This is the event object that is passedfrom the source to the listener.

• The event class must be a subclass of EventObjectwhich is foundin package java.util.

• Call your event class XXXEvent according to the JDK namingconventions.

Define the listener interface This is the interface that all listener mustimplement.

• Define an interface that extends EventListener interface whichis in package java.util. The EventListener interface is a“marker” interface.

• The event interface is call XXXListener according to the JDKnaming conventions.

• Every method in the listener interface denotes a specific event.Each method should return void and take one parameter, whichis the event object. An example of an event handler method isas below:

public void someMethod(XXXEvent xEvt);

Define the event source This could be any class that is firing the event.

• Add event registration and deregistration method. These meth-ods has the following forms:

public void addXXXListener(XXXListener l)public void removeXXXListener(XXXListener l)

• For each event handler method in the listener interface, definean event firing method. These firing method is responsible forinstantiating the event object and calling the appropriate eventhandler method.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 83

Page 93: 67544219-OOP-JAVA

AccountListener Interface 7.3.3

7.3.1 Account Class Again

We will now add additional features to Account class which will allow anyinstance of Account to fire an event whenever we deposit or withdraw fromit. The event will contain the amount deposited or withdrawn.

7.3.2 The AccountEvent Object

Information pertaining to a particular transction in Account is encapsulatedin the AccountEvent an event object. The event object will have a read onlyproperty called amount which gives the amount deposited or withdrawn.The code for AccountEvent is as follows:

1 import java.lang.*;2 import java.util.*;3 public class AccountEvent4 extends EventObject {5 private float amount;6 public AccountEvent(Object src, float amt) {7 super(src);8 amount = amt;9 }

10 public float getAmount() {11 return (amount);12 }13 }

The explanation is as follows:

line 2, Remember to import java.util package because the EventObjectclass is in it.

line 6, The constructor takes 2 parameters; src is the event source and amtis the amount deposited or withdrawn.

line 7, Calls the superclass’ constructor and sets the event source.

line 10 to 12, Getter for the amount properties. Notice that this is a readonly property. This is because event objects are considered immutableso there are no setter methods.

7.3.3 AccountListener Interface

The AccountListener interface contains event handling methods that willbe called when a specific event occurs. Java convention dictates that theseevent handling methods be defined in an interface that is a subclass of

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 84

Page 94: 67544219-OOP-JAVA

Event Listener Registration/Deregistration 7.3.4

EventListener. A class that wants to handle any of the events defined inthe AccountListener interface should implement that interface.

So the AccountListener interface looks like this:

1 import java.lang.*;2 import java.util.*;3 public interface AccountListener4 extends EventListener {5 public void moneyDeposited(AccountEvent aEvt);6 public void moneyWithdrawn(AccountEvent aEvt);7 }

7.3.4 Event Listener Registration/Deregistration

Inorder for listeners to be notified of potential events, the event listenershave to register themseleves the the event source. The event source class,Account in this case, must provide registration and deregistration method.The account event registration and deregistration method has the followingsignature:

public void addAccountListener(AccountListener l)public void removeAccountListener(AccountListener l)

The required modification to Account class is as follows:

1 import java.lang.*;2 import java.util.*;3 public abstract class Account {4 private String name;5 private float balance;6 private Vector listeners;7 . . .8 private Interest interest;9 public Account(String n, int no) {

10 . . .11 listeners = new Vector();12 }13 public void deposit(float amt) {14 if (amt >= 0) {15 balance += amt;16 fireMoneyDeposited(new AccountEvent(this, amt));17 }18 }19 public void withdrawal(float amt) {20 if ((amt <= balance) && (amt >= 0)) {

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 85

Page 95: 67544219-OOP-JAVA

Event Listener Registration/Deregistration 7.3.4

21 balance -= amt;22 fireMoneyWithdrawn(new AccountEvent(this, amt));23 }24 }25 public void addAccountListener(AccountListener l) {26 listeners.addElement(l);27 }28 public void removeAccountListener(AccountListener l) {29 listeners.removeElement(l);30 }31 private void fireMoneyDeposited(AccountEvent aEvt) {32 Vector tmpV;33 synchronized(listeners) {34 tmpV = (Vector)listeners.clone();35 }36 for (int i = 0; i < tmpV.size(); i++) {37 AccountListener l = (AccountListener)tmpV.elementAt(i);38 l.moneyDeposited(aEvt);39 }40 }41 private void fireMoneyWithdrawn(AccountEvent aEvt) {42 . . .43 }44 . . .45 }

Before we discuss the lengthy code, we must remember that Accountclass is an event source. As an event source, Account must do the following:

1. Provide event registration method.

2. Provide event deregistration method.

3. Notify listeners when an event has occured.

Now lets turn our attention to the code; the following lines are noteworthy:

line 6, 11, The Vector class a dynamic array which can be used to storearbitarily objects. We will use an instance of Vector called listenersto keep references of listeners who have registered with us to receiveevent notification. Refer to your JDK documentation for details onVector class. It is under java.util package.

line 23 to 25, This is the event registration method. When a listener registerwith us, we keep a reference of the listener interface. All listener arekept in the listeners.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 86

Page 96: 67544219-OOP-JAVA

Event Listener Registration/Deregistration 7.3.4

line 26 to 28, This is the event deregistration method. Listeners can chooseto stop receiving events by calling this method. We remove the previ-ously registered listener from listeners.

line 16, After someone has deposited some money, we need to notify ourlisteners. To do this we call fireMoneyDeposited() method whichdoes the notification. We also need to pass an event object along withthe notification. The event object consist of the source of the event(this) and the amount that is deposited (amt).

line 31 to 33, Before we notify our listeners of an event we first make acopy of the listeners. This is to prevent new listeners being addedwhile we are notifying the listeners. The synchronized keyword is tolock listeners while being copied. We will look at synchronized inchapter 12.

line 34 to 36, In these 3 lines we go through every listener that have beenregistered with us and we call the its fireMoneyDeposited() methodthus notifying it of the deposit event.

The figure 7.5 illustrates this entire process:A word of caution: event notification is a method invocation; control is

passed from the event source to the listener. The listener should not “hold”the control. It should return the control to the source as soon as possible,otherwise you will holdup event delivery to other listeners.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 87

Page 97: 67544219-OOP-JAVA

Event Listener Registration/Deregistration 7.3.4

public void addAccountListener(AccountListener l)

EventListener

AccountEvent

public class Fredimplements AccountListener {public void moneyDeposited(AccountEvent aEvt) {

. . .}public void moneyWithdrawn(AccountEvent aEvt) {

. . .}

}

Event Sourcelisteners

Register listener

Reference listeners

Fire event

Figure 7.5: Notifying listeners

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 88

Page 98: 67544219-OOP-JAVA

Chapter 8

Exceptions

Program bugs and program crashes are invevitable unless you plan to con-tinue writing “hello world” for the rest of your life. Defensive program-ming assumes all codes to be erraneous and proceeds to inter spread errorchecks to normal code. Sometimes you can spend more coding time onchecking and handling errors than actually writing your program.

8.1 Exceptions

Java’s way of defensive programming is via the use of its exceptions mech-anism. Exceptions has the following two benefits:

• They allow you to separate error handling code from normal code.

• You can determine exactly who handles an error. There is a welldefined chain of responsibility; exception travel up the method callstack until it is handled by one of the method. Unhandle exceptionare captured and reported by the JVM.

An exception is an event thrown either by the JVM or by your code toindicate that an error has occured. We will begin our exception discussionby learing how to glean useful information for exception stacks. We will thenproceed to looking at Java exception mechanism; we will end this chapterby creating our very own exceptions.

8.1.1 An Exceptional Example

Let’s look at the following code

1 import java.lang.*;2

3 public class ExceptionEx {4 public String[] msgs = {"bonjour", "chou san",

89

Page 99: 67544219-OOP-JAVA

Exception Objects 8.1.2

5 "selamat pagi" };6 public void doit() {7 int i = 0;8 while (i < msgs.length)9 System.out.println(msgs[++i]);

10 }11 public static void main(String[] args) {12 ExceptionEx ex = new ExceptionEx();13 ex.doit();14 }15 }

which will generate the following exception stack example when executed:

1 chou san2 selamat pagi3 java.lang.ArrayIndexOutOfBoundsException: 34 at ExceptionEx.doit(ExceptionEx.java:9)5 at ExceptionEx.main(ExceptionEx.java:13)

The stack consists of 2 parts, line 3 indicates the type of exception thathas occured and lines 4 and 5 shows the methods on the call stack. The ex-ception type is ArrayIndexOutOfBoundsException which occurs in doit()method at line 9 in the ExceptionEx.java file. Notice how the exception“travels” from doit() to main() until it reaches the JVM which prints outthe exception.

Examining line 9 we find the offending line:

System.out.println(msgs[++i]);

Apparently the programer should have written i++ instead of ++i whichresulted in the exception.

8.1.2 Exception Objects

A exception object is an object that represents the state of the exception.When an exception occurs the JVM captures the environment at that in-stance. This captured information is the exception object. You can examinethe exception object to find out what is wrong and recover from it.

All exception objects are subclass of Exception1 and has the followingmethods:

public void printStackTrace()Prints out the stack trace at the point of the exception. An exampleof this output is shown in page 90.

1Actuall all exceptions are subclass of Throwable.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 90

Page 100: 67544219-OOP-JAVA

try-catch Block 8.1.3

public String getMessage()Returns the exception’s error message, if any.

8.1.3 try-catch Block

A try-catch block establishes a block of code that is to have its exceptionand abnormal exits handled. A catch established what exception that theblock should catch and take whatever action necessary to deal with theexceptional condition. The syntax of a try-catch block is as follows:

try {<exception_block>

} catch (<exception_class> e) {<exception_handler>

}

Lets look at a try-catch block; we will rewrite the example on page 89to handle the ArrayIndexOutOfBoundsException and recover from it.

1 . . .2 public void doit() {3 int i = 0;4 while (i < msgs.length)5 try {6 System.out.println(msgs[++i]);7 } catch (ArrayIndexOutOfBoundsException e) {8 System.out.println("Oops! Busted index. Reseting");9 i = 0;

10 }11 }12 . . .

The explanation for the exception code snippet is as follows:

line 5 to 7, These lines define the exception block, viz. the block of codethat could generate an exception. Our block of code consist of 1 singleline vis.the { } between lines 5 and 7.

line 7, The catch defines what exception to catch. This is specified asa formal parameter immediately after catch. If such an exception israised in the exception block, program control is passed to the excep-tion handler. Notice that the catch block looks a lot like a methoddeclaration. Also, note the“e”. This is the exception object.

When we run the ExceptionEx again, we get the following output:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 91

Page 101: 67544219-OOP-JAVA

And finally... 8.1.4

chou sanselamat pagiOops! Busted index. Resetingchou sanselamat pagiOops! Busted index. Resetingchou sanselamat pagi

When i equals to 3, line 6 of the code snippet above generated an excep-tion; the exception object is caught by catch and the exception handleris executed. We see the “Oops!” message printed out and i s reset to 0.When the exception handler completes, the program returns to while andthe entire process is repeated.

You can catch multiple exception within an exception block. This isdone by adding multiple catch to the exception block; the previous codesnippet is modified to catch 2 exceptions as below:

1 . . .2 public void doit() {3 int i = 0;4 while (i < msgs.length)5 try {6 System.out.println(msgs[++i]);7 } catch (ArrayIndexOutOfBoundsException e) {8 System.out.println("Oops! Busted index. Reseting");9 i = 0;

10 } catch (NullPointerException e) {11 System.out.println("Oops! Did not initialize array");12 break;13 }14 }15 . . .

When an exception is thrown in a multi catch blocks, it is caught by thefirst catch block with the appropriate exception object type. Only one catchblock will be executed.

Please note that the previous code snippet has a bug in the array access.You should always correct a bug rather than using a try-catch to circumventit.

8.1.4 And finally...

The finally keyword is generally used to clean up after a try or a catch.It defines a block of code that is always executed regardless of whether an

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 92

Page 102: 67544219-OOP-JAVA

And finally... 8.1.4

exception is thrown. This is also true when you execute a return, continueor break. Lets take a look at an example :

1 . . .2 public void readFile(String file) {3 FileInputStream fis = null;4 int ch;5 try {6 fis = new FileInputStream(file);7 while ((ch = is.read()) != -1)8 System.out.println(ch);9 } catch (IOException e) {

10 System.out.println(e.getMessage());11 } finally {12 is.close();13 }14 }15 . . .

Line 7 reads a character for a FileInputStream. The read() method maythrow a IOException if it encountered an error during the read. But re-gardless of whether an IOExceptiion exception is thrown or not, the abovecode snippet will gurantee to close the file because we have the close()(line 12 ) in a finally block. You can also use a finally without a catchclause. We will cover I/O in the next chapter.

There are 4 possible scenerios to a try-catch-finally block. They are

Forced exit is when you forced program control to be passed out of a tryblock. This is done using a return, continue or break.

Normal completion is when the code in a try-catch-finally block com-pletes normally.

Caught exception thrown refers to an exception thrown that is specifiedin a catch.

Uncaught exception thrown is when an exception is thrown and thisexception is not specified in a catch. This category of exception isalmost always a RuntimeException.

If we have the following code skeleton

try {// Point 1

} catch ( . . .) {// Point 2

} finally {

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 93

Page 103: 67544219-OOP-JAVA

Generating Exceptions 8.1.6

// Point 3}

// Point 4

the execution path of the above mentioned scenerios are as follows:Forced Point 1, Point 3, Point 4Normal Point 1, Point 3, Point 4Caught Point 1, Point 2, Point 3, Point 4Uncaught Point 1, Point 3, Point 4

8.1.5 Declaring Exceptions

Sometimes you may not choose to handle an exception but pass it on thecalling method. In this case you must declare the out going exception aspart of your method declaration. The readFile() method on page 93 ismodified so that the caller instead of readFile() is responsible for handlingIOException.

1 . . .2 public void readFile(String file)3 throws IOException {4 FileInputStream fis = null;5 try {6 int ch;7 fis = new FileInputStream(file);8 while ((ch = is.read()) != -1)9 System.out.println(ch);

10 } finally {11 is.close();12 }13 }14 . . .

Note line 3, you use throws to declare that there is an exception to becaught. It is the responsibility of the caller to handle it within a try-catchblock.

8.1.6 Generating Exceptions

You can generate your own exception with a throw (note the missing “s”)statement. A throw does 2 things:

1. Creates an exception object.

2. Causes normal program execution to stop.

This above 2 points is best illustrated with the following example:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 94

Page 104: 67544219-OOP-JAVA

Creating Your Own Exception 8.2

1 . . .2 public void readFile(String file)3 throws IOException, FileNotFoundException {4 FileInputStream fis = null;5 File fd = new File(file);6 if (!fd.exists())7 throw new FileNotFoundException(file);8 try {9 int ch;

10 fis = new FileInputStream(file);11 while ((ch = is.read()) != -1)12 System.out.println(ch);13 } finally {14 is.close();15 }16 }17 . . .

The explanation for the above code is as follows: we check if the file exists;if it exists we proceed to open and read it. But if it does not exists, wethrow a FileNotFoundException (line 7 ). Notice that you have to instan-tiate the exception object. After the throw statement, the program existthe readFile() method. The remainding statements in the method is notexecuted.

8.2 Creating Your Own Exception

Besides using the JDK supplied exception classes, you can also create yourown exception objects. This requires you to subclass the Exception class.We will add exception to Account class. We will modify OverdrawnExceptionto withdrawal() method. The OverdrawnException will capture all infor-mation pertaining to an overdrawn transaction. These information includesthe following:

• Account name.

• Account number.

• Account balance at the time of the withdrawal.

• Overdrawn amount.

• The date of the transaction.

The following code implements OverdrawnException.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 95

Page 105: 67544219-OOP-JAVA

Creating Your Own Exception 8.2

1 import java.lang.*;2 import java.util.*;3 public class OverdrawnException4 extends Exception {5 private final String name;6 private final int acctNo;7 private final float balance;8 private final float withdrawAmount;9 private final Date date;

10 public OverdrawnException(Account acct, float amt) {11 super("Overdrawn");12 name = acct.getName();13 acctNo = acct.getAccountNumber();14 balance = acct.getBalance();15 withdrawnAmount = amt;16 date = new Date();17 }18 public String getName() {19 return (name);20 }21 . . .22 public float getWithdrawAmount() {23 return (withdrawAmount);24 }25 }

The explanation for the above code is as follows:

line 10, The constructor takes an Account object and initializes the ac-count name (name), account number (acctNo) and current balance(balance). The amt holds the amount the the user is attempting towithdraw. Note that these members are marked final. This meansthat the value of these members cannot be changed. What we are re-ally saying here is that OverdrawnException object is immtable; viz.once create, the content of the object cannot be changed.

line 11, Since the superclass has a constructor with a String parameter.You can get this message using the getMessage() method.

line 12 to 16, are read only properties to name, account number, balance,amount attempted to withdraw and the transcation date.

To use OverdrawnException, we modify withdrawal() of Account classas follows:

1 public class Account {2 . . .

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 96

Page 106: 67544219-OOP-JAVA

Creating Your Own Exception 8.2

3 public void withdrawal(float amt)4 throws OverdrawnException, ErroneousAmountException {5 if (amt > balance)6 throw new OverdrawnException(this, amt);7 if ((amt < 0)8 throw new ErroneousAmountException(this, amt);9 balance -= amt;

10 }11 . . .12 }

line 4, Declares OverdrawnException and ErroneousAmountExceptionwill be thrown from withdrawal(). Assme ErroneousAmountExceptionis defined.

line 6, If the amount to be withdrawn is greater than what is in the account,we throw the OverdrawnException, passing to it all the necessaryparameters.

line 7, 8, We check if we are withdrawing negative amount. If so we throwa different exception.

line 9, When we have passed all the necessary checks, we do the withdraw.

The following code snippet show how we use the modified withdrawal().

1 . . .2 try {3 account.withdraw(amt);4 } catch (OverdrawnException e) {5 System.out.println("Overdrawn");6 System.out.println("You have: " + e.getBalance());7 System.out.println("You attempt to withdraw: "8 + e.getWithdrawAmount());9 }

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 97

Page 107: 67544219-OOP-JAVA

Chapter 9

Streams

Most programs use data in one form or another. These data can be in a localfile, a socket on the network, a database, variables or from another program.The JDK provides classes for reading and writing streams of data. Theseclasses are part of the java.io package. We will also look at the concept ofstream chaining.

9.1 The File Class

One of the commonly used classes in java.io package is the File class.This class provides methods to manipulate the file system which includesdeleting files, listing directories, returning file statistics renaming files andothers. Recall that in chapter 8 in page 94 we used File to check for fileexistance; we will look at a code snippet which displays the properties of agiven file if it exists. The code is shown below:

1 import java.io.*;2 . . .3 public void fileInformation(String fileName) {4 File fn = new File(fileName);5 if (!fn.exists()) {6 System.out.println(fileName + " does not exists.");7 return;8 }9 System.out.println(fileName + " is a "

10 + fn.isDirectory()? "directory." :"file.");11 if (!fn.canRead()) {12 System.out.println(fileName + " is not readable.");13 return;14 }15 System.out.println(fileName + " is " + fn.length()16 + " bytes long.");

98

Page 108: 67544219-OOP-JAVA

The File Class 9.1

17 System.out.println(fileName + " is last modified on "18 + fn.lastModified() + ".");19 }20 . . .

The explanation for the above code is as follows:

line 1, Do not forget to import the java.io package.

line 5, If the file does not exist we proceed no further.

line 10, Prints out an appropriate message if fileName is a directory.

line 11, Check if we can read the file.

line 15 to 18, If we can read the file, we print out the size and the lastmodified date.

The File class has the following methods:

public String getName()Returns the file name.

public String getParent()Returns the parent part of the file or null if the file name has noparent part.

public void delete()Deletes a file.

public boolean exists()Test if the file exists.

public long length()Returns the size of the file.

public long lastModified()Returns the last modified date of the file.

public boolean canRead()Test if the file is readable.

public boolean canWrite()Test if the file is writable.

public boolean isFile()Test if the file is a “normal” file.

public boolean isDirectory()Test if the file is a directory.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 99

Page 109: 67544219-OOP-JAVA

InputStream 9.2.1

public String[] list()Returns a list of files in a directory, if the current File object is adirectory.

public void mkdir()Creates a directory.

9.2 Character and Byte Streams

Streams are data sources that we read and write to serially. Whether youare reading a file or a socket connection, the idea of a stream is the same.Prior to JDK 1.1, the java.io package only supported 8-bit byte streams.The concept of 16-bit character streams was introduced in JDK 1.1. Toread byte streams we use InputStream and OutputStream classes and theirsubclasses; to read character streams, we use Reader and Writer classesand their subclasses.

The InputStream and Reader classes are input streams. As the nameimplies, you read from these streams but not write to it. Similarly, OutputStreamand Writer classes are output streams; you cannot read from these latterstreams.

Both the character and byte stream classes are quite similar in their useso we will just concentrate on the byte stream and leave character streamclasses as an exercise for the reader.

9.2.1 InputStream

The InputStream class is an abstract and is a superclass of all classesrepresenting input byte streams. Figure 9.1 shows all the subclasses ofInputStream.

InputStream has the following methods; this list is not exhaustive. Alsoall the above methods throws IOException.

public int read()Reads the next byte of data from this input stream. The value byte isreturned as an int in the range 0 to 255. If no byte is available becausethe end of the stream has been reached, the value -1 is returned. Thismethod blocks until input data is available, the end of the stream isdetected, or an exception is thrown.

public int read(byte[] b)Reads up to b.length bytes of data from this input stream into anarray of bytes.

public long skip(long n)Skips over and discards n bytes of data from this input stream.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 100

Page 110: 67544219-OOP-JAVA

OutputStream 9.2.2

InputStream

SequencedInputStream

PipedInputStream

FilterInputStream

ByteArrayInputStreamStringBufferInputStreamFileInputStream

BufferedInputStream

PushbackInputStream

DataInputStream

Figure 9.1: InputStream class hierarchy

public int available()Returns the number of bytes that can be read from this input streamwithout blocking.

public void close()Closes this input stream and releases any system resources associatedwith the stream.

Recall that InputStream is an abstract class. We cannot use InputStreamto do any reading. We must use a concrete implementation of it such as aFileInputStream. Table 9.1 summarize all input stream classes availablein java.io and also java.util.zip1.

9.2.2 OutputStream

The OutputStream class is an abstract and is a superclass of all classesrepresenting output byte streams. Figure 9.2 shows all the subclasses ofOutputStream.

OutputStream has the following methods; these methods throw IOException.

public void write(int b)Writes a byte to the output stream.

1Yes, ZIP, as in PKZIP

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 101

Page 111: 67544219-OOP-JAVA

OutputStream 9.2.3

Class Name DescriptionBufferedInputStream Reads a buffer of bytes from an InputStream, and

then returns bytes from the buffer, making smallreads more efficient.

ByteArrayInputStream Reads bytes sequentially from an array.CheckedInputStream Coputes a checksum of the bytes it reads

from an InputStream. This class is found injava.util.zip.

DataInputStream Reads binary representations of Java primitivetypes from an InputStream.

FileInputStream Reads bytes sequentially from a file.FilterInputStream The superclass of byte input stream filter classes.GZIPInputStream This class uncompresses GZIP compressed bytes it

reads from an InputStream.InflaterInputStream This is the superclass of GZIPInputStream and

ZipInputStream.InputStream The superclass of all byte input stream.ObjectInputStream Reads binary representations of Java objects and

primitive values from a byte stream.PipedInputStream Reads bytes written to the PipedOutputStream to

which it is connected.PushbackInputStream Adds a fixed-size “pushback buffer” to an input

stream, so that bytes can be “unread”.SequenceInputStream Reads bytes sequentially from two or more input

streams, as if they were a single stream.ZipInputStream This class uncompresses entries in a ZIP file. This

class is found in java.util.zip.

Table 9.1: Input stream classes

public void write(byte[] b)Writes b.length bytes from the specified byte array to this outputstream.

public void flush()Flushes this output stream and forces any buffered output bytes to bewritten out.

public void close()Closes the output stream. It is advisable call flush() before closing.

Table 9.2 summerizes all the OutputStream classes in java.io and java.util.zip.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 102

Page 112: 67544219-OOP-JAVA

A File Copy Example 9.2.3

OutputStream

PipedOutputStream

FilterOutputStream

ByteArrayOutputStreamStringBufferOutputStreamFileOutputStream

BufferedOutputStream

PushbackOutputStream

DataOutputStream

Figure 9.2: InputStream class hierarchy

9.2.3 A File Copy Example

We will now write a copy program in Java using FileInputStream andFileOutupStream. The explanation will follow the code.

1 import java.lang.*;2 import java.io.*;3 public class FileCopy {4 public static void main(String[] args)5 throws IOException {6 if (args.length != 2) {7 System.out.println("java FileCopy <src> <dst>");8 System.exit(-1);9 }

10 if (!(new File(args[0])).exists()) {11 System.out.println(args[0] + " does not exists.");12 System.exit(-1);13 }14 if ((new File(args[1])).exists()) {15 System.out.println(args[1] + " will be overwritten.");16 System.exit(-1);17 }18 int c;19 FileInputStream srcFile = new FileInputStream(args[0]);20 FileOutputStream dstFile = new FileOutputStream(args[1]);

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 103

Page 113: 67544219-OOP-JAVA

A File Copy Example 9.2.3

Class Name DescriptionBufferedOutputStream Buffers byte output for efficiency; write to an

OutputStream only when the buffer fills up.ByteArrayOutputStream Writes bytes sequentially to an array.CheckedOutputStream Computes a checksup of the bytes written to

an OutputStream. This class is found injava.util.zip.

DataOutputStream Writes binary representations of Java primitivetypes to an OutputStream.

DeflaterOutputStream the superclass of GZIPOutputStream andZipOutputStream.

FileOutputStream Writes bytes sequentially to a file.FilterOuputStream The superclass of all byte output stream filters.GZIPOutputStream Compress and write bytes out using the GZIP al-

gorithm.ObjectOutputStream Writes binary representation of java objects and

primitive values to an OutputStream.OutputStream The superclass of all byte output streams.PipedOutputStream Writes bytes to the PipedInputStream to which it

is connected.ZipOutputStream Compress and write bytes to a ZIP file. This class

is found in java.util.zip.

Table 9.2: Output stream classes

21 try {22 while ((c = srcFile.read()) != -1)23 dstFile.write(c);24 dstFile.flush();25 } finally {26 srcFile.close();27 dstFile.close();28 }29 }30 }

line 2, Do not forget to import java.io package.

line 5, The main() thorws IOException.

line 6 to 9, Checks if we have enough parameter. We need a source file tocopy from and a destination file to copy to.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 104

Page 114: 67544219-OOP-JAVA

Stream Chaining 9.3

line 10 to 13, These 4 lines of code checks if the source file exists.

line 14 to 17, These lines warns that an existing file will be overwritten.Remember we are copying to this file.

line 19, Use FileInputStream to open source file for reading.

line 20, Use FileOutputStream to open destination file for writing.

line 22, Keep reading a byte from srcFile until we hit an end of file whichis denoted by a -1.

line 23, After reading the byte, we write to dstFile.

line 24, When we have completed copying, force any remainding bytes inthe output buffer to the disk.

line 25, The finally clause here ensures that all opened files will be closed.If we some how encountered an IOException in line 22 or 23, the filesare first closed before throwing an exception (line 5 ).

9.3 Stream Chaining

The java.io packages distinguishes between 2 type of streams:

Node stream This type of streams read or write from a specific place suchas a disk or from the network. FileInputStream is a node stream.

Filter stream These are layered onto of node streams and provide addi-tional functionalities that are not found in node streams.

The idea of stacking filter stream classes on node streeam is one of themost powerful feature in the Java I/O package; this is known as streamchaining. Stream chaining is a way of connecting several stream classes towork together to provide new functionalities. Its “plug and play, mix andmatch”. Assume we have GZIPOutputStream2 and DataOutputStream class;we can chain these classes so that whatever value that we write will be com-pressed before saving to a file. Figure 9.3 illustrates this chain. This is howthe chain works; when values are written to DataOutputStream, they areconverted to a portable binary format before forwarding to GZIPOutputStream.GZIPOutputStream then compresses the data before passing it to FileOutputStreamfor saving.

The source code for creating the chain shown in figure 9.3 is as below:2GZIP is GNU Zip

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 105

Page 115: 67544219-OOP-JAVA

Stream Chaining 9.3

DataOutputStream GZIPOutputStream FileOutputStream

Data

To diskConvert to portablebinary format

Compress data

Figure 9.3: Stream chaining example

1 import java.lang.*;2 import java.io.*;3 import java.util.zip.*;4 public class WriteChain {5 public static void main(String[] args)6 throws IOException {7 FileOutputStream fos = new FileOutputStream("output.gz");8 GZIPOutputStream gzos = new GZIPOutputStream(fos);9 DataOutputStream dos = new DataOutputStream(gzos);

10 try {11 dos.writeUTF(args[0]);12 dos.flush();13 } finally {14 dos.close();15 }16 }17 }

The explanation for the above code snippet is as follows:

line 7, We create a FileOutputStream which is our node stream. The filename that we will be writing our data to is “output.gz”.

line 8, Here, we instantiate the first of our filter stream, the GZIPOutputStreamwhich does all the compression. Notice that this filter stream is layeredon fos, which is FileOutputStream.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 106

Page 116: 67544219-OOP-JAVA

Performing I/O with Account 9.3.2

line 9, We now add another filter stream on to the chain. Notice that wheninstantiating DataOutputStream, we use gzos.

line 11, We now can write a String to our chain. You always write to thestream class at the top of the chain. In this case it is dos.

line 12, Do not forget to force the data to the hard disk.

line 14, When closing a chained stream, you only need to close the top moststream class because the dos.close() method call will automaticallytrigger other close() through all the chained classes.

9.3.1 Decorator Design

Stream chaining is a well known design in object oriented software. Itsformal name is known as decorator or wrapper. The decorator keeps ourobject simple; you do not have to write a complex object with all possiblefeatures. Instead you write small, simple and focused objects that can becombined with other objects to provide new functionalities. The advantagesof the decorator design is as follows:

• Add function to objects dynamically and transparently with out af-fecting other objects.

• Functions can also be revoked dynamically and transparently.

9.3.2 Performing I/O with Account

The best way to understand how a filter stream works is to actually writeone. We will write a AccountInputStream and AccountOutputStream thatwrites and reads Account objects. We will first detail the steps involvedfollowed by an implementation of the above mentioned 2 classes.

The steps for creating a filter stream is a filter streams is as follows:

1. Extend the FilterInputStream or FilterOutputStream.

2. Write a constructor that accepts an InputStream or an OutputStreamrespectively.

3. Override read() or write() if necessary.

4. Provide additional read and/or write methods if necessary.

Lets look at AccountOutputStream first. The filter stream has the fol-lowing new methods:

public void writeAccount(Account acct)Writes acct to a stream.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 107

Page 117: 67544219-OOP-JAVA

Performing I/O with Account 9.3.2

public void writeAccount(String name, int acctNo, float balance, boolean overdraft)Writes name, acctNo, balance and overdraft as an Account objectto a stream.

The following code listing implements AccountOutputStream.

1 import java.lang.*;2 import java.io.*;3 public class AccountOutputStream4 extends FilterOutputStream {5 private static final byte END_OF_FIELD = 0;6 public AccountOutputStream(OutputStream os) {7 super(os);8 }9 public void writeAccount(Account acct)

10 throws IOException {11 writeAccount(acct.getName()12 , acct.getAccountNumber()13 , acct.getBalance()14 , acct.isOverdraft());15 }16 public void writeAccount(String name, int acctNo17 , float balance, boolean overdraft)18 throws IOException {19 write(name.getBytes());20 write(END_OF_FIELD);21 write(String.valueOf(acctNo).getBytes());22 write(END_OF_FIELD);23 write(String.valueOf(balance).getBytes());24 write(END_OF_FIELD);25 write(String.valueOf(overdraft).getBytes());26 write(END_OF_FIELD);27 }28 }

line 4, Extends the FilterOutputStream.

line 5, The END_OF_FIELD constant is a value to separate the Accountmembers when we write the members to a OutputStream. This is sothat when we read the values back, we know where one member endsand another begins.

line 6, Our constructor needs to accept a OutputStream. This is in accor-dance with the filter stream requirements.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 108

Page 118: 67544219-OOP-JAVA

Performing I/O with Account 9.3.2

line 9, The first of our writeAccount() methods. This write method takesan Account object.

line 11 to 14, Calls the other writeAccount() which does the writing.

line 16, The method is the workhorse of the class. Data for each memberis first converted to String using valueOf(). Once in String, theString is written as bytes. Remember a character is 16-bit in Java.

line 19 to 26, After writing a member, we write the END_OF_FIELD.

A dump of an AccountOutputStream is shown in figure 9.4. You cansee that the account name is “Fred Flintstone”, the account number is“12345”. There is $100 in the account with no overdraft capability. The“\0” is the END_OF_FIELD.

000 F r e d F l i n t s t o n e \0020 1 2 3 4 5 \0 1 0 0 . 0 \0 f a l s040 e \0

Figure 9.4: Contents of an AccountInputStream file

The classAccountInputStream reads a file written by AccountOutputStream.readAccount() reads a “record” which consists of a name, an account num-ber, a balance and an overdraft status; it then instantiate an Account objectand returns it to the caller. The code that implements AccountInputStreamis shown below:

1 import java.lang.*;2 import java.io.*;3 public class AccountInputStream4 extends FilterInputStream {5 private static final byte END_OF_FIELD = 0;6 private byte[] buffer;7 private int dataPointer;8 public AccountInputStream(InputStream is) {9 super(is);

10 buffer = new byte[256];11 }12 public Account readAccount()13 throws IOException {14 String name = null;15 int acctNo = 0;16 float balance = 0F;

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 109

Page 119: 67544219-OOP-JAVA

Performing I/O with Account 9.3.2

17 boolean overdraft = false;18 try {19 name = readField();20 acctNo = Integer.parseInt(readField());21 balance = Float.valueOf(readField()).floatValue();22 overdraft = Boolean.valueOf(readField()).booleanValue();23 } catch (NumberFormatException e) {24 throw new IOException("Data file is corrupted.");25 }26 Account acct = new Account(name, acctNo);27 acct.setOverdraft(overdraft);28 acct.withdrawal(100F);29 acct.deposit(balance);30 return (acct);31 }32 private String readField()33 throws IOException {34 dataPointer = 0;35 while ((buffer[dataPointer++] = (byte)read()) != END_OF_FIELD);36 return (new String(buffer, 0, --dataPointer));37 }38 }

line 6, 10, buffer is an internal buffer which we use to hold temporarydata. The size of the buffer is set to 256 bytes.

line 32, The readField() method is responsible for reading a field. Re-member that a field is denoted by a END_OF_FIELD byte. When it hasa field, readField() converts the field to a String and returns it tothe caller.

line 35, We read the InputStream, one byte at a time until we hit aEND_OF_FIELD byte. The read byte is stored in buffer.

line 36, The field held in buffer is converted to a String and returned tothe caller.

line 12, The readAccount() method returns as Account object that isconstructed from the information in a InputStream.

line 19 to 22, All data are stored to an OutputStream as a String. So whenwe read back the data with the exception of name, we need to convertall other fields back to their value. We use parseInt(), floatValue()and booleanValue() to do this for us. These method will throw a

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 110

Page 120: 67544219-OOP-JAVA

Performing I/O with Account 9.3.2

NumberFormatException if we fail. In this case we rethrow the excep-tion as IOException, reporting that we have encountered corrupteddata.

line 26, Once we have all the necessary information, we instantiate anAccount object.

line 28, A new Account always has $100 in it (see page 27) , so we mustremove it first before depositing the actual amount.

Now that we have looked at the implementation, lets see how we writea compress Account object to a file. The code snippet is shown below:

1 Account acct;2 . . .3 FileOutputStream fos = new FileOutputStream("account.gz");4 GZIPOutputStream gzos = new GZIPOutputStream(fos);5 AccountOutputStream aos = new AccountOutputStream(gzos);6 aos.writeAccount(acct);

Reading the save Account object back is just as simple:

1 FileInputStream fis = new FileInputStream("account.gz");2 GZIPInputStream gzis = new GZIPInputStream(fis);3 AccountInputStream ais = new AccountInputStream(gzis);4 Account acct = ais.readAccount();

Stream chaining is a very simple but powerful concept. It allows us tobuild new functionality into our streams modularly. The AccountInputStreamand AccountOutputStream classes shows just how simple it is to build onwhat is provided in java.io package.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 111

Page 121: 67544219-OOP-JAVA

Chapter 10

Object Serialization

Streams I/O has traditionally been used to save and retrieve “record” typedata. For “simple” objects, stream I/O may well be adequate but for “com-plex” objects, writing a filter stream may not be as straight forward. Con-sider the following class and you will begin to appreciate the immensity ofproblem.

1 public class ComplexObject2 extends SuperComplexObject {3 public String name;4 private int index;5 public SomeObject someObject;6 // methods and constructors7 . . .8 }

Consider the following points from ComplexObject class above:

line 2, You have to save ComplexObjects’s super class SuperComplexObject;in fact you will have to save all super classes.

line 4, If there are no getter methods for index, how are you going to savethis?

line 5, You will also have to save someObject, including its super class ifany.

10.1 Serialization

Serialization is the process of “flattening” an object which can then be savedto some permanent storage or passed to another object via OutputStream.This is sometimes also known as persistence. When an object is serialized,only members of the object is serialized; static and final members, meth-ods and constructors are not serialized.

112

Page 122: 67544219-OOP-JAVA

ObjectInputStream and ObjectOutputStream 10.1.2

Besides saving the objects members, the serialization process also storesthe objects’ graph and version. The graph is the objects ancestory viz. itssuperclass. Serialization of an object begins with the highest serializableclass in the object’s class hierarchy. The process then walks down the hier-archy to serialize data from each subclass in turn. We will look at versioningin section 10.4

10.1.1 The Serializable Interface

To allow an object to be serializable, the class must have the following:

• Implement the Serializable interface which is in java.io package.

• Provide a default constructor or a constructor with no parameters.

The Serializable interface has no methods and only serve as a markerto indicate that it can be serialize. You do not have to implement Serializableon every class, just once along the class hierarchy; preferabally in the superclass. All its subclasses will be serializable as well. If we have a 3 class hierar-chy, with ClassA at the top, followed by ClassB and ClassC at the bottom;if ClassA implements Serializable, all of its subclass are serializable.

For Account class to be serializable, we only have to implement theserializable interface as below. The Account definition is taken from page 46

1 public abstract class Account2 implements Serializable {3 private String name;4 private int acctNo;5 private float balance;6 private boolean overdraft;7 private Interest interest;8 public Account() { }9 . . .

Since Account is the base class for all other account classes (eg. SavingAccountand FixedDepositAccount), these subclass will be serializable as well.

10.1.2 ObjectInputStream and ObjectOutputStream

The ObjectInputStream and ObjectOutputStream are used to serialize anddeserialize objects respectively. To serialize and deserialize and write ob-jects, use readObject() and writeObject() from ObjectInputStream andObjectOutputStream respectively. The following code snippet creates andwrites to account.ser file a SavingAccount object.

1 . . .2 SavingAccount account = new SavingAccount(

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 113

Page 123: 67544219-OOP-JAVA

Specifying What Gets Serialized 10.2.1

3 "Fred", 12345);4 FileOutputStream fos = new FileOutputStream(5 "account.ser");6 ObjectOutputStream oos = new ObjectOutputStream(fileOut);7 oos.writeObject(account);8 oos.flush();9 . . .

When account is serialized, name, acctNo, balance, overdraft and interestis written to account.ser. But since interest references to a class (whichimplements the Interest interface), we need to serialize that as well. Sothat class must implement Serializable as well. In other words, all nonprimary type member must be serializable if its containing class is to beserialized. Otherwise you will get a NotSerializableException.

Notice that like filter streams, ObjectOutputStream is layered onto anode stream. To deserialize account.ser see the following code snippet:

1 . . .2 FileInputStream fis = new FileInputStream("account.ser");3 ObjectInputStream ois = new ObjectInputStream(fis);4 Account account = (Account)ois.readObject();5 . . .

When you deserialize an object, you need to cast the object (line 4 ) backto its original class.

10.2 Customizing the Serialization Process

10.2.1 Specifying What Gets Serialized

The default behaviour of writeObjec() is to write all the object’s membersto an output stream. Sometimes we may not want certain members to beserialized; members that hold sensitive information, transitory data or datathat is not intended to be serialized. To denote non serializable fields, wemark these members with the transient keyword.

Let’s take a at Account again. One member that is not a good candidatefor serialization is interest for the following reason:

• It is transitory in that we can change interest rate calculation. It ismuch better to re set interest rate calculation after we have deserializedan Account object.

• We cannot be sure that the class that implemented Interest interfacealso implemented Serialization.

To mark interest non serializable, we add the transient keyword like so:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 114

Page 124: 67544219-OOP-JAVA

readObject and writeObject Method 10.2.2

1 public abstract class Account2 implements Serializable {3 private String name;4 private int acctNo;5 private float balance;6 private boolean overdraft;7 private transient Interest interest;8 public Account() { }9 . . .

10.2.2 readObject and writeObject Method

Serialization offers you more control over the read and writing process thanmere transient. A serializable class can implement the following two meth-ods to take over the entire serialization and deserialization process.

private void writeObject(ObjectOutputStream out)throws IOException

private void readObject(ObjectInputStream in)throws IOException, ClassNotFoundException;

The writeObject() method is responsible for writing the members of theobject to the stream and readObject() is responsible for restoring it.

Our Accountwill do the following: any attempt to deserialize an Accountobject that is 60 days old will result in an exception. The easiest wayto write writeObject() and readObject() is to begin each method withcalling defaultWriteObject() and defaultReadObject() respectively.

defaultWriteObject() method writes non static and non transientmembers of the current object to an OutputStream which is exactly thebehaviour of serialization. The idea is that you want to use the default se-rialization mechanism to serialize all “standard” members before you saveany additional data.

Similarly defaultReadObject() reads the non static and non transientmembers of the current object from an InputStream. The code to performexpiration checks on serialized Account object is as follows:

1 public abstract class Account2 implements Serializable {3 private String name;4 private int acctNo;5 private float balance;6 private boolean overdraft;7 private transient Interest interest;8 public Account() { }

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 115

Page 125: 67544219-OOP-JAVA

Validating a Deserialized Object 10.3

9 . . .10 private void writeObject(ObjectOutputStream out)11 throws IOException {12 out.defaultWriteObject();13 out.writeLong(((((new Date()).getTime()/1000)/60)/60)/24);14 }15 private void readObject(ObjectInputStream in)16 throws IOException, ClassNotFoundException {17 in.defaultReadObject();18 long current = ((((new Date()).getTime()/1000)/60)/60)/24;19 if ((current - in.readLong()) > 60)20 throw new IOException("Object expired!");21 }22 . . .

The explanation is as follows:

line 10, During serialization, control is passed to writeObject(). It is upto writeObject() to determine what to persist.

line 12, Use defaultWriteObject() to write the usual members into thestream.

line 13, We now write the time (in days since January 1 1970) on the streamas well. This is additional information not part of Account.

line 15, readObject() is called when an Account object is deserialized.

line 17, defaultReadObject() populates the object with data from theInputStream.

line 18, We now get the current time (again expressed in days since January1 1970).

line 19, 20, If the timestime from the stream (in.readLong()) is morethan 60 days old, we throw an IOException.

10.3 Validating a Deserialized Object

In the previous section, we informally did our validation in the readObject()method. As it turns out, JDK provides a more formal method of performingvalidation. When a class implements the ObjectInputValidation interface,JVM will call validateObject() (from ObjectInputValidation) after theentire object graph have been installed.

ObjectInputValidation has only one method with the following signa-ture:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 116

Page 126: 67544219-OOP-JAVA

Validating a Deserialized Object 10.3

public voiid validateObject()throws InvalidObjectException;

To use ObjectInputValidation you must perform the following steps:

1. Implement ObjectInputValidation in you class; write your valida-tion code in validateObject().

2. Register your validation interface in readObject()method using regi-sterValidation().

Lets rewrite the Account validation using this framework. Here’s howthe new code looks like:

1 public abstract class Account2 implements Serializable, ObjectInputValidation {3 private String name;4 . . .5 private boolean overdraft;6 private transient Interest interest;7 private transient long serTime;8 public Account() { }9 . . .

10 private void writeObject(ObjectOutputStream out)11 throws IOException {12 out.defaultWriteObject();13 out.writeLong(((((new Date()).getTime()/1000)/60)/60)/24);14 }15 private void readObject(ObjectInputStream in)16 throws IOException, ClassNotFoundException {17 in.defaultReadObject();18 serTime = in.readLong();19 in.registerValidation(this, 0);20 }21 public void validateObject()22 throws InvalidObjectException {23 long current = ((((new Date()).getTime()/1000)/60)/60)/24;24 if ((current - serTime) > 60)25 throw new InvalidObjectException("Object expired!");26 }27 . . .

The explanation for the above code is as follows:

line 2, You have to implement the ObjectInputValidation interface.

line 7, serTime is a temporary variable for holding the serialized time. Seeline 18.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 117

Page 127: 67544219-OOP-JAVA

Versioning 10.4

line 16, You can only validate objects as they are deserialized, so you haveto register your validation routine in readObject().

line 17, As usual, read in all the standard members that we have serialized.

line 18, Read in the time stamp and store it in serTime.

line 19, Register our validateObject() for registration.

line 21, This is our validation method. This will be called after the entireobject graph has been restored.

line 24, We do the check again, as in the previous incarnation of this code.

line 25, If the object has been serialized for more than 60 day, we throw aInvalidObjectException.

10.4 Versioning

Versioning allows a serialized object to identify its class during the deseri-alization process. Consider the following scenerio: you have an object ofClassA which you have serialized. You subsequently modified ClassA toinclude additional members. So now when you deserialize the old ClassAobject, you cannot deserialize it back to ClassA because this class is nolonger the original class.

In JDK 1.1, before a class is deserialized, its version number is matchedagainst that of its class. If they match then the JVM will proceed with theserialization; otherwise you will get an InvalidClassException.

As mention previously, the version is written to an OutputStream alongwith the object’s state and the object graph during persistance. The versionnumber for a class can be provided with one of the following 2 ways:

1. Let the JVM assign one for you randomly.

2. Define one yourself.

To provide a version number for a particular class, you add a staticmember call serialVersionUID in you class like so:

1 public abstract class Account2 implements Serializable {3 public static final long serialVersionUID = 1234567890L;4 private String name;5 private int acctNo;6 . . .

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 118

Page 128: 67544219-OOP-JAVA

Versioning 10.4

If you did not provide a serialVersionUID, JDK will compute1 a ver-sion number using the signature of a stream of bytes that reflect the classdefinition. The danger here is that the serialVersionUIDwill change when-ever you modify the class. This will not happen if you explicitly provide aserialVersionUID.

You can examine a class’s serialVersionUID with serialver in thebin directory of the JDK. To view a class’ version number, run the followingcommand

serialver -show

and type the class’ name in the “Full Class Name:” window. An exampleis shown in figure 10.1.

Figure 10.1: Graphical interface of serialver

1The algorithm used is the NIST’s Secure Hash Algorithm (SHA-1)

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 119

Page 129: 67544219-OOP-JAVA

Chapter 11

Networking

The Java API includes a set of classes that facilitates writing TCP/IP basednetwork programs. These classes can be found in java.net package. The“network” classes in the said package allows a programmer to write thefollowing:

• TCP and UDP oriented programs.

• Multicast programs.

• Access URLs as stream so that you can access a web page as if it wasa file local to your system.

• Extend URL’s protocol and content.

In this chapter, we will examine a client-server program that uses theTCP protocol. We will assume that the reader is familar with TCP/IPconcepts. We will nonetheless provide a quick review of of IP address andport numbers.

11.1 Addresses and Ports

Every server or host that participate in a TCP/IP network requires an IPaddress. This is a 32 bit unique number. An IP address comprises of 2parts:

Network number The network number (netid) defines a network. Allservers with the same netid belongs to the same network.

Host number Servers in the same network must have unique host number(hostid).

IP address are written in dotted form as a.b.c.d ; each digit is an 8 bitvalue. An example of an address is 192.10.1.1. There are 4 classes of IPaddress. They are shown in Figure 11.1.

120

Page 130: 67544219-OOP-JAVA

Client-Server Model 11.2

net id host id0

multicast address1 11

host id011 net id

host id1 0 net idClass B

Class A

Class C

Class D

128 - 191 . 0 - 255

1 - 127

192 - 233 . 0 - 255 . 0 - 255

224 - 239 . 0 - 255 . 0 - 255 . 0 - 255

Figure 11.1: IP address format

Class A networks are for networks with lots of host while class C networkscater for smaller networks.

A host or server connected to a TCP/IP network can be more thanone active process at any given time. Data for a particular process in thehost must be able to identify the intended process uniquely. To distinguishprocess in a host, TCP and UDP uses 16 bit integer values known as portnumbers. Port numbers are bound to one and only one process at any onetime and can be reused if the process has terminated. In summary, a portnumber and an IP address uniquely identifies a process in a host. This portnumber, IP address pair is know as an end point. Communication betweenend points can occur over either TCP or UDP.

11.2 Client-Server Model

TCP/IP applications typically consists of 2 parts: a server which providessome service like file, print or authentication and a client which use thisservice.

To create a server side end point, the server must specify the protocol itwishes to use and a port number. This server process is know as binding andthe server is said to be bound to the port number. If the bind is successful,the server will enter its second phase. This is known as listening. In thisphase, the server will listen on the bound port for incoming client connection.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 121

Page 131: 67544219-OOP-JAVA

Client-Server Model 11.2

A client opens a connection to a server by specifying the IP address ofthe host in which the server resides and the port number which the server isbound to. The client must also specify the same network protocol that theserver uses1.

These above steps can be summarized as follows:

1. The server binds itself to a port. It then listens for client connection.

2. The client establishes a connection to the server residing on host (IPaddress) listening on port (port number).

3. The client and server can now communicate once the connection hasestablished.

We will now look an an overview of creating a client and server with theJDK. We use the ServerSocket class to write a server. A ServerSocket isinstantiated by providing a port number in its constructor like so:

ServerSocket server = new ServerSocket(12345);

The ServerSocket has an accept() method which is used to listen forincoming client connection. When a client initiates a connection, accept()will return a Socket object. This Socket is the server’s connection with theclient.

How does the client initiates a connection to a server? The client requires2 pieces of information:

1. A host name or an IP address of the host in dotted notation.

2. The port number which the server is listening on.

With this 2 pieces of information, the client can instatiate a Socket objectwhich will connect to the given IP address or host name on the given port.The below example connects to a server listening on port 12345 on hostbatcave.

Socket toServer = new Server("batcave", 12345);

Once the connection is established, both client and server calls getInputStream()and getOutputStream. These methods returns an input and output stream.These streams on the server and client are “crossed” in that data writtenon the client’s OutputStream will appear on the server’s InputStream andvice versa. This entire process is illustrated in figure 11.2.

We are now ready to write an account client-server program which servesAccount objects to its client. The client-server program consists of thefollowing 3 classes:

1All this sounds rather complicated but it is very easy to do with Java.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 122

Page 132: 67544219-OOP-JAVA

Defining the Protocol 11.2.1

Client

new Socket(“batcave”,12345)

getInputStream()

getOutputStream()

Servernew ServerSocket(12345)

Socket()

accept()

getInputStream()

getOutputStream()

Figure 11.2: Interaction between ServerSocket and Socket

AccountServer The server program that servers Account objects.

AccountServerAPI This is a set of API that accesses the AccountServer.Any client that wishes to communicate with AccountServer will usethis class.

AccountProtocol A class that defines the protocol between the serverand a client. The protocol in question here is not the network pro-tocol but application protocol viz. the protocol used between theAccountServer and AccountClient application.

11.2.1 Defining the Protocol

The AccountProtocol is a holder class that contains information passedbetween server and a client. The following commands are defined for theprotocol:

GET Retrives an Account object from the server.

PUT Request the server to save a particular Account.

OKAY An acknowledgement that the last operation was successful.

ERROR Denotes an error has occured.

AccountProtocol contains the following method:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 123

Page 133: 67544219-OOP-JAVA

Defining the Protocol 11.2.1

public int getCommand()Returns the command of the protocol.

public int getAccountNumber()Returns the contained account number.

public Account getAccount()Returns the Account object contained within the AccountProtocol.

The listing for AccountProtocol is as below:

1 public class AccountProtocol2 implements Serializable {3 public static final int ERROR = -1;4 public static final int GET = 0;5 public static final int PUT = 1;6 public static final int OKAY = 2;7 private final int cmd;8 private final int accountId;9 private final Account account;

10 public AccountProtocol(int c, int id) {11 cmd = c;12 account = null;13 accountId = id;14 }15 public AccountProtocol(int c, Account acct) {16 cmd = c;17 accountId = acct.getAccountNumber();18 account = acct;19 }20 public int getCommand() {21 return (cmd);22 }23 public int getAccountNumber() {24 return (accountId);25 }26 public Account getAccount() {27 return (account);28 }29 }

Lets examine the code:

line 2, The Serializable interface ensure that AccountProtocol is writableacross the network. Remember, we have to pass one of these objectsfrom the client to server and vice versa.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 124

Page 134: 67544219-OOP-JAVA

Writing a Server 11.2.2

line 3 to 6, The 2 defined protocols.

line 7 to 9, The AccountProtocol object is immutable; viz. once created,nothing in it should change. This is so that what the client knows thatit has received the same object that was created at the server and viceversa. We do not want the account contained in a AccountProtocolobject to change on its way from the server to the client. This designdecision is reflected in the class in the following manner:

• Getter methods only to the properties; viz. all members are read-only.

• Adding a final modifier to cmd, account and accountId to en-sure that once assigned, these variable can never be changed.

We have seen this in chapter 8.

line 10 to 14, The first constructor accepts a command and an accountnumber. This is mainly used for creating a protocol that requests anAccount object.

line 15 to 19, The second constructor creates a AccountProtocol using acommand and an Account object.

line 20 to 22, Returns the type of command represented by a protocolobject.

line 23 to 25, Returns the account number of the Account object containwithin.

line 26 to 28, Returns the Account object.

Remember the validation protocol that we implemented to Account inpage 116? All that continues to work here! When a AccountProtocol objectgets serialized, the Account that we have set also gets serialized as well.

11.2.2 Writing a Server

The AccountServer serves Account objects to clients. Accounts objectsare stored as serialized disk files. The file name is the account numberwith a “.ser” extension. When the server receives a command, it does thefollowing:

GET Deserialized an Account object using the provided account numberand returns the object to the client. If the Account is not found, anERROR is returned. If the server is able deserialize the Account, theserver will create a new AccountProtocol object with OKAY commandand the Account object and returns it to the client.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 125

Page 135: 67544219-OOP-JAVA

Writing a Server 11.2.2

PUT Serialized the given Account. An ERROR is returned the AccountServercannot serializes the object. If the server is successful in serializing theobject, with will acknowledge with OKAY.

The flow of the above mentioned protocol is shown in figure 11.3.

Receives aGET

Receives aPUT

Gets theaccount

Saves theaccount

Successful?

ReturnsOKAY

ReturnsERROR

true false

Figure 11.3: Flow diagram of AccountServer’s protocol

To write a server you have to do the following steps:

1. Create an instance of ServerSocket giving the required port numberin the constructor.

2. Listen on the port by calling accept().

3. When a client connects, accept() will return a Socket instance. Thisinstance is connected with the client.

4. To communicate with the client, the server calls getInputStream()and getOutputStream() on the Socket instance. This will return anInputStream and an OutputStream respectively. The OutputStreamis attached to the client’s InputStream and vice versa.

5. Terminate the connection by calling close() on the Socket.

The AccountServer listing is as follows :

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 126

Page 136: 67544219-OOP-JAVA

Writing a Server 11.2.2

1 import java.lang.*;2 import java.io.*;3 import java.net.*;4 public class AccountServer5 extends ServerSocket {6 public static final int PORT = 12345;7 public AccountServer(int port)8 throws IOException {9 super(port);

10 }11 public void run() {12 System.out.println("AccountServer started...");13 while (true) {14 try {15 Socket clnt = accept();16 ObjectInputStream ois = new ObjectInputStream(17 clnt.getInputStream());18 ObjectOutputStream oos = new ObjectOutputStream(19 clnt.getOutputStream());20 AccountProtocol acctProto =21 (AccountProtocol)ois.readObject();22 try {23 switch (acctProto.getCommand()) {24 case AccountProtocol.GET:25 handleGet(oos, acctProto);26 break;27 case AccountProtocol.PUT:28 handlePut(oos, acctProto);29 break;30 case AccountProtocol.ERROR:31 default:32 }33 } catch (Exception e) {34 oos.writeObject(new AccountProtocol(35 AccountProtocol.ERROR, 0));36 } finally {37 ois.close();38 oos.close();39 clnt.close();40 }41 } catch (Exception e) { }42 }43 }44 private void handleGet(ObjectOutputStream netOOS

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 127

Page 137: 67544219-OOP-JAVA

Writing a Server 11.2.2

45 , AccountProtocol proto)46 throws Exception {47 FileInputStream fis = new FileInputStream(48 proto.getAccountNumber() + ".ser");49 ObjectInputStream ois = new ObjectInputStream(fis);50 AccountProtocol result = new AccountProtocol(51 AccountProtocol.OKAY, (Account)ois.readObject());52 netOOS.writeObject(result);53 netOOS.flush();54 ois.close();55 }56 private void handlePut(ObjectOutputStream netOOS57 , AccountProtocol proto)58 throws Exception {59 FileOutputStream fos = new FileOutputStream(60 proto.getAccountNumber() + ".ser");61 ObjectOutputStream oos = new ObjectOutputStream(fos);62 oos.writeObject(proto.getAccount());63 oos.flush();64 oos.close();65 netOOS.writeObject(new AccountProtocol(AccountProtocol.OKAY66 , 0));67 netOOS.flush();68 }69 public static void main(String[] args)70 throws Exception {71 AccountServer server = new AccountServer(PORT);72 server.run();73 }74 }

Explanation for the AccountServer code is as follows:

line 3, Remember to import java.net package.

line 5, The AccountServer is a subclass of ServerSocket. We do not haveto create a separate ServerSocket just to accept client connection.

line 9, We manually chain the super class’ constructor because ServerSocketdoes not have a construct with the default constructor’s signature.

line 11 to 41, The run() method is our main loop. In here, we wait forclient connection and process them.

line 15, accept() waits for a connection; it will return with a Socketinstance when a client connects.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 128

Page 138: 67544219-OOP-JAVA

Writing the Server API 11.2.3

line 16 to 19, Creates an ObjectInputStream and an ObjectOutputStreamfrom the Socket.

line 20, 21, Once we have gotten the input and output stream, we read theAccountProtocol object send by the client.

line 23 to 32, We now use a switch statment to distinguish the commandthat we have received from the client.

line 34, 35, If any of the handleXXX() methods throw any exceptions, wewill send an ERROR back to the client.

line 44 to 55, handleGet() desrializes the requested account for the harddisk and returns it in a AccountProtocol to the client.

line 47 to 49, Opens the serialized object file for reading.

line 50, 51, Creates a AccountProtocol object that contains the requestedobject.

line 52, Sends the AccountProtocol to the client.

line 55 to 68, handlePut() gets the Account object for AccountProtocoland serializes it to the hard disk.

line 59 to 60, Open a file for serializing the Account.

line 62, Extract the Account and serializes it.

line 65, 66, Returns an OKAY status to the client.

line 71, Starts the AccountServer on port 12345.

11.2.3 Writing the Server API

A client uses the Socket class to initiate a connection to a server. Toinstantiate a Socket, you will need the IP address of the host and the portnumber. If you successfully create a Socket instance, the accept()will havereturned a corresponding Socket on the server side. All you have to do nowis to get the InputStream and OutputStream. Once caveat about gettingthe InputStream and OutputStream from the server and client side Socketis that you cannot call get the same stream from both side in the samesequence. This will cause your program to hang. Consider the followingcode snippet from the server side:

1 Socket clnt = accept();2 InputStream is = clnt.getInputStream();3 OutputStream os = clnt.getOutputStream();

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 129

Page 139: 67544219-OOP-JAVA

Writing the Server API 11.2.3

Note the call sequence: InputStream frist. If we were to write the followingon the client side, our program will hang:

1 Socket toServer = new Socket("batcave", 12345);2 InputStream is = toServer.getInputStream();3 OutputStream os = toServer.getOutputStream();

We should reverse the getXXXStream() call sequence like below:

1 Socket toServer = new Socket("batcave", 12345);2 OutputStream os = toServer.getOutputStream();3 InputStream is = toServer.getInputStream();

Okay, lets look at AccountServerAPI. The class has 1 constructor thattakes a host name that the server is running on. The signature of theconstructor is a follows:

public AccountServerAPI(String server)

AccountServerAPI contains the following methods:

public Account getAccount(int accountNumber)Retrieves an Account with using the provided accountNumber. If theaccountNumber does not exist, getAccount() will return null.

public Account putAccount(Account acct)Saves acct back to the server. If the save is successful, putAccount()will return the Account object that is saved; this will be equal to acct.If the save is not successful, a null will be returned.

Both getAccount() and putAccount() throws APIException2. Why do weneed a AccountServerAPI? Remember abstraction and encapsulation? Wewant to hide the implementation details for the users, programmers whowill be using our API to develop applications, and localize our protocolbehaviour to 2 classes: AccountServerAPI and AccountServer.

The listing for AccountServerAPI is as follows:

1 import java.lang.*;2 import java.io.*;3 import java.net.*;4 public class AccountServerAPI {5 private Socket toServer = null;6 private String hostname;7 private ObjectInputStream ois;8 private ObjectOutputStream oos;9 public AccountServerAPI(String hn) {

2APIException listing is not shown.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 130

Page 140: 67544219-OOP-JAVA

Writing the Server API 11.2.3

10 hostname = hn;11 }12 public Account getAccount(int acctId)13 throws APIException {14 AccountProtocol result = write(15 new AccountProtocol(AccountProtocol.GET, acctId));16 if (result.getCommand() == AccountProtocol.OKAY)17 return (result.getAccount());18 else19 return (null);20 }21 public Account putAccount(Account acct)22 throws APIException {23 AccountProtocol result = write(24 new AccountProtocol(AccountProtocol.PUT, acct));25 if (result.getCommand() == AccountProtocol.OKAY)26 return (acct);27 else28 return (null);29 }30 public AccountProtocol write(AccountProtocol proto)31 throws APIException {32 AccountProtocol result = null;33 connect();34 try {35 oos.writeObject(proto);36 oos.flush();37 result = (AccountProtocol)ois.readObject();38 } catch (Exception e) {39 close();40 throw new APIException(e.getMessage());41 }42 try {43 close();44 } finally {45 return (result);46 }47 }48 private void connect()49 throws APIException {50 try {51 toServer = new Socket(hostname, AccountServer.PORT);52 oos = new ObjectOutputStream(toServer.getOutputStream());53 ois = new ObjectInputStream(toServer.getInputStream());

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 131

Page 141: 67544219-OOP-JAVA

Writing the Server API 11.2.3

54 } catch (UnknownHostException e) {55 throw new APIException(e.getMessage());56 } catch (IOException e) {57 throw new APIException(e.getMessage());58 }59 }60 private void close()61 throws APIException {62 try {63 oos.close();64 ois.close();65 toServer.close();66 } catch (IOException e) {67 throw new APIException(e.getMessage());68 }69 }70 }

line 12 to 20, The getAccount() method returns the an Account from theserver when given a valid account number.

line 14, 15, We create a AccountProtocol, setting the command to GETand give the appropriate account number. After we have create theprotocol, we use write() method (see below). The result of the GETis returned as another AccountProtocol object.

line 16, We check the return result if the command is OKAY.

line 17, If the command is an OKAY, we then return the Account object tothe caller and exits this method.

line 19, If the command is not an OKAY, very likely an ERROR, we thenreturn a null.

line 21 to 29, The putAccount() saves an Account object back to theserver.

line 23, 24, Again, we create a AccountProtocol object, setting the com-mand to PUT and give an Account object that we wish to save. Wethen use write() to write the protocol to the server.

line 25, 26, We check result again to see if the write is successful. If itis we return the saved Account object to the caller signifying that thesave is successful.

line 28, If the save is not successful, we return a null.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 132

Page 142: 67544219-OOP-JAVA

Using the AccountServerAPI 11.2.4

line 30 to 47, The write() method takes a AccountProtocol object andsends it to the AccountServer. The method then reads the replyfrom the server and returns this to the caller. Note that write() isa public method. You can actually call write() and send you owncommands to the server.

line 33, Connects to the server first. We will examine the connect()method shortly.

line 35, 36, Writes the AccountProtocol to the server. The flush() forcesthe write on the ObjectOutputStream. oos is set by connect().

line 37, We then read the result returned by the server. ois is set byconnect().

line 39, 40, If the above writeObject() or readObject() has any ex-ceptions, we closes the stream and notify the caller by throwing anAPIException.

line 43, If the writeObject() and readObject() is successful, we thenclose the connection to the server.

line 45, Returns result which we got from the server back to the caller.

line 48 to 59, This method connects to an AccountServer; it also sets upthe ObjectInputStream and ObjectOutputStream for reading andwriting later.

line 51, We create a connection to a server on host hostname which we setin the constructor listening on port AccountServer.PORT (12345).

line 52, Create an ObjectOutputStream using the InputStream from theSocket.

line 53, Similarly, create an ObjectInputStream.

line 60 to 69, The close() method closes the opened object streams aswell as the connection to the server.

11.2.4 Using the AccountServerAPI

Now that we have hide the complexities of handling the protocol in getAccount()and putAccount(), we will now see how we can use the AccountServerAPI.We need to create an instance of AccountServerAPI by providing it withthe server’s name as in the following code:

AccountServerAPI api = new AccountServerAPI("batcave");

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 133

Page 143: 67544219-OOP-JAVA

Using the AccountServerAPI 11.2.4

The following code snippet gets an account 12345 from the server, pro-cesses it and saves the account back.

1 . . .2 AccountProtocol result = api.getAccount(12345);3 if (result.getCommand() != AccountProtocol.OKAY) {4 // Error ! Did not get account5 return;6 }7 Account acct = result.getAccount();8 // process acct9 . . .

10 result = api.putAccount(acct);11 if (result.getCommand() != AccountProtocol.OKAY) {12 // Error ! Save was not successful13 return;14 }15 . . .

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 134

Page 144: 67544219-OOP-JAVA

Chapter 12

Threads and Synchronization

Threads, like taxes are always present in the JVM. Threading is such anintegral part of the JVM that it is almost impossible to write single threadedprogram save for hello world; even then your single threaded program livesin the JVM threaded environment. Here are just some examples that theJVM uses threads to support your program without your knowledge:

• In handling event, the JVM dispatches a thread to call your eventhandler.

• When your AWT window requires repaint because of exposure, thepaint() is called by a thread.

• Object references goes out of scope, a thread called the garbage col-lector is used to free the memory.

Threads are very powerful concepts in computer science. They allow usto exploit the natural concurrency that occurs in our program; by naturalconcurrency we mean multiple independent task. By creating threads tohandle these independent tasks, we make our program more efficient andresponsive. Some examples tasks that will benefit from being threaded areasynchronous I/O, timers and servers.

Consider the code snippet below which is part of the AccountServershown on page 126:

1 . . .2 public void run() {3 System.out.println("AccountServer started...");4 while (true) {5 try {6 Socket clnt = accept();7 ObjectInputStream ois = new ObjectInputStream(8 clnt.getInputStream());9 ObjectOutputStream oos = new ObjectOutputStream(

135

Page 145: 67544219-OOP-JAVA

What is a Thread? 12.1

10 clnt.getOutputStream());11 AccountProtocol acctProto =12 (AccountProtocol)ois.readObject();13 try {14 switch (acctProto.getCommand()) {15 // Process command16 }17 } catch (Exception e) {18 . . .19 } finally {20 . . .21 }22 } catch (Exception e) { }23 }24 }25 . . .

When the server starts, the JVM creates the first thread to executethe server. This thread is called the primordial thread. This thread willhang in accept() until it receives a connection. When a client connec-tion comes in (line 6 ), the server returns from accept() and reads in theAccountProtocol object (line 11, 12 ) and proceeds to handle the con-tained command (line 14 to 16 ) by calling the appropriate handleXXX()method. The server has just received a client connection and is presently inhandleGet() method. At this point, another client contacts the server. Butsince the server is in handleGet(), the client is forced to wait until the serverreturns to accept() to accept the connection. This is one instance wherewe can use thread to make our program more efficient and responsive by cre-ating a thread to handle the client while the server’s thread returns to waitin accept(). We will return to this example a little later and mutithreadit.

12.1 What is a Thread?

So what exactly is a thread? A thread is an execution path viz. a sectionof code executed independently of other threads within a single program. Athread has the following characteristics:

• Threads start their execution at a well know point just as Java pro-grams start their execution at a well known point. A Java programwill always start executing at main().

• Statemets from a thread’s starting point are executed according totheir sequence. A thread can access all local variables and membervariables.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 136

Page 146: 67544219-OOP-JAVA

Creating a Thread 12.1.1

• Threads are independent of each other; their execution order is con-sider to be non-deterministic viz. you cannot predict the order ofexecution of the threads.

12.1.1 Creating a Thread

There are 2 ways that you can create a thread with JDK. You can either

1. subclass Thread class, or

2. implements the Runnable interface.

believe that the second method is more flexible because you can alwaysimplement more than 1 interface but subclass only on class. So we will lookat creating threads from the Runnable interface perspective. Once you haveunderstand this approach, creating threads by subclassing Thread is veryeasy. Subclassing Thread is in fact a specialization of the first method. Wewill leave this as an exercise for the reader1.

To create a thread, you must implement the Runnable interface. Theinterface contains only 1 method and is define as below:

public interface Runnable {public void run();

}

You class that implements Runnable must implement run(). The run()method is very important to a thread because it is the thread’s startingpoint just as main() is a Java program’s starting point.

When a thread starts, it will execute the run() method. When thethread has completed executing run(), the thread is said to have completedand therefore dead. Consider the below code:

1 import java.lang.*;2 public class ThreadedMessage3 implements Runnable {4 private String msg;5 public ThreadedMessage(String m) {6 msg = m;7 }8 public void run() {9 System.out.println(msg);

10 }11 }

1Hint: think of subclassing and overriding.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 137

Page 147: 67544219-OOP-JAVA

Creating a Thread 12.1.1

line 3, We implement the Runnable interface if we want this class to runas a thread. The ThreadedMessage class is not a thread yet. Byimplementing the Runnable interface, we are merely giving this classthe capability to run as a thread.

line 8 to 10, The run() method which we must implement.

Now that we have a class which is capable of running as a thread, we willnow make it run as one. The following code snippet shows how:

1 . . .2 ThreadedMessage msg0 = new ThreadedMessage(3 "Hello threaded world #1");4 ThreadedMessage msg1 = new ThreadedMessage(5 "Hello threaded world #2");6 ThreadedMessage msg2 = new ThreadedMessage(7 "Hello threaded world #3");8 Thread thr0 = new Thread(msg0);9 Thread thr1 = new Thread(msg1);

10 Thread thr2 = new Thread(msg2);11 thr0.start();12 thr1.start();13 thr2.start();14 . . .

line 2 to 7, We create 3 instances of ThreadedMessage. These are just yourregular instance. Nothing fancy.

line 8 to 10, Now we create 3 instances of Thread. The Thread class takesa Runnable interface in its constructor.

line 11 to 13, When we call start() on the Thread instance, the Threadinstance will start running as a bona fide thread.

The above code deserves a little more explanation. When we pass an in-stance of ThreadedMessage , msg0 for example, to an instance of Thread(thr0), we are asking thr0 to execute msg0 as a thread. At this point thr0is not a thread yet. When we call start(), the JVM will start thr0 as athread. At this point, thr0 will start executing run(). The thread thr0 issaid to complete when it has completed executing run(). Figure 12.1 showsthe interaction of the threads.

Therefore, creating a thread involves the following steps:

1. Implement the Runnable interface in your class. Write code in run()method; these code will be executed by the thread.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 138

Page 148: 67544219-OOP-JAVA

Thread Class 12.1.2

Thread

Line no.4 6 8`2

msg0

msg1

msg2

primordial

9` 10 11 12 13

Figure 12.1: Time/thread graph

2. Instantiate a Thread object, giving it the class that implements theRunnable interface in the Thread’s constructor.

3. Call start() on the Thread object.

12.1.2 Thread Class

Now that we know how to create threads, lets examine some useful methodsin the Thread class.

public boolean isAlive()Checks if a thread is alive. The definition of is alive is the thread hasnot completed executed the run() method.

public void start()This method starts a thread. Note that you cannot restart a threadwith this method if a thread is completed. You have to recreate thethread instance.

public void setDaemon(boolean d)Sets if the thread is a daemon thread viz. a worker thread. When youcreate a thread, by default, these thread are known as user thread.User thread are threads that are performing your code. By contrast,daemon threads are those threads that provide certain services likeclocking and watchdog. A Java program will not exit if there are user

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 139

Page 149: 67544219-OOP-JAVA

Thread Class 12.1.2

threads which are still alive. You can set a thread to be daemon bycalling this method with true. This method can only be called beforeyou call start().

public void setName(String name)Sets a user friendly name to your thread.

public void setPriority(int p)Changes the priority of the thread. A thread can be in one of thefollowing 3 priorities:

• Thread.MAX_PRIORITY

• Thread.MIN_PRIORITY

• Thread.NORM_PRIORITY

You can set any priorities between the range of MAX_PRIORITY andMIN_PRIORITY inclusive. We will look at priorities in section 12.1.3.

public void sleep(long time)Causes the thread to cease execution for a period of time (in millisec-onds). When a thread is a sleep it does not loose ownership of thelocks that it is holding. We will look at locks in the following section.

public native static Thread currentThread(int p)Returns the thread that is executing the current object.

public void yield()Causes the current thread to temporarily stop executing so that otherthreads can have a chance to execute.

We will now rewrite AccountServer that it allocates a thread for eachconnection. AccountServer now behaves as follows:

• When the server receives a connection, accept() will return a Socketinstance.

• This Socket will passed to a thread called ConnectionHandler whichis responsible for handling client’s requests.

• The server thread (primordial thread) will return to accept() to waitfor other client connections.

Lets look at the ConnectionHandler first; the listing is as below:

1 import java.lang.*;2 import java.io.*;3 import java.net.*;4 public class ConnectionHandler

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 140

Page 150: 67544219-OOP-JAVA

Thread Class 12.1.2

5 implements Runnable {6 private ObjectInputStream ois;7 private ObjectOutputStream oos;8 private Socket clnt;9 public ConnectionHandler(Socket sock)

10 throws IOException {11 clnt = sock;12 }13 public void run() {14 try {15 ois = new ObjectInputStream(clnt.getInputStream());16 oos = new ObjectOutputStream(clnt.getOutputStream());17 AccountProtocol acctProto =18 (AccountProtocol)ois.readObject();19 try {20 switch (acctProto.getCommand()) {21 case AccountProtocol.GET:22 handleGet(oos, acctProto);23 break;24 case AccountProtocol.PUT:25 handlePut(oos, acctProto);26 break;27 case AccountProtocol.ERROR:28 default:29 }30 } catch (Exception e) {31 oos.writeObject(new AccountProtocol(32 AccountProtocol.ERROR, 0));33 oos.flush();34 } finally {35 ois.close();36 oos.close();37 clnt.close();38 }39 } catch (Exception e) {40 System.out.println(e.getMessage());41 }42 }43 private void handleGet(ObjectOutputStream netOOS44 , AccountProtocol proto)45 throws Exception {46 // as before47 . . .48 }

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 141

Page 151: 67544219-OOP-JAVA

Thread Class 12.1.2

49 private void handlePut(ObjectOutputStream netOOS50 , AccountProtocol proto)51 throws Exception {52 // as before53 . . .54 }55 }

If you examine the ConnectionHandler class you would have notice that allthe the code is exactly from AccountServer. The bulk of the code whichwas previously in a while loop is now in a run() method (line 13 to 42 ).

The following is a multi threaded version of the original AccountServer:

1 import java.lang.*;2 import java.io.*;3 import java.net.*;4 public class AccountServer5 extends ServerSocket {6 public static final int PORT = 12345;7 public AccountServer(int port)8 throws IOException {9 super(port);

10 }11 public void run() {12 System.out.println("AccountServer started...");13 while (true) {14 try {15 Thread thread = new Thread(16 new ConnectionHandler(accept()));17 thread.start();18 } catch (Exception e) {19 System.out.println(e.getMessage());20 }21 }22 }23 public static void main(String[] args)24 throws Exception {25 AccountServer server = new AccountServer(PORT);26 server.run();27 }28 }

Notice how simple AccontServer has become. Most of the “multi thread-ing” logic is between between lines 15 to 17. When the server receivesa client connection, it creates a ConnectionHandler to handle the client.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 142

Page 152: 67544219-OOP-JAVA

Enhancing AccountServer 12.2

The ConnectionHandler instance is started as a thread. At this point theConnectionHandler thread will handle the client’s requests (in run()) whilethe server thread returns to wait for other client connection (line 15 ).

12.1.3 Priorities

You can give priorities to threads. This is done with the setPriority()method. The default priority for all threads is Thread.NORM_PRIORITY. Ahigher priority thread will preempt a lower priority thread. The followingmethods suspends the execution of the calling thread and gives other threadsa chance to execute:

yield() When a thread calls yield(), it stops executing temporarily andgive threads of higer or equal priority a chance to execute.

sleep() A thread which calls sleep() will temporarily (for the durationof the sleep time) stop executing and give lower priority threads achance to run.

12.1.4 States of a Thread

A thread can be in one of the following 4 states:

Initial A thread is said to be in its initial state when it is created untilstart() is called.

Runnable A thread is in its runnable state after its start() is called. Arunnable thread does not mean that the thread is actually running.This is for the thread scheduler to decide. All this state says is thatthe thread is ready to run.

Blocked A blocked thread is one that cannot run because it is waiting forsome resource or some events.

Exiting When a thread has completed its run().

Figure 12.2 show the life cycle of a thread and its transistion between thevarious states.

12.2 Enhancing AccountServer

Before we proceed further with threads, lets return to look at the currentstate of our AccountServer. Consider the following scenerio:

A client connects to the server and request account number 12345. Theserver deserializes the account and returns it to the client. The connectionbetween the client and the server is now severed. This behaviour is codifiedin AccountServer and AccountServerAPI in chapter 11. After the first

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 143

Page 153: 67544219-OOP-JAVA

Enhancing AccountServer 12.2

Initial

Blocked

Runn-able

Exiting

new Thread()

wait()

completesrun() notify()

start()

yield() orpreempted

Figure 12.2: Life cycle of a thread

client has request 12345, a second client connects and request the same ac-count. We could not possibally return the account to another client becausethis would cause account 12345 to be inconsistent.

To solve this problem, the server must know what Account objects havebeen requested. The server needs to keep a checkout list so that any sub-sequent request for account found on this list will be rejected. When thechecked out account is later save, it is taken off this list. The new behaviourfor AccountServer is as follows:

1. The server receives a client connection. It spawns a ConnectionHandlerthread and passes it the connection.

2. If the command is a GET, the ConnectionHandler thread checks therequested account number against a requested list. If the account isnot on the list, the thread will return the requested account with anOKAY status.

3. But if the account has been checked out, the thread will return a newstatus, INUSE to the client.

4. If the client sends a PUT command, the server must now check if theaccount is on the checkout list. If it is, the server must remove itfrom the list after serializing the account. If the account has not beenchecked out, we just serializes it.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 144

Page 154: 67544219-OOP-JAVA

Enhancing AccountServer 12.2

5. We define an additional command called RELEASE which essentiallydoes the same thing as a PUT except that RELEASE only removes anaccount from the checkout list.

The modified protocol is shown in figure 12.3.

Receives aGET

Receives aPUT

Gets theaccount

Saves theaccount

Successful?

ReturnsOKAY

ReturnsERROR

true false

Checkout?

ReturnsINUSE

ReturnsERROR

true false

Add tocheckout

Remove fromcheckout

Figure 12.3: A modifed flow diagram of AccountServer’s protocol

To implement the checkout list, we employ Hashtable class. This classimplements a hashtable. Briefly, hashtable is a structure that allows youto store data by associating the data with a unique key. We will use thefollowing 3 methods from Hashtable:

public Object put(Object key, Object data)Associate the key with data. If the key exists in the hashtable, theprevious will be returned and the current data data will take its place.

public boolean containsKey(Object key)Test if the hashtable contains key.

public Object remove(Object key)Deletes the key from the hashtable. Will return null if the key is notin the hashtable; otherwise the corresponding data is returned.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 145

Page 155: 67544219-OOP-JAVA

Enhancing AccountServer 12.2

All 3 classes that implements the server must be modified. These classes areAccountServer, ConnectionHandler and AccountProtocol. Modificationto AccountProtocol is as follows; we add the INUSE (line 7 ) and RELEASE(line 8 ) to the list of commands.

1 public class AccountProtocol2 implements Serializable {3 public static final int ERROR = -1;4 public static final int GET = 0;5 public static final int PUT = 1;6 public static final int OKAY = 2;7 public static final int INUSE = 3;8 public static final int RELEASE = 4;9 private final int cmd;

10 private final int accountId;11 private final Account account;12 public AccountProtocol(int c, int id) {13 . . .

The following is a listing of the modified AccountServer.

1 import java.lang.*;2 import java.io.*;3 import java.net.*;4 import java.util.*;5 public class AccountServer6 extends ServerSocket {7 public static final int PORT = 12345;8 private Hashtable checkout;9 public AccountServer(int port)

10 throws IOException {11 super(port);12 checkout = new Hashtable();13 }14 public void run() {15 System.out.println("AccountServer started...");16 while (true) {17 try {18 Thread thread = new Thread(19 new ConnectionHandler(accept(), checkout));20 thread.start();21 } catch (Exception e) {22 System.out.println(e.getMessage());23 }24 . . .25 }

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 146

Page 156: 67544219-OOP-JAVA

Enhancing AccountServer 12.2

line 4, Hashtable class is in java.util package.

line 8, We declare checkout as a Hashtable.

line 12, Instantiate checkout when we create the server. A instance ofHashtable is shared by all ConnectionHandler threads.

line 19, When we create a thread, we now need to pass to the threadcheckout. The thread will check if a given account is in checkout.

Everything else in AccountServer remains save for those modificationslisted above.

And finally, the listing for ConnectionHandler.

1 import java.lang.*;2 import java.io.*;3 import java.net.*;4 import java.util.*;5 public class ConnectionHandler6 implements Runnable {7 private ObjectInputStream ois;8 private ObjectOutputStream oos;9 private Socket clnt;

10 private Hashtable checkout;11 public ConnectionHandler(Socket sock, Hashtable table)12 throws IOException {13 clnt = sock;14 checkout = table;15 }16 public void run() {17 try {18 ois = new ObjectInputStream(clnt.getInputStream());19 oos = new ObjectOutputStream(clnt.getOutputStream());20 AccountProtocol acctProto =21 (AccountProtocol)ois.readObject();22 try {23 switch (acctProto.getCommand()) {24 . . .25 case AccountProtocol.RELEASE:26 handleRelease(oos, acctProto);27 break;28 . . .29 }30 } catch (Exception e) {31 . . .

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 147

Page 157: 67544219-OOP-JAVA

Enhancing AccountServer 12.2

32 }33 private void handleGet(ObjectOutputStream netOOS34 , AccountProtocol proto)35 throws Exception {36 AccountProtocol result;37 Integer key = new Integer(proto.getAccountNumber());38 if (checkout.containsKey(new Integer(key))) {39 result = new AccountProtocol(AccountProtocol.INUSE, 0);40 } else {41 FileInputStream fis = new FileInputStream(key + ".ser");42 ObjectInputStream ois = new ObjectInputStream(fis);43 Account account = (Account)ois.readObject();44 result = new AccountProtocol(45 AccountProtocol.OKAY, account);46 ois.close();47 checkout.put(key, account);48 }49 netOOS.writeObject(result);50 netOOS.flush();51 }52 private void handlePut(ObjectOutputStream netOOS53 , AccountProtocol proto)54 throws Exception {55 FileOutputStream fos = new FileOutputStream(56 proto.getAccountNumber() + ".ser");57 ObjectOutputStream oos = new ObjectOutputStream(fos);58 oos.writeObject(proto.getAccount());59 oos.flush();60 oos.close();61 handleRelease(netOOS, proto);62 }63 private void handleRelease(ObjectOutputStream netOOS64 , AccountProtocol proto) {65 Integer key = new Integer(proto.getAccountNumber());66 if (checkout.containsKey(key))67 checkout.remove(key);68 netOOS.writeObject(new AccountProtocol(69 AccountProtocol.OKAY, 0));70 netOOS.flush();71 }72 public static void main(String[] args) {73 . . .

The explanation for the modified ConnectionHandler is as follows:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 148

Page 158: 67544219-OOP-JAVA

Enhancing AccountServer 12.2

line 14, Hold a reference to the Hashtable object that is passed.

line 25, 26, In addition to GET and PUT (not shown), we also check if thecommand is a RELEASE. If it is we call the handleRelease() method.

line 33 to 51, The handleGet() method is now modified so that it willcheck checkout first before returning the requested account. If therequested account is in checkout, a INUSE is returned.

line 37, Create a key using the account number. The key has to be anobject because the put() method in Hashtable only accepts Objects(see page 145).

line 38, We now check if the account has been requested using the keycreated from the previous line.

line 39, If the account has been checked out, we return a INUSE commandback to the client.

line 41 to 45, Otherwise we retrieve the account as before.

line 46, After we have deserialized the account we now need to put thisaccount in checkout.

line 52 to 62, handlePut()method serializes an account as well as removingthe account from checkout.

line 61, We use handleRelease() method to remove an account fromcheckout.

line 63 to 71, The handleRelease() removes an account from the checkoutlist.

line 65, Again we create a key from the account number.

line 66, We check if the account is on the checkout list.

line 67 to 69, If it is we remove it from checkout and returns an OKAY tothe client.

To accomodate the new INUSE command, we add a new method toAccountServerAPI called isInUse() which indicates if the last operationon an account is has been checkout by another client. The following list thisnew method and modifications to the AccountServerAPI class.

1 public class AccountServerAPI {2 . . .3 private boolean inuse;4 public AccountServerAPI(String hn) {

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 149

Page 159: 67544219-OOP-JAVA

Synchrnonization 12.3

5 hostname = hn;6 inuse = false;7 }8 . . .9 public AccountProtocol write(AccountProtocol proto)

10 throws APIException {11 AccountProtocol result = null;12 connect();13 try {14 oos.writeObject(proto);15 oos.flush();16 result = (AccountProtocol)ois.readObject();17 inuse = AccountProtocol.INUSE == result.getCommand();18 } catch (Exception e) {19 close();20 throw new APIException(e.getMessage());21 }22 try {23 close();24 } finally {25 return (result);26 }27 }28 public boolean isInUse() {29 return (inuse);30 }31 . . .32 }

line 3, Add a new member inuse which keeps track of the INUSE command.

line 17, After we have read the return result from the server, we set inuse.

line 28 to 30, Checks if the last command involved a checkout account.

12.3 Synchrnonization

In the previous section, we modified our AccountServer and ConnectionHandlerclass such that a checkout account will be entered into a checkout list. Thismethod of updating is acceptable if our server is single threaded. But it isnot. Consider the following: a client request for account 12345. A threadis created (thr1) thread which then checks if 12345 is in the checkout list.12345 is not on the list. thr1 proceeds to access the account from harddisk but gets preempted. At this point in time, a second thread (thr2) is

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 150

Page 160: 67544219-OOP-JAVA

synchronized Keyword 12.3.1

created for another client which also happens to reqests 12345. It checksthe checkout list. 12345 is not on the list. This is because thr1 has not yetupdate the checkout list. thr2 then proceeds to deserialize 12345, updatesthe checkout list and returns the Account object back to the client. Thethread scheduler now continues thr1’s execution. thr1 completes its re-quest: deserializes 12345, updates the checkout list and returns the accountback to the client. This interaction is shown in figure 12.4.

What we need is a way of making the deserialize and updating the check-out list atomic. An atomic action is an action that cannot be further brokeninto smaller actions; in other words the deserialization and updating thecheckout list actions cannot be interrupted. So how are we going to createan atomic action out of the deserialization and updating actions.

As it turns out, every Java object has a lock and since our programis abound with objects, we could theoretically use any object to act as alock. In practise, we should choose the object that best fits the purpose.In our case, the best candidate would be checkout in AccountServer.The reason for choosing checkout is because this object is shared by allConnectionHandler threads. AccountServer passes the same checkoutobject to all threads that it creates. To implement atomicity, we performthe following steps:

• A ConnectionHandler thread will try to lock checkout object. Uponacquiring the lock, the thread will deserialize the requested accountand updates checkout. After performing the two actions, the threadreleases the lock.

• When a ConnectionHandler thread tries to lock checkout and findsthat another thread has acquired the lock, the thread will not pro-ceed until the lock has been released and it has acquired it. This isperformed by the JVM.

• When 2 threads tires to simultaneously acquire a lock, the JVM willarbitrarily assign the lock to a thread.

12.3.1 synchronized Keyword

We will now introduce the synchronized keyword which is used to acquirea lock. The syntax is as follows:

synchronized(<object>){<body>

}

The <object> is the object whose lock we are trying to acquire. If we aresuccessful, we will proceed into the <body>. If we are not succesful, we

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 151

Page 161: 67544219-OOP-JAVA

synchronized Keyword 12.3.1

thr1 thr2Thread is created to GET 12345.Checks if 12345 is on the checkout list.It is not.Deserializing 12345 but gets pre-empted.

Thread is created to GET 12345.

Checks if 12345 is no the checkout list.It is not.Deserializes 12345.Returns 12345 to client.Updates checkout list.Terminates.

Continues running. Completes deseri-alization.Returns 12345 to client.Updates checkout list.Terminates.

Figure 12.4: A race condition

will “wait” at synchronized until we acquire the lock. When we exit the<body>, we releases the lock. Therefore, the curly brackets ({ }) defines thescope of the lock. The <body> is also called a critical region because only 1thread is allowed in at any one time.

If a thread which is holding a lock gets preempted, it still holds the lock.So atomicity is guranteed. The modifications to ConnectionHandler is asfollows:

1 public class ConnectionHandler2 implements Runnable {3 . . .4 private Hashtable checkout;5 . . .6 private void handleGet(ObjectOutputStream netOOS7 , AccountProtocol proto)8 throws Exception {9 AccountProtocol result;

10 Integer key = new Integer(proto.getAccountNumber());11 synchronized(checkout) {12 if (checkout.containsKey(key)) {13 result = new AccountProtocol(AccountProtocol.INUSE14 , 0);15 } else {

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 152

Page 162: 67544219-OOP-JAVA

synchronized Keyword 12.3.1

16 FileInputStream fis = new FileInputStream(key + ".ser");17 ObjectInputStream ois = new ObjectInputStream(fis);18 Account account = (Account)ois.readObject();19 result = new AccountProtocol(AccountProtocol.OKAY20 , account);21 ois.close();22 checkout.put(key, account);23 }24 }25 netOOS.writeObject(result);26 netOOS.flush();27 }28 private void handlePut(ObjectOutputStream netOOS29 , AccountProtocol proto)30 throws Exception {31 synchronized(checkout) {32 FileOutputStream fos = new FileOutputStream(33 proto.getAccountNumber() + ".ser");34 ObjectOutputStream oos = new ObjectOutputStream(fos);35 oos.writeObject(proto.getAccount());36 oos.flush();37 oos.close();38 handleRelease(netOOS, proto);39 }40 }41 private void handleRelease(ObjectOutputStream netOOS42 , AccountProtocol proto)43 throws Exception {44 Integer key = new Integer(proto.getAccountNumber());45 synchronized(checkout) {46 if (checkout.containsKey(key))47 checkout.remove(key);48 }49 netOOS.writeObject(new AccountProtocol(AccountProtocol.OKAY50 , 0));51 netOOS.flush();52 }53 }

line 11 to 24, This synchronized block (critical region) ensures that dese-rialization and updating of checkout is atomic. Note that we havechanged nothing in the original code save for enclosing it with asynchronized.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 153

Page 163: 67544219-OOP-JAVA

Thread Safe Objects 12.3.2

line 31 to 39, Just as a GET is atomic, so a PUT command must be atomic aswell since both handleGet() and handlePut() manipulates the samecheckout list. If handlePut() is not synchronized, then this methodwill update checkout without regard to what handleGet() is doing.This can lead to inconsistencies in the checkout list.

line 45 to 48, Similarly, when we handle a RELEASE command, we also needto acquire the lock to checkout before modifying checkout.

A few pointers to remember when you are using synchronized:

• Create the smallest possible block; otherwise you are delaying the lock.This could lead to performance problem if you have lots of threadswaiting to enter the critical region.

• You should always try to release a lock as quick as possible. Again,the reason should be obvious.

• Never write nested synchronized blocks as below:

synchronized(anObject) {. . .synchronized(anotherObject) {

. . .}

}

This can lead to dead locks.

12.3.2 Thread Safe Objects

We have seen that by using synchronized, we create a critical region whichmaintains atomicity on all the statements contain therein. But we mustremember to explicitly lock the object (checkout in the example above).What if, in our haste, we forget to lock checkout before we use, or that theperson who is writing threaded programs is a novice and have no notion ofthread safeness.

So, if you know that your program is going to be used in a multi threaded,make your class thread safe. Instead of requiring others to synchronized()the object before using, we can declare a method to be synchronized as inthe example below:

public synchronized void someMethod() {. . .

}

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 154

Page 164: 67544219-OOP-JAVA

Thread Safe Objects 12.3.2

When we invoke someMethod(), we must acquire the lock to the object viz.the object which someMethod() is part of. When we leave the method, werelease. As before, the method body of someMethod() is now considered thecritical region. This is just a variation of the follow:

public void someMethod() {synchronized(this) {

. . .}

}

With this new found knowledge, lets modify AccountServer such thatwe can control the maximum number of ConnetionHandler thread theserver can create at any one time. We will call this class Counter. TheCounter class has 1 constructor which takes an int; the int specifies thenumber of thread that can be active at any given time. Counter class hasthe following methods:

public synchronized boolean add()Increments the count. add() will return true then we have not ex-ceeded the limit; false otherwise.

public synchronized void release()Decrement the count.

public void getCurrentCount()Returns the number of currently active thread. Notice that this methoddoes not have the synchronized keyword in its method declaration.We will explain this shortly.

public void getCount()Returns the maximum count. This method is not synchronized aswell.

The listing for Counter is as follows:

1 public class Counter {2 private final int maximum;3 private int current;4 public Counter(int max) {5 maximum = max;6 current = 0;7 }8 public synchronized boolean add() {9 if (current == maximum)

10 return (false);11 current++;

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 155

Page 165: 67544219-OOP-JAVA

Thread Safe Objects 12.3.2

12 return (true);13 }14 public synchronized void release() {15 current = (--current < 0)? 0: current;16 }17 public int getCurrentCount() {18 return (current);19 }20 public int getCount() {21 return (maximum);22 }23 }

line 5, We set the variable maximun which controls the number of threadthat can be active at any given time.

line 6, current holds the number of thread that is active at any given time

line 8 to 13, This is the first of the thread safe method. We must acquirethe lock to the object (this) before we can invoke this method.

line 9, 10, We check if we have reached the limit, if we have then we returnfalse.

line 11, 12, Otherwise we increment current and return true.

line 14 to 16, The release() method decrements the current variable.

line 17 to 19, Returns the number of active thread; viz. the value ofcurrent.

line 20 to 22, This method returns the maximum count; viz. the value ofmaximum.

As we have pointed out earlier, we do not need to lock the object beforeinvoking getCount(). Why? The observant reader will have notice thatboth add() and release() modifies the current variable. We cannot have2 thread calling add() and relase() simultaneous. The behaviour is non-deterministic; to enforce orderly update of current, we require the invokerof the 2 methods to acquire the object lock first before proceeding. Butsince getCount() and getCurrentCount() does not update count we donot need to lock the object. This prevents unnecessary delay.

Modifications to AccountServer and ConnectionThread is only mini-mal. The changes to these classes are as follows:

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 156

Page 166: 67544219-OOP-JAVA

Thread Safe Objects 12.3.2

1 public class AccountServer2 extends ServerSocket {3 . . .4 private Counter count;5 public AccountServer(int port)6 throws IOException {7 super(port);8 checkout = new Hashtable();9 count = new Counter(5);

10 }11 public void run() {12 System.out.println("AccountServer started...");13 while (true) {14 try {15 Thread thr = new Thread(new ConnectionHandler(accept()16 , checkout, count));17 thr.start();18 } catch (Exception e) {19 System.out.println(e.getMessage());20 }21 }22 }23 . . .24 }

The following lines are noteworthy:

line 9, Create an instance of Counter. We have hard coded the Counterso that it only allows a maximum 5 threads to be active.

line 15. 16, Now whenever we create a thread, will pass to it the countobject.

Let’s turn our attention to ConnectionThread and see how it uses Counterclass.

1 public class ConnectionHandler2 implements Runnable {3 . . .4 private Hashtable checkout;5 private Counter count;6 public ConnectionHandler(Socket sock, Hashtable table7 , Counter cnt)8 throws IOException {9 clnt = sock;

10 checkout = table;

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 157

Page 167: 67544219-OOP-JAVA

Condition Variables 12.4

11 count = cnt;12 }13 public void run() {14 if (!count.add())15 return;16 try {17 . . .18 } catch (Exception e) {19 System.out.println(e.getMessage());20 }21 count.release();22 }23 . . .24 }

line 14, We try to increnemnt count. If we are successful, we continueexecuting the thread.

line 15, If we cannot increment count, we then exit from the thread.

line 21, When we are done with our processing, we must call release()to decrement the count before we exit.

12.4 Condition Variables

If synchronized allows threads to enter and exit critical region in an orderlymanner then condition variables allows one thread to notify another whencertain condition exists. Consider the following: presently Counter will willterminate a thread2 if there are already a maximum number of thread active.A better way to handle this situation might be as follows:

When we have reached maximum number of active threads, then put thenext thread in a waiting area. When one of the currently running threadterminates, it notifies the waiting thread that there is now a slot availablefor it to run. The waiting thread then resumes execution. The conditionhere is that if current have reached maximum we wait for it to drop belowmaximum.

To implement condition variables, we use wait() and notify(). Thesetwo methods are found in Object class. Since every object in the JVMinherits directly or indirectly from Object, we can use condition variableson all objects. The following explains these 2 methods:

public void wait()Waits for a condition to occur. The wait() method causes a thread

2It will return false and ConnectionHandler will terminate the thread.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 158

Page 168: 67544219-OOP-JAVA

Condition Variables 12.4

to wait until it is notified by another thread to stop waiting. Whenwait() is called, the thread releases its lock on an object and waitsuntil another thread notifies it to wake up through notify(). After athread is awakened, it must reacquire the lock before it can proceed.The caller of this method must first acquire the lock; viz. calling fromwithin a synchronized block.

public void notify()This method wakes up a thread that has called wait(). notify()arbitrarily awakens just 1 thread. This method can only be called bythe current owner of the lock.

Both the above method will throw IllegalMonitorStateException if thecaller is not the current owner of the lock. Below is a reimplementation ofCounter that uses condition variables:

1 public class Counter2 extends Object {3 private final int maximum;4 private int current;5 public Counter(int max) {6 maximum = max;7 current = 0;8 }9 public synchronized void add() {

10 if (current == maximum)11 while (true)12 try {13 wait();14 break;15 } catch (InterruptedException e) { }16 current++;17 }18 public synchronized void release() {19 current = (--current < 0)? 0: current;20 notify();21 }22 public int getCount() {23 return (maximum);24 }25 }

line 13, If we have already reached maximum, then we wait until we arenotified.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 159

Page 169: 67544219-OOP-JAVA

Implication of static on Threads 12.5

line 14, When we awakened from wait(), we exit the while loop.

line 15, wait() throws InterruptedException. In this case we ignore thisexception. When we return from the empty exception body we returnto the wait() method by virtue of the infinate loop.

line 20, When we decrement current, we call notify() to wakeup anywaiting threads.

Notice that both wait() and notify() are called from within a synchronizedblock. This is what we mean by saying you have to acquire the object’slock before invoking either of those methods. We now need to modify onlyConnectionHandler to change the way we invoke add() as below:

1 . . .2 public void run() {3 count.add();4 try {5 . . .6 } catch (Exception e) {7 System.out.println(e.getMessage());8 }9 count.release();

10 }11 . . .

So how does this new scheme works? We have 2 ConnectionHandlerthreads; lets call them thr1 and thr2. thr1 is running and has just calledadd() so that current is now equals to maximum. Now when thr2 invokeadd() by first acquiring the Counter’s lock. But add() will not let thr2proceed because the maximum has been reached. So Counter puts thr2in a waiting area by invoking wait(). thr2 also gives up the lock that itis holding. When thr1 completes, it calls release() before it exits. Thistrigger a call to notify(). thr2 awakens but it could not continue yetbecause it has to reacquire the object’s lock. When thr1 exits release(),it releases the lock. thr2 then acquires the lock and continues with itsexecution. This interaction is shown in figure 12.5.

12.5 Implication of static on Threads

During the course of this book, you have notice that we have at numeroustimes preceed member or method declarations with static. What exactlyis static?

We know that when we instantiate 2 instance of FixedDepositAccount,the members of both instances are separate in the sense that if we were to

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 160

Page 170: 67544219-OOP-JAVA

Implication of static on Threads 12.5

thr1 thr2Acquire Counter’s lock. Calls add().Release lock on exit.Continues running.

Acquire Counter’s lock. Calls add().Cannot proceed. Calls wait(). Re-lease lock and go to sleep.

Acquire Counter’s lock. Callsrelease(). release() callsnotify().

Wakes up. Tries to get Counter’s lock.

Exits release(). Releases Counter’slock.

Got Counter’s lock.

Continues running.

Figure 12.5: wait() and notify() interaction

change the name member of one instance via setName(), it will not affectthe name of another instance.

Sometimes, we might want all instances to share a single member viz.changing a member variable cause all other instances to “see” this change.To achieve this behaviour, we preceed a member’s declaration with static.Consider the following simple declaration:

1 public class Fred {2 public String name;3 public static int age;4 }

Now if we were to create 2 instances of Fred and perform the followingoperations on these instances:

1 Fred flintstone = new Fred();2 flintstone.name = "Flintstone";3 flintstone.age = 40;4 Fred mercury = new Fred();5 mercury.name = "Mercury";6 mercury.age = 45;

The result of listing below:

name ageflintstone Flintstone 45mercury Mercury 45

Notice that both age member are 45 but name remains their respectivevalues. This is because of the static declaration on age. By making age

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 161

Page 171: 67544219-OOP-JAVA

Implication of static on Threads

static, we are declaring that there is only 1 copy of age no matter how manyinstance of Fred we have instantiated. When we change a static member,all other instance sees it. Members declared with static are called classmembers since there is only 1 copy of that member for the entire class;non static members are called instance member since they are local to theinstance only.

We can access class members without actually instantiating it. To accessa class member, we specify the class name followed by the class member.The syntax is as follows:

<class_name>.<class_member>

Therefore to access age, we do the following:

Fred.age = 45;

Methods declared with static are called class methods. Class methodsdiffer from instance methods in one important way: you cannot use thisin a class method’s body. This is because a class method is not associatedwithy any particular instance.

What impact does class methods or members have on thread program-ming? When a member is declared static, there is only one copy. So ifyou lock a static member, you are effectively locking out all access to thatmember.

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 162

Page 172: 67544219-OOP-JAVA

Appendix A

Listing

The following is a complete list of all classes pertaining to the Account classthat we have used as an example throughout this book. The listing is baseon ideas that we have developed until chapter 12.

A.1 Core Classes

The following listing pertains to the core Account class.

A.1.1 Account.java

1 import java.lang.*;

2 import java.io.*;

3 import java.util.*;

4 public abstract class Account

5 implements Serializable {

6 public static final long serialVersionUID = 1234567890L;

7 private String name;

8 private int acctNo;

9 private float balance;

10 private boolean overdraft;

11 private Interest interest;

12 private Vector listeners;

13 public class DefaultRate

14 implements Interest {

15 public float calculate(float amt) {

16 return (balance * 0.1F);

17 }

18 }

19 public Account() { }

20 public Account(String n, int no) {

21 name = n;

22 acctNo = no;

23 balance = 100F;

24 overdraft = false;

25 listeners = new Vector();

163

Page 173: 67544219-OOP-JAVA

Account.java A.1.1

26 interest = new Interest() {

27 private float monthlyRate[] = {0.1F, 0.07F, 0.1F, 0.1F

28 , 0.1F, 0.12F, 0.1F, 0.1F, 0.08F, 0.1F, 0.1F, 0.0F};

29 private float rate; {

30 rate = monthlyRate[

31 (Calendar.getInstance()).get(Calendar.MONTH)];}

32 public float calculate(float amt) {

33 return (balance * rate);

34 }

35 };

36 }

37 public void setName(String n) {

38 name = n;

39 }

40 public String getName() {

41 return (name);

42 }

43 public int getAccountNumber() {

44 return (acctNo);

45 }

46 public float getBalance() {

47 return (balance);

48 }

49 public void setOverdraft(boolean b) {

50 overdraft = b;

51 }

52 public boolean isOverdraft() {

53 return (overdraft);

54 }

55 public abstract void printAccount();

56 public void setInterestCalculation(Interest i) {

57 interest = i;

58 }

59 public float calculateInterest() {

60 if (interest != null)

61 return (interest.calculate(getBalance()));

62 else

63 return (0F);

64 }

65 public void deposit(float amt)

66 throws ErroneousAmountException {

67 if (amt < 0)

68 throw new ErroneousAmountException("deposit", this, amt);

69 if (amt >= 0)

70 balance += amt;

71 fireMoneyDeposited(new AccountEvent(this, amt));

72 }

73 public void withdrawal(float amt)

74 throws OverdrawnException, ErroneousAmountException {

75 if (amt > balance)

76 throw new OverdrawnException("withdraw", this, amt);

77 if (amt < 0)

78 throw new ErroneousAmountException("withdraw", this, amt);

79 balance -= amt;

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 164

Page 174: 67544219-OOP-JAVA

Account.java A.1.1

80 fireMoneyWithdrawn(new AccountEvent(this, amt));

81 }

82 public void transfer(Account from, float amt)

83 throws OverdrawnException, ErroneousAmountException {

84 if (amt < 0)

85 return;

86 from.withdrawal(amt);

87 deposit(amt);

88 }

89 private void writeObject(ObjectOutputStream out)

90 throws IOException {

91 out.defaultWriteObject();

92 out.writeLong(((((new Date()).getTime()/1000)/60)/60)/24);

93 }

94 private void readObject(ObjectInputStream in)

95 throws IOException, ClassNotFoundException {

96 in.defaultReadObject();

97 long current = ((((new Date()).getTime()/1000)/60)/60)/24;

98 if ((current - in.readLong()) > 60)

99 throw new IOException("Object expired!");

100 }

101 public void addAccountListener(AccountListener l) {

102 listeners.addElement(l);

103 }

104 public void removeAccountListner(AccountListener l) {

105 listeners.removeElement(l);

106 }

107 private void fireMoneyDeposited(AccountEvent aEvt) {

108 Vector tmpV;

109 synchronized(listeners) {

110 tmpV = (Vector)listeners.clone();

111 }

112 for (int i = 0; i < tmpV.size(); i++) {

113 AccountListener l = (AccountListener)tmpV.elementAt(i);

114 l.moneyDeposited(aEvt);

115 }

116 }

117 private void fireMoneyWithdrawn(AccountEvent aEvt) {

118 Vector tmpV;

119 synchronized(listeners) {

120 tmpV = (Vector)listeners.clone();

121 }

122 for (int i = 0; i < tmpV.size(); i++) {

123 AccountListener l = (AccountListener)tmpV.elementAt(i);

124 l.moneyWithdrawn(aEvt);

125 }

126 }

127 public String toString() {

128 return ("name = " + name + "\n"

129 + "acctNo = " + acctNo + "\n"

130 + "balance = " + balance + "\n"

131 + "overdraft = " + overdraft + "\n");

132 }

133 }

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 165

Page 175: 67544219-OOP-JAVA

AccountException.java A.1.4

A.1.2 AccountListener.java

1 import java.lang.*;

2 import java.util.*;

3 public interface AccountListener

4 extends EventListener {

5 public void moneyDeposited(AccountEvent aEvt);

6 public void moneyWithdrawn(AccountEvent aEvt);

7 }

A.1.3 AccountEvent.java

1 import java.lang.*;

2 import java.util.*;

3 public class AccountEvent

4 extends EventObject {

5 private float amount;

6 public AccountEvent(Object src, float amt) {

7 super(src);

8 amount = amt;

9 }

10 public float getAmount() {

11 return (amount);

12 }

13 }

A.1.4 AccountException.java

1 import java.lang.*;

2 import java.util.*;

3 public class AccountException

4 extends Exception {

5 private final String name;

6 private final int acctNo;

7 private final float balance;

8 private final float withdrawAmount;

9 private final Date date;

10 public AccountException(String exName, Account acct, float amt) {

11 super(exName);

12 name = acct.getName();

13 acctNo = acct.getAccountNumber();

14 balance = acct.getBalance();

15 withdrawAmount = amt;

16 date = new Date();

17 }

18 public String getName() {

19 return (name);

20 }

21 public int getAccountNumber() {

22 return (acctNo);

23 }

24 public float getBalance() {

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 166

Page 176: 67544219-OOP-JAVA

FixedDepositAccount.java A.2.1

25 return (balance);

26 }

27 public float getWithdrawAmount() {

28 return (withdrawAmount);

29 }

30 public Date getExceptionDate() {

31 return (date);

32 }

33 }

A.1.5 Interest.java

1 import java.lang.*;

2 public interface Interest {

3 public float calculate(float amt);

4 }

A.2 Subclass and Implementations

The following are classes that either subclass or implemnts one of the pre-vious class or interface.

A.2.1 FixedDepositAccount.java

1 import java.lang.*;

2 import java.util.*;

3 public class FixedDepositAccount

4 extends Account {

5 private Date term;

6 private float interest;

7 public FixedDepositAccount(String n, int acct) {

8 super(n, acct);

9 term = null;

10 interest = -1F;

11 }

12 public FixedDepositAccount(String n) {

13 this(n, Math.abs((new Random()).nextInt()));

14 }

15 public void setTerm(Date t) {

16 if (term == null)

17 term = t;

18 }

19 public Date getTerm() {

20 return (term);

21 }

22 public void setInterest(float i) {

23 if (interest == -1F)

24 interest = i;

25 }

26 public float getInterest() {

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 167

Page 177: 67544219-OOP-JAVA

TightRate.java A.2.4

27 return(interest);

28 }

29 public void withdrawal(float amt)

30 throws OverdrawnException, ErroneousAmountException {

31 Date today = new Date();

32 if (today.after(term))

33 super.withdrawal(amt);

34 }

35 public void withdrawal()

36 throws OverdrawnException, ErroneousAmountException {

37 withdrawal(getBalance());

38 }

39 public void printAccount() {

40 System.out.println("Account name = " + getName());

41 System.out.println("Amount deposited = $" + getBalance());

42 System.out.println("Mature on = " + getTerm());

43 System.out.println("Interest rate = " + getInterest() + "%");

44 }

45 }

A.2.2 SavingAccount.java

1 import java.lang.*;

2 public class SavingAccount

3 extends Account {

4 public SavingAccount(String n, int acct) {

5 super(n, acct);

6 }

7 public void printAccount() {

8 System.out.println("Account name = " + getName());

9 System.out.println("Current balance = $" + getBalance());

10 }

11 }

A.2.3 GenerousRate.java

1 import java.lang.*;

2 public class GenerousRate

3 implements Interest {

4 public float calculate(float amt) {

5 return (amt * 0.5F);

6 }

7 }

A.2.4 TightRate.java

1 import java.lang.*;

2 public class TightRate

3 implements Interest {

4 public float calculate(float amt) {

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 168

Page 178: 67544219-OOP-JAVA

AccountServer.java A.3.1

5 return (amt * 0.01F);

6 }

7 }

A.2.5 ErroneousAmountException.java

1 import java.lang.*;

2 public class ErroneousAmountException

3 extends AccountException {

4 public ErroneousAmountException(String exName, Account acct

5 , float amt) {

6 super(exName, acct, amt);

7 }

8 }

A.2.6 OverDrawnException.java

1 import java.lang.*;

2 public class OverdrawnException

3 extends AccountException {

4 public OverdrawnException(String exName, Account acct, float amt) {

5 super(exName, acct, amt);

6 }

7 }

A.3 Account Server

The following list the account server classes.

A.3.1 AccountServer.java

1 import java.lang.*;

2 import java.io.*;

3 import java.net.*;

4 import java.util.*;

5 public class AccountServer

6 extends ServerSocket {

7 public static final int PORT = 12345;

8 private Hashtable checkout;

9 private Counter count;

10 public AccountServer(int port)

11 throws IOException {

12 super(port);

13 checkout = new Hashtable();

14 count = new Counter(5);

15 }

16 public void run() {

17 System.out.println("AccountServer started...");

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 169

Page 179: 67544219-OOP-JAVA

ConnectionHandler.java A.3.2

18 while (true) {

19 try {

20 Thread thr = new Thread(new ConnectionHandler(accept()

21 , checkout, count));

22 thr.start();

23 } catch (Exception e) {

24 System.out.println(e.getMessage());

25 }

26 }

27 }

28 public static void main(String[] args)

29 throws Exception {

30 AccountServer server = new AccountServer(PORT);

31 server.run();

32 }

33 }

A.3.2 ConnectionHandler.java

1 import java.lang.*;

2 import java.io.*;

3 import java.net.*;

4 import java.util.*;

5 public class ConnectionHandler

6 implements Runnable {

7 private ObjectInputStream ois;

8 private ObjectOutputStream oos;

9 private Socket clnt;

10 private Hashtable checkout;

11 private Counter count;

12 public ConnectionHandler(Socket sock, Hashtable table, Counter cnt)

13 throws IOException {

14 clnt = sock;

15 checkout = table;

16 count = cnt;

17 }

18 public void run() {

19 count.add();

20 try {

21 ois = new ObjectInputStream(clnt.getInputStream());

22 oos = new ObjectOutputStream(clnt.getOutputStream());

23 AccountProtocol acctProto = (AccountProtocol)ois.readObject();

24 try {

25 switch (acctProto.getCommand()) {

26 case AccountProtocol.GET:

27 handleGet(oos, acctProto);

28 break;

29 case AccountProtocol.PUT:

30 handlePut(oos, acctProto);

31 break;

32 case AccountProtocol.RELEASE:

33 handleRelease(oos, acctProto);

34 break;

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 170

Page 180: 67544219-OOP-JAVA

ConnectionHandler.java A.3.2

35 case AccountProtocol.ERROR:

36 default:

37 }

38 } catch (Exception e) {

39 oos.writeObject(new AccountProtocol(AccountProtocol.ERROR, 0));

40 oos.flush();

41 } finally {

42 ois.close();

43 oos.close();

44 clnt.close();

45 }

46 } catch (Exception e) {

47 System.out.println(e.getMessage());

48 }

49 count.release();

50 }

51 private void handleGet(ObjectOutputStream netOOS, AccountProtocol proto)

52 throws Exception {

53 AccountProtocol result;

54 Integer key = new Integer(proto.getAccountNumber());

55 synchronized(checkout) {

56 if (checkout.containsKey(key)) {

57 result = new AccountProtocol(AccountProtocol.INUSE, 0);

58 } else {

59 FileInputStream fis = new FileInputStream(key + ".ser");

60 ObjectInputStream ois = new ObjectInputStream(fis);

61 Account account = (Account)ois.readObject();

62 result = new AccountProtocol(AccountProtocol.OKAY, account);

63 ois.close();

64 checkout.put(key, account);

65 }

66 }

67 netOOS.writeObject(result);

68 netOOS.flush();

69 }

70 private void handlePut(ObjectOutputStream netOOS, AccountProtocol proto)

71 throws Exception {

72 synchronized(checkout) {

73 FileOutputStream fos = new FileOutputStream(proto.getAccountNumber()

74 + ".ser");

75 ObjectOutputStream oos = new ObjectOutputStream(fos);

76 oos.writeObject(proto.getAccount());

77 oos.flush();

78 oos.close();

79 handleRelease(netOOS, proto);

80 }

81

82 }

83 private void handleRelease(ObjectOutputStream netOOS, AccountProtocol proto)

84 throws Exception {

85 Integer key = new Integer(proto.getAccountNumber());

86 synchronized(checkout) {

87 if (checkout.containsKey(key))

88 checkout.remove(key);

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 171

Page 181: 67544219-OOP-JAVA

Counter.java A.3.4

89 }

90 netOOS.writeObject(new AccountProtocol(AccountProtocol.OKAY, 0));

91 netOOS.flush();

92 }

93 }

A.3.3 AccountProtocol.java

1 import java.lang.*;

2 import java.io.*;

3 public class AccountProtocol

4 implements Serializable {

5 public static final int ERROR = -1;

6 public static final int GET = 0;

7 public static final int PUT = 1;

8 public static final int OKAY = 2;

9 public static final int INUSE = 3;

10 public static final int RELEASE = 4;

11 private final int cmd;

12 private final int accountId;

13 private final Account account;

14 public AccountProtocol(int c, int a) {

15 cmd = c;

16 accountId = a;

17 account = null;

18 }

19 public AccountProtocol(int c, Account a) {

20 cmd = c;

21 accountId = a.getAccountNumber();

22 account = a;

23 }

24 public int getCommand() {

25 return (cmd);

26 }

27 public int getAccountNumber() {

28 return (accountId);

29 }

30 public Account getAccount() {

31 return (account);

32 }

33 }

A.3.4 Counter.java

1 import java.lang.*;

2 public class Counter

3 extends Object {

4 private final int maximum;

5 private int current;

6 public Counter(int max) {

7 maximum = max;

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 172

Page 182: 67544219-OOP-JAVA

AccountServerAPI.java A.3.6

8 current = 0;

9 }

10 public synchronized void add() {

11 if (current == maximum)

12 while (true)

13 try {

14 wait();

15 break;

16 } catch (InterruptedException e) { }

17 current++;

18 }

19 public synchronized void release() {

20 current = (--current < 0)? 0: current;

21 notify();

22 }

23 public int getCount() {

24 return (maximum);

25 }

26 }

A.3.5 Counter.java

1 import java.lang.*;

2 public class APIException

3 extends Exception {

4 public APIException() {

5 super();

6 }

7 public APIException(String msg) {

8 super(msg);

9 }

10 }

A.3.6 AccountServerAPI.java

1 import java.lang.*;

2 import java.io.*;

3 import java.net.*;

4 public class AccountServerAPI {

5 private Socket toServer = null;

6 private String hostname;

7 private ObjectInputStream ois;

8 private ObjectOutputStream oos;

9 private boolean inuse;

10 public AccountServerAPI(String hn) {

11 hostname = hn;

12 inuse = false;

13 }

14 public Account getAccount(int acctId)

15 throws APIException {

16 AccountProtocol result = write(

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 173

Page 183: 67544219-OOP-JAVA

AccountServerAPI.java A.3.6

17 new AccountProtocol(AccountProtocol.GET, acctId));

18 if (result.getCommand() == AccountProtocol.OKAY)

19 return (result.getAccount());

20 else

21 return (null);

22 }

23 public Account putAccount(Account acct)

24 throws APIException {

25 AccountProtocol result = write(

26 new AccountProtocol(AccountProtocol.PUT, acct));

27 if (result.getCommand() == AccountProtocol.OKAY)

28 return (acct);

29 else

30 return (null);

31 }

32 public void releaseAccount(int acctId)

33 throws APIException {

34 write(new AccountProtocol(AccountProtocol.RELEASE, acctId));

35 }

36 public AccountProtocol write(AccountProtocol proto)

37 throws APIException {

38 AccountProtocol result = null;

39 connect();

40 try {

41 oos.writeObject(proto);

42 oos.flush();

43 result = (AccountProtocol)ois.readObject();

44 inuse = AccountProtocol.INUSE == result.getCommand();

45 } catch (Exception e) {

46 close();

47 throw new APIException(e.getMessage());

48 }

49 try {

50 close();

51 } finally {

52 return (result);

53 }

54 }

55 public boolean isInUse() {

56 return (inuse);

57 }

58 private void connect()

59 throws APIException {

60 try {

61 toServer = new Socket(hostname, AccountServer.PORT);

62 oos = new ObjectOutputStream(toServer.getOutputStream());

63 ois = new ObjectInputStream(toServer.getInputStream());

64 } catch (UnknownHostException e) {

65 throw new APIException(e.getMessage());

66 } catch (IOException e) {

67 throw new APIException(e.getMessage());

68 }

69 }

70 private void close()

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 174

Page 184: 67544219-OOP-JAVA

AccountServerAPI.java A.3.6

71 throws APIException {

72 try {

73 oos.close();

74 ois.close();

75 toServer.close();

76 } catch (IOException e) {

77 throw new APIException(e.getMessage());

78 }

79 }

80 }

Copyright c© July 1999 Lee Chuk Munn. All rights reserved. 175